texlive[61033] Build/source/texk/web2c/hitexdir: eliminating htex.w

commits+mruckert at tug.org commits+mruckert at tug.org
Fri Nov 12 12:09:18 CET 2021


Revision: 61033
          http://tug.org/svn/texlive?view=revision&revision=61033
Author:   mruckert
Date:     2021-11-12 12:09:17 +0100 (Fri, 12 Nov 2021)
Log Message:
-----------
eliminating htex.w and giving all file names the hi... prefix

Modified Paths:
--------------
    trunk/Build/source/texk/web2c/hitexdir/am/hitex.am
    trunk/Build/source/texk/web2c/hitexdir/format.w
    trunk/Build/source/texk/web2c/hitexdir/hitex.w

Added Paths:
-----------
    trunk/Build/source/texk/web2c/hitexdir/hilexer.c
    trunk/Build/source/texk/web2c/hitexdir/hilexer.l
    trunk/Build/source/texk/web2c/hitexdir/hiparser.c
    trunk/Build/source/texk/web2c/hitexdir/hiparser.h
    trunk/Build/source/texk/web2c/hitexdir/hiparser.y

Removed Paths:
-------------
    trunk/Build/source/texk/web2c/hitexdir/hishrink-lexer.c
    trunk/Build/source/texk/web2c/hitexdir/hishrink-parser.c
    trunk/Build/source/texk/web2c/hitexdir/hishrink-parser.h
    trunk/Build/source/texk/web2c/hitexdir/htex.w

Modified: trunk/Build/source/texk/web2c/hitexdir/am/hitex.am
===================================================================
--- trunk/Build/source/texk/web2c/hitexdir/am/hitex.am	2021-11-12 00:49:04 UTC (rev 61032)
+++ trunk/Build/source/texk/web2c/hitexdir/am/hitex.am	2021-11-12 11:09:17 UTC (rev 61033)
@@ -16,9 +16,9 @@
 ## Except we eschew all lex/yacc steps in the Makefile here; see below.
 ## AM_YFLAGS = -d -v -Wno-yacc
 
-hitex_CPPFLAGS = $(AM_CPPFLAGS) $(ZLIB_INCLUDES)
+hitex_CPPFLAGS = $(AM_CPPFLAGS) $(ZLIB_INCLUDES) 
 hitex_CPPFLAGS += -I$(srcdir)/libmd5
-hitex_LDADD = $(KPATHSEA_LIBS) $(ZLIB_LIBS)
+hitex_LDADD = $(KPATHSEA_LIBS) $(ZLIB_LIBS) libmd5.a
 hitex_LDADD += libmd5.a
 hitex_DEPENDENCIES = $(KPATHSEA_DEPEND) $(ZLIB_DEPEND) libmd5.a
 #
@@ -32,7 +32,7 @@
 hishrink_DEPENDENCIES = $(ZLIB_DEPEND)
 
 # HiTeX CWEB sources
-hitex_web = hitexdir/format.w hitexdir/htex.w hitexdir/hitex.w
+hitex_web = hitexdir/format.w hitexdir/hitex.w
 
 # Creating several files: need stamp file and two rules with identical recipes
 hi_ctangle_sh = CWEBINPUTS=$(srcdir)/hitexdir AM_V_P=$(AM_V_P) $(SHELL) ./tangle-sh $@ $(CTANGLE)
@@ -39,13 +39,12 @@
 
 # HiTeX C/yacc/lex sources generated using ctangle.
 # For each cweb (.w) source file, list the files generated.
-format_c_h_l_y = basetypes.h error.h hformat.h \
-        mkhformat.c \
-	hput.c hput.h \
-	hget.c hget.h \
-	shrink.l shrink.y \
+format_c_h_l_y = hibasetypes.h hierror.h hiformat.h \
+        himktables.c \
+	hiput.c hiput.h \
+	higet.c higet.h \
+	hilexer.l hiparser.y \
 	hishrink.c histretch.c
-htex_c_h = htex.c htex.h
 hitex_c_h = hitex.c hitex.h 
 
 $(format_c_h_l_y): format-tangle
@@ -60,22 +59,15 @@
 hitex-tangle: ctangle$(EXEEXT) hitexdir/hitex.w tangle-sh
 	$(hi_ctangle_sh) hitex
 
-# htex.c needs hitex.h, so depend on the hitex tangle.
-$(htex_c_h): htex-tangle hitex-tangle
-	$(hi_ctangle_sh) htex
-#
-htex-tangle: ctangle$(EXEEXT) hitexdir/htex.w tangle-sh hitex-tangle
-	$(hi_ctangle_sh) htex
+# Generating hitables.c using himktables.
+hitables.c: himktables
+	./himktables > $@ || { rm -f hitables.c; exit 1; }
 
-# Generating hformat.c using mkhformat.
-hformat.c: mkhformat
-	./mkhformat >hformat.c || { rm -f hformat.c; exit 1; }
-
 # hitex
-nodist_hitex_SOURCES = hformat.c hput.c $(htex_c_h) $(hitex_c_h)
+nodist_hitex_SOURCES = hitables.c hiput.c $(hitex_c_h)
 
 # histretch
-nodist_histretch_SOURCES = hformat.c histretch.c
+nodist_histretch_SOURCES = hitables.c histretch.c
 
 # The actual sources for the lexer and parser are in format.w.
 # However, to simplify life with Automake (a little), we include the
@@ -82,14 +74,16 @@
 # generated [.ch] files as if they were the sources here, and don't try
 # to have Automake support the derivation from .w.
 #
-nodist_hishrink_SOURCES = hformat.c hishrink.c \
-  hitexdir/hishrink-lexer.c \
-  hitexdir/hishrink-parser.c hitexdir/hishrink-parser.h 
+# The $(srcdir) is not necessary if everything is up to date,
+# but can help with the remake if the [.ch] or [.ly] are not present.
+nodist_hishrink_SOURCES = hitables.c \
+  hitexdir/hilexer.c \
+  hitexdir/hiparser.c hitexdir/hiparser.h 
 
 # This is our attempt to ensure that bison got run before anything else,
 # when needed.
 #
-$(hishrink_OBJECTS): $(srcdir)/hitexdir/hishrink-parser.h
+$(hishrink_OBJECTS): $(srcdir)/hitexdir/hiparser.h
 #
 # By the way, the $(BUILT_SOURCES) suggestion in the Automake manual for
 # this does not work for us, because we want to be able to invoke
@@ -100,7 +94,7 @@
 
 DISTCLEANFILES += $(nodist_hitex_SOURCES)
 DISTCLEANFILES += $(nodist_hishrink_SOURCES) $(nodist_histretch_SOURCES)
-DISTCLEANFILES += format-tangle htex-tangle hitex-tangle
+DISTCLEANFILES += format-tangle hitex-tangle
 
 ## HiTeX tests
 # still missing

Modified: trunk/Build/source/texk/web2c/hitexdir/format.w
===================================================================
--- trunk/Build/source/texk/web2c/hitexdir/format.w	2021-11-12 00:49:04 UTC (rev 61032)
+++ trunk/Build/source/texk/web2c/hitexdir/format.w	2021-11-12 11:09:17 UTC (rev 61033)
@@ -47,9 +47,9 @@
 
 
 \def\setrevision$#1: #2 ${\gdef\lastrevision{#2}}
-\setrevision$Revision: 2515 $
+\setrevision$Revision: 2541 $
 \def\setdate$#1(#2) ${\gdef\lastdate{#2}}
-\setdate$Date: 2021-09-23 17:59:58 +0200 (Thu, 23 Sep 2021) $
+\setdate$Date: 2021-10-26 09:03:28 +0200 (Tue, 26 Oct 2021) $
 
 \null
 
@@ -719,7 +719,7 @@
 @<read and check the end byte |z|@>=
 HGETTAG(z);@+
 if (a!=z)
-  QUIT(@["Tag mismatch [%s,%d]!=[%s,%d] at 0x%x to 0x%tx\n"@],@|
+  QUIT(@["Tag mismatch [%s,%d]!=[%s,%d] at 0x%x to " SIZE_F "\n"@],@|
     NAME(a),INFO(a),NAME(z),INFO(z),@|node_pos, hpos-hstart-1);
 @
 
@@ -938,7 +938,7 @@
 @
 
 @<parsing rules@>=
-integer: SIGNED @+| UNSIGNED { RNG("number",$1,0,INT32_MAX);};
+integer: SIGNED @+| UNSIGNED { RNG("number",$1,0,0x7FFFFFFF);};
 @
 
 To preserve the ``signedness'' of an integer also for positive signed integers
@@ -1227,7 +1227,7 @@
 \getcode
 @<shared get functions@>=
 #define @[HGET_UTF8C(X)@]  (X)=HGET8;@+ if ((X&0xC0)!=0x80) \
-  QUIT(@["UTF8 continuation byte expected at 0x%tx got 0x%02X\n"@],hpos-hstart-1,X)@;
+  QUIT(@["UTF8 continuation byte expected at " SIZE_F " got 0x%02X\n"@],hpos-hstart-1,X)@;
 
 uint32_t hget_utf8(void)
 { uint8_t a;
@@ -2824,7 +2824,7 @@
 { uint32_t n;
   if (info<2) return;
   n=HGET8;
-  if (n-1!=0x100-info) QUIT(@["Size boundary byte 0x%x with info value %d at 0x%tx"@],
+  if (n-1!=0x100-info) QUIT(@["Size boundary byte 0x%x with info value %d at " SIZE_F@],
                             n, info,hpos-hstart-1);
 }
 
@@ -2861,7 +2861,7 @@
     hpos=hpos+(L).s; hget_size_boundary(I);\
     { uint32_t s=hget_list_size(I); \
       if (s!=(L).s) \
-      QUIT(@["List sizes at 0x%x and 0x%tx do not match 0x%x != 0x%x"@],node_pos+1,hpos-hstart-I-1,(L).s,s);}
+      QUIT(@["List sizes at 0x%x and " SIZE_F " do not match 0x%x != 0x%x"@],node_pos+1,hpos-hstart-I-1,(L).s,s);}
 @
 
 \putcode
@@ -5788,7 +5788,7 @@
 { xdimen_t x;
   uint16_t f,r;
   uint8_t n;
-  DBG(DBGDEF,"Defining normal stream %d at 0x%tx\n",*(hpos-1),hpos-hstart-2);
+  DBG(DBGDEF,"Defining normal stream %d at " SIZE_F "\n",*(hpos-1),hpos-hstart-2);
   hget_xdimen_node(&x); @+hwrite_xdimen_node(&x); 
   HGET16(f); @+RNG("magnification factor",f,0,1000);@+ hwritef(" %d",f);
   n=HGET8; if (n==255) hwritef(" *"); else { REF_RNG(stream_kind,n);@+hwrite_ref(n);@+}
@@ -5804,7 +5804,7 @@
   else
   { ref_t df;
     @<read the start byte |a|@>@;
-    DBG(DBGDEF,"Defining stream %d at 0x%tx\n",*hpos,hpos-hstart-1);
+    DBG(DBGDEF,"Defining stream %d at " SIZE_F "\n",*hpos,hpos-hstart-1);
     DEF(df,stream_kind,HGET8);
     hwrite_start();@+hwritef("stream");@+ at +hwrite_ref(df.n);
     if (df.n>0) 
@@ -6165,12 +6165,12 @@
 { if (((next_range-1)/2)>max_ref[range_kind])
     QUIT("Page range %d > %d",(next_range-1)/2,max_ref[range_kind]);
   if (on && page_on[pg]!=0)
-    QUIT(@["Template %d is switched on at 0x%x and 0x%tx"@],@|
+    QUIT(@["Template %d is switched on at 0x%x and " SIZE_F@],@|
            pg, range_pos[page_on[pg]].pos, hpos-hstart);
   else if (!on && page_on[pg]==0)
-    QUIT(@["Template %d is switched off at 0x%tx but was not on"@],@|
+    QUIT(@["Template %d is switched off at " SIZE_F " but was not on"@],@|
            pg, hpos-hstart);
-  DBG(DBGRANGE,@["Range *%d %s at 0x%tx\n"@],pg,on?"on":"off",hpos-hstart);
+  DBG(DBGRANGE,@["Range *%d %s at " SIZE_F "\n"@],pg,on?"on":"off",hpos-hstart);
   range_pos[next_range].pg=pg;
   range_pos[next_range].pos=hpos-hstart;
   range_pos[next_range].on=on;
@@ -6365,15 +6365,15 @@
 { size_t s;
   DBG(DBGBASIC,"Writing hint output %s\n",str); 
   s=hput_banner("hint",str);
-  DBG(DBGDIR,@["Root entry at 0x%tx\n"@],s);
+  DBG(DBGDIR,@["Root entry at " SIZE_F "\n"@],s);
   s+=hput_root();
-  DBG(DBGDIR,@["Directory section at 0x%tx\n"@],s);
+  DBG(DBGDIR,@["Directory section at " SIZE_F "\n"@],s);
   s+=hput_section(0);
-  DBG(DBGDIR,@["Definition section at 0x%tx\n"@],s);
+  DBG(DBGDIR,@["Definition section at " SIZE_F "\n"@],s);
   s+=hput_section(1);
-  DBG(DBGDIR,@["Content section at 0x%tx\n"@],s);
+  DBG(DBGDIR,@["Content section at " SIZE_F "\n"@],s);
   s+=hput_section(2);
-  DBG(DBGDIR,@["Auxiliary sections at 0x%tx\n"@],s);
+  DBG(DBGDIR,@["Auxiliary sections at " SIZE_F "\n"@],s);
   hput_optional_sections();
 }
 @
@@ -6396,7 +6396,7 @@
 
 \getcode
 @<shared get macros@>=
-#define HGET_ERROR @/ QUIT(@["HGET overrun in section %d at 0x%tx\n"@],@|section_no,hpos-hstart)
+#define HGET_ERROR @/ QUIT(@["HGET overrun in section %d at " SIZE_F "\n"@],@|section_no,hpos-hstart)
 #define @[HEND@]   @[((hpos<=hend)?0:(HGET_ERROR,0))@]
 
 #define @[HGET8@]      ((hpos<hend)?*(hpos++):(HGET_ERROR,0))
@@ -6410,7 +6410,7 @@
 @<put functions@>=
 void hput_error(void)
 {@+if (hpos<hend) return;
- QUIT(@["HPUT overrun section %d pos=0x%tx\n"@],@|section_no,hpos-hstart);
+ QUIT(@["HPUT overrun section %d pos=" SIZE_F "\n"@],@|section_no,hpos-hstart);
 }
 @
 
@@ -6708,8 +6708,8 @@
    bsize=dir[section_no].bsize*buffer_factor+0.5;
    if (bsize<pos+n) bsize=pos+n;
    if (bsize>=HINT_NO_POS) bsize=HINT_NO_POS;
-   if (bsize<pos+n)  QUIT(@["Unable to increase buffer size 0x%tx by 0x%x byte"@],@|hpos-hstart,n);
-   DBG(DBGBUFFER,@["Reallocating output buffer "@|" for section %d from 0x%x to 0x%tx byte\n"@],
+   if (bsize<pos+n)  QUIT(@["Unable to increase buffer size " SIZE_F " by 0x%x byte"@],@|hpos-hstart,n);
+   DBG(DBGBUFFER,@["Reallocating output buffer "@|" for section %d from 0x%x to " SIZE_F " byte\n"@],
        section_no,dir[section_no].bsize,bsize);
    REALLOCATE(dir[section_no].buffer,bsize,uint8_t);
    dir[section_no].bsize=(uint32_t)bsize;
@@ -6722,7 +6722,7 @@
 { size_t s;
   s=fwrite(buffer,1,size,hout);
   if (s!=size)
-    QUIT(@["short write 0x%tx < %d in section %d"@],s,size,n);
+    QUIT(@["short write " SIZE_F " < %d in section %d"@],s,size,n);
   return s;
 }
 
@@ -7063,7 +7063,7 @@
 \getcode
 @<get file functions@>=
 static void hget_root(entry_t *root)
-{ DBG(DBGDIR,"Root entry at 0x%tx\n",hpos-hstart);
+{ DBG(DBGDIR,"Root entry at " SIZE_F "\n",hpos-hstart);
   hget_entry(root); 
   root->pos=hpos-hstart;
   max_section_no=root->section_no;
@@ -7168,7 +7168,7 @@
   dir[0].section_no=max_section_no;
   hput_entry(&dir[0]);
   s=hput_data(0, hstart,hpos-hstart);
-  DBG(DBGDIR,@["Writing root size=0x%tx\n"@],s);
+  DBG(DBGDIR,@["Writing root size=" SIZE_F "\n"@],s);
   return s;
 }
 
@@ -7226,7 +7226,7 @@
      }
      fclose(f);
      if (fsize!=dir[i].size) 
-       QUIT(@["File size 0x%tx does not match directory size %u"@],@|fsize,dir[i].size);
+       QUIT(@["File size " SIZE_F " does not match directory size %u"@],@|fsize,dir[i].size);
    }
 }
 @
@@ -8752,7 +8752,7 @@
 To print messages\index{message} or indicate errors, I define the following macros:
 \index{MESSAGE+\.{MESSAGE}}\index{QUIT+\.{QUIT}}
 
-@(error.h@>=
+@(hierror.h@>=
 #ifndef _ERROR_H
 #define _ERROR_H
 #include <stdlib.h>
@@ -8772,25 +8772,22 @@
 \index{DBG+\.{DBG}}\index{SIZE F+\.{SIZE\_F}}\index{DBGTAG+\.{DBGTAG}}
 \index{RNG+\.{RNG}}\index{TAGERR+\.{TAGERR}}
 @<debug macros@>=
-#if 0 
-/* use 0x percent tx instead */
 #ifdef WIN32
 #define SIZE_F "0x%x"
 #else
 #define SIZE_F "0x%zx"
 #endif
-#endif
 #ifdef DEBUG
 #define @[DBG(FLAGS,...)@] ((debugflags & (FLAGS))?LOG(__VA_ARGS__):0)
 #else
 #define @[DBG(FLAGS,...)@] 0
 #endif
-#define @[DBGTAG(A,P)@] @[DBG(DBGTAGS,@["tag [%s,%d] at 0x%tx\n"@],@|NAME(A),INFO(A),(P)-hstart)@]
+#define @[DBGTAG(A,P)@] @[DBG(DBGTAGS,@["tag [%s,%d] at " SIZE_F "\n"@],@|NAME(A),INFO(A),(P)-hstart)@]
 
 #define @[RNG(S,N,A,Z)@] @/\
   if ((int)(N)<(int)(A)||(int)(N)>(int)(Z)) QUIT(S@, " %d out of range [%d - %d]",N,A,Z)
 
-#define @[TAGERR(A)@] @[QUIT(@["Unknown tag [%s,%d] at 0x%tx\n"@],NAME(A),INFO(A),hpos-hstart)@]
+#define @[TAGERR(A)@] @[QUIT(@["Unknown tag [%s,%d] at " SIZE_F "\n"@],NAME(A),INFO(A),hpos-hstart)@]
 @
 
 The \.{bison} generated parser will need a function |yyerror| for
@@ -8865,7 +8862,7 @@
 @
 
 
-We will put the |hnode_size| variable into the {\tt hformat.c} file
+We will put the |hnode_size| variable into the {\tt tables.c} file
 using the following function. We add some comments and
 split negative values into their components, to make the result more
 readable.
@@ -9275,7 +9272,7 @@
 
 @<skip and check the start byte |a|@>=
   HTEGTAG(a);
-  if (a!=z) QUIT(@["Tag mismatch [%s,%d]!=[%s,%d] at 0x%tx to 0x%x\n"@],@|NAME(a),INFO(a),NAME(z),INFO(z),@|
+  if (a!=z) QUIT(@["Tag mismatch [%s,%d]!=[%s,%d] at " SIZE_F " to 0x%x\n"@],@|NAME(a),INFO(a),NAME(z),INFO(z),@|
     hpos-hstart,node_pos-1);
 @
 
@@ -9727,7 +9724,7 @@
 { uint32_t n;
   if (info<2) return;
   n=HTEG8;
-  if (n-1!=0x100-info) QUIT(@["List size boundary byte 0x%x does not match info value %d at 0x%tx"@],
+  if (n-1!=0x100-info) QUIT(@["List size boundary byte 0x%x does not match info value %d at " SIZE_F@],
                             n, info,hpos-hstart);
 }
 
@@ -9755,7 +9752,7 @@
     l->p=hpos-hstart;
     hteg_size_boundary(INFO(z));
     s=hteg_list_size(INFO(z));
-    if (s!=l->s) QUIT(@["List sizes at 0x%tx and 0x%x do not match 0x%x != 0x%x"@],
+    if (s!=l->s) QUIT(@["List sizes at " SIZE_F " and 0x%x do not match 0x%x != 0x%x"@],
                         hpos-hstart,node_pos-1,s,l->s);
     @<skip and check the start byte |a|@>@;
   }
@@ -9851,7 +9848,7 @@
 The macro |_MSC_VER| (Microsoft Visual C Version)\index{Microsoft Visual C}
 is defined only if using the respective compiler.
 \index{false+\\{false}}\index{true+\\{true}}\index{bool+\&{bool}}
-@(basetypes.h@>=
+@(hibasetypes.h@>=
 #ifndef __BASETYPES_H__
 #define __BASETYPES_H__
 #include <stdlib.h>
@@ -9873,7 +9870,6 @@
 #define false (!true)
 #define __SIZEOF_FLOAT__ 4
 #define __SIZEOF_DOUBLE__ 8
-#define INT32_MAX              (2147483647)
 #define PRIx64 "I64x"
 #pragma  @[warning( disable : @[4244@]@t @> @[4996@]@t @> @[4127@])@]
 #else 
@@ -9898,11 +9894,11 @@
 
 
 
-\subsection{{\tt hformat.h}}\index{hformat.h+{\tt hformat.h}}
-The \.{hformat.h} file contains definitions of types, macros, variables and functions
+\subsection{{\tt format.h}}\index{format.h+{\tt format.h}}
+The \.{format.h} file contains definitions of types, macros, variables and functions
 that are needed in other compilation units.
 
-@(hformat.h@>=
+@(hiformat.h@>=
 #ifndef _HFORMAT_H_
 #define _HFORMAT_H_
 @<debug macros@>@;
@@ -9926,15 +9922,15 @@
 
 #endif
 @
-\subsection{{\tt hformat.c}}\index{hformat.c+{\tt hformat.c}}\index{mkhformat.c+{\tt mkhformat.c}}
-For maximum flexibility and efficiency, the file {\tt hformat.c}
+\subsection{{\tt tables.c}}\index{tables.c+{\tt tables.c}}\index{mktables.c+{\tt mktables.c}}
+For maximum flexibility and efficiency, the file {\tt tables.c}
 is generated by a \CEE\ program.
-Here is the |main| program of {\tt mkhformat}:
+Here is the |main| program of {\tt mktables}:
 
-@(mkhformat.c@>=
+@(himktables.c@>=
 #include <stdio.h>
-#include "basetypes.h"
-#include "hformat.h"
+#include "hibasetypes.h"
+#include "hiformat.h"
 @<skip macros@>@;
 
 int max_fixed[32], max_default[32];
@@ -9952,8 +9948,8 @@
   int i;
   
   
-  printf("#include \"basetypes.h\"\n"@/
-         "#include \"hformat.h\"\n\n");@/
+  printf("#include \"hibasetypes.h\"\n"@/
+         "#include \"hiformat.h\"\n\n");@/
 
   @<print |content_name| and |definition_name|@>@;
 
@@ -10001,11 +9997,11 @@
 @
 
 
-\subsection{{\tt hget.h}}\index{hget.h+{\tt hget.h}}
-The \.{hget.h} file contains function prototypes for all the functions
+\subsection{{\tt get.h}}\index{get.h+{\tt get.h}}
+The \.{get.h} file contains function prototypes for all the functions
 that read the short format.
 
-@(hget.h@>=
+@(higet.h@>=
 @<hint types@>@;
 @<directory entry type@>@;
 @<shared get macros@>@;
@@ -10049,9 +10045,9 @@
 
 
 
-\subsection{{\tt hget.c}}\index{hget.c+{\tt hget.c}}
-@(hget.c@>=
-#include "basetypes.h"
+\subsection{{\tt get.c}}\index{get.c+{\tt get.c}}
+@(higet.c@>=
+#include "hibasetypes.h"
 #include <string.h>
 #include <math.h>
 #include <zlib.h>
@@ -10059,9 +10055,9 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 
-#include "error.h"
-#include "hformat.h"
-#include "hget.h"
+#include "hierror.h"
+#include "hiformat.h"
+#include "higet.h"
 
 @<common variables@>@;
 
@@ -10074,12 +10070,12 @@
 @<shared skip functions@>@;
 @
 
-\subsection{{\tt hput.h}}\index{hput.h+{\tt hput.h}}
-The \.{hput.h} file contains function prototypes for all the functions
+\subsection{{\tt put.h}}\index{put.h+{\tt put.h}}
+The \.{put.h} file contains function prototypes for all the functions
 that write the short format.
 
 
-@(hput.h@>=
+@(hiput.h@>=
 @<put macros@>@;
 @<hint macros@>@;
 @<hint types@>@;
@@ -10148,18 +10144,18 @@
 @
 
 
-\subsection{{\tt hput.c}}\label{writeshort}\index{hput.c+{\tt hput.c}}
+\subsection{{\tt put.c}}\label{writeshort}\index{put.c+{\tt put.c}}
 \noindent
-@(hput.c@>=
-#include "basetypes.h"
+@(hiput.c@>=
+#include "hibasetypes.h"
 #include <string.h>
 #include <ctype.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <zlib.h>
-#include "error.h"
-#include "hformat.h"
-#include "hput.h"
+#include "hierror.h"
+#include "hiformat.h"
+#include "hiput.h"
 
 @<common variables@>@;
 @<shared put variables@>@;
@@ -10168,18 +10164,18 @@
 @<put functions@>@;
 @
 
-\subsection{{\tt shrink.l}}\index{shrink.l+{\tt shrink.l}}\index{scanning}
-The definitions for lex are collected in the file {\tt shrink.l}
+\subsection{{\tt lexer.l}}\index{lexer.l+{\tt lexer.l}}\index{scanning}
+The definitions for lex are collected in the file {\tt lexer.l}
 
-@(shrink.l@>=
+@(hilexer.l@>=
 %{
-#include "basetypes.h"
-#include "error.h"
-#include "hformat.h"
-#include "hput.h"
+#include "hibasetypes.h"
+#include "hierror.h"
+#include "hiformat.h"
+#include "hiput.h"
 
 @<enable bison debugging@>@;
-#include "hishrink-parser.h"
+#include "hiparser.h"
 
 @<scanning macros@>@;@+
 @<scanning functions@>@;
@@ -10206,20 +10202,20 @@
 
 
 
-\subsection{{\tt shrink.y}}\index{shrink.y+{\tt shrink.y}}\index{parsing}
+\subsection{{\tt parser.y}}\index{parser.y+{\tt parser.y}}\index{parsing}
 
-The grammar rules for bison are collected in the file  {\tt shrink.y}.
+The grammar rules for bison are collected in the file  {\tt parser.y}.
 % for the option %token-table use the command line parameter -k
 
 
-@(shrink.y@>=
+@(hiparser.y@>=
 %{
-#include "basetypes.h"
+#include "hibasetypes.h"
 #include <string.h>
 #include <math.h>
-#include "error.h"
-#include "hformat.h"
-#include "hput.h"
+#include "hierror.h"
+#include "hiformat.h"
+#include "hiput.h"
 extern char **hfont_name; /* in common variables */
 
 @<definition checks@>@;
@@ -10261,7 +10257,7 @@
 \.{shrink} is a \CEE\ program translating a \HINT\ file in long format into a \HINT\ file in short format.
 
 @(hishrink.c@>=
-#include "basetypes.h"
+#include "hibasetypes.h"
 #include <string.h>
 #include <ctype.h>
 #include <sys/types.h>
@@ -10271,10 +10267,10 @@
 #endif
 #include <zlib.h>
 
-#include "error.h"
-#include "hformat.h"
-#include "hput.h"
-#include "hishrink-parser.h"
+#include "hierror.h"
+#include "hiformat.h"
+#include "hiput.h"
+#include "hiparser.h"
 
 extern void yyset_debug(int lex_debug);
 extern int yylineno;
@@ -10334,7 +10330,7 @@
 format into a \HINT\ file in long format.
 
 @(histretch.c@>=
-#include "basetypes.h"
+#include "hibasetypes.h"
 #include <math.h>
 #include <string.h>
 #include <ctype.h>
@@ -10345,9 +10341,9 @@
 #include <direct.h>
 #endif
 #include <fcntl.h>
-#include "error.h"
-#include "hformat.h"
-#include "hget.h"
+#include "hierror.h"
+#include "hiformat.h"
+#include "higet.h"
 
 @<get macros@>@;
 @<write macros@>@;
@@ -10399,7 +10395,7 @@
 and the write functions call some get functions. This requires
 function declarations to satisfy the define before use requirement
 of \CEE. Some of the necessary function declarations are already
-contained in {\tt hget.h}. The remaining declarations are these:
+contained in {\tt get.h}. The remaining declarations are these:
 
 @<get function declarations@>=
 extern void hget_xdimen_node(xdimen_t *x);
@@ -10420,15 +10416,15 @@
 \.{skip} is a \CEE\ program reading the content section of a \HINT\ file in short format 
 backwards.
 
-@(skip.c@>=
-#include "basetypes.h"
+@(hiskip.c@>=
+#include "hibasetypes.h"
 #include <string.h>
 #include <zlib.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
-#include "error.h"
-#include "hformat.h"
+#include "hierror.h"
+#include "hiformat.h"
 @<hint types@>@;
 
 @<common variables@>@;

Added: trunk/Build/source/texk/web2c/hitexdir/hilexer.c
===================================================================
--- trunk/Build/source/texk/web2c/hitexdir/hilexer.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/hitexdir/hilexer.c	2021-11-12 11:09:17 UTC (rev 61033)
@@ -0,0 +1,3230 @@
+#line 1 "lexer.c"
+
+#line 3 "lexer.c"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+/* %not-for-header */
+/* %if-c-only */
+/* %if-not-reentrant */
+
+/* %endif */
+/* %endif */
+/* %ok-for-header */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 4
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* %if-c++-only */
+/* %endif */
+
+/* %if-c-only */
+
+/* %endif */
+
+/* %if-c-only */
+
+/* %endif */
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+/* %if-c-only */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+/* %endif */
+
+/* %if-tables-serialization */
+/* %endif */
+/* end standard C headers. */
+
+/* %if-c-or-c++ */
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX               (~(size_t)0)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+/* %endif */
+
+/* begin standard C++ headers. */
+/* %if-c++-only */
+/* %endif */
+
+/* TODO: this is always defined, so inline it */
+#define yyconst const
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
+#else
+#define yynoreturn
+#endif
+
+/* %not-for-header */
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+/* %ok-for-header */
+
+/* %not-for-header */
+/* Promotes a possibly negative, possibly signed char to an
+ *   integer in range [0..255] for use as an array index.
+ */
+#define YY_SC_TO_UI(c) ((YY_CHAR) (c))
+/* %ok-for-header */
+
+/* %if-reentrant */
+/* %endif */
+
+/* %if-not-reentrant */
+
+/* %endif */
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin  )
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+/* %if-not-reentrant */
+extern int yyleng;
+/* %endif */
+
+/* %if-c-only */
+/* %if-not-reentrant */
+extern FILE *yyin, *yyout;
+/* %endif */
+/* %endif */
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+    
+    /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires
+     *       access to the local variable yy_act. Since yyless() is a macro, it would break
+     *       existing scanners that call yyless() from OUTSIDE yylex.
+     *       One obvious solution it to make yy_act a global. I tried that, and saw
+     *       a 5% performance hit in a non-yylineno scanner, because yy_act is
+     *       normally declared as a register variable-- so it is not worth it.
+     */
+    #define  YY_LESS_LINENO(n) \
+            do { \
+                int yyl;\
+                for ( yyl = n; yyl < yyleng; ++yyl )\
+                    if ( yytext[yyl] == '\n' )\
+                        --yylineno;\
+            }while(0)
+    #define YY_LINENO_REWIND_TO(dst) \
+            do {\
+                const char *p;\
+                for ( p = yy_cp-1; p >= (dst); --p)\
+                    if ( *p == '\n' )\
+                        --yylineno;\
+            }while(0)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		*yy_cp = (yy_hold_char); \
+		YY_RESTORE_YY_MORE_OFFSET \
+		(yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+		} \
+	while ( 0 )
+#define unput(c) yyunput( c, (yytext_ptr)  )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+/* %if-c-only */
+	FILE *yy_input_file;
+/* %endif */
+
+/* %if-c++-only */
+/* %endif */
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	int yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via yyrestart()), so that the user can continue scanning by
+	 * just pointing yyin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* %if-c-only Standard (non-C++) definition */
+/* %not-for-header */
+/* %if-not-reentrant */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */
+/* %endif */
+/* %ok-for-header */
+
+/* %endif */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+                          : NULL)
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* %if-c-only Standard (non-C++) definition */
+
+/* %if-not-reentrant */
+/* %not-for-header */
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+static int yy_n_chars;		/* number of characters read into yy_ch_buf */
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = NULL;
+static int yy_init = 0;		/* whether we need to initialize */
+static int yy_start = 0;	/* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+/* %ok-for-header */
+
+/* %endif */
+
+void yyrestart ( FILE *input_file  );
+void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size  );
+void yy_delete_buffer ( YY_BUFFER_STATE b  );
+void yy_flush_buffer ( YY_BUFFER_STATE b  );
+void yypush_buffer_state ( YY_BUFFER_STATE new_buffer  );
+void yypop_buffer_state ( void );
+
+static void yyensure_buffer_stack ( void );
+static void yy_load_buffer_state ( void );
+static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file  );
+#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size  );
+YY_BUFFER_STATE yy_scan_string ( const char *yy_str  );
+YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len  );
+
+/* %endif */
+
+void *yyalloc ( yy_size_t  );
+void *yyrealloc ( void *, yy_size_t  );
+void yyfree ( void *  );
+
+#define yy_new_buffer yy_create_buffer
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){ \
+        yyensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+	}
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){\
+        yyensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+	}
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* %% [1.0] yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here */
+/* Begin user sect3 */
+
+#define FLEX_DEBUG
+typedef flex_uint8_t YY_CHAR;
+
+FILE *yyin = NULL, *yyout = NULL;
+
+typedef int yy_state_type;
+
+extern int yylineno;
+int yylineno = 1;
+
+extern char *yytext;
+#ifdef yytext_ptr
+#undef yytext_ptr
+#endif
+#define yytext_ptr yytext
+
+/* %% [1.5] DFA */
+
+/* %if-c-only Standard (non-C++) definition */
+
+static yy_state_type yy_get_previous_state ( void );
+static yy_state_type yy_try_NUL_trans ( yy_state_type current_state  );
+static int yy_get_next_buffer ( void );
+static void yynoreturn yy_fatal_error ( const char* msg  );
+
+/* %endif */
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	(yytext_ptr) = yy_bp; \
+/* %% [2.0] code to fiddle yytext and yyleng for yymore() goes here \ */\
+	yyleng = (int) (yy_cp - yy_bp); \
+	(yy_hold_char) = *yy_cp; \
+	*yy_cp = '\0'; \
+/* %% [3.0] code to copy yytext_ptr to yytext[] goes here, if %array \ */\
+	(yy_c_buf_p) = yy_cp;
+/* %% [4.0] data tables for the DFA and the user's section 1 definitions go here */
+#define YY_NUM_RULES 126
+#define YY_END_OF_BUFFER 127
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+	{
+	flex_int32_t yy_verify;
+	flex_int32_t yy_nxt;
+	};
+static const flex_int16_t yy_accept[371] =
+    {   0,
+        0,    0,    0,    0,    0,    0,  127,  125,    6,    6,
+       43,   47,   10,  125,  114,  125,    4,    4,    1,    2,
+       41,  124,  124,  124,  124,  124,  124,  124,   31,  124,
+      124,  124,  124,  124,  124,  124,  124,  124,  124,   32,
+      124,   40,   14,   15,   13,   11,   74,   74,   58,   72,
+       48,   73,   49,   50,   74,  126,  126,  126,  126,    0,
+        0,    0,    0,    0,    0,    0,    7,    5,    5,    9,
+        9,    0,    0,    0,    4,  124,  124,  124,  124,  124,
+      124,  124,  124,  124,  124,  124,  124,  124,  124,  124,
+      124,  124,   29,  124,  124,  124,  124,  124,  124,  124,
+
+       28,  124,   97,  124,  124,  124,  124,   27,  124,  124,
+      124,  124,  124,  124,  124,   86,  124,  124,  124,  124,
+       12,    0,   58,   58,    0,   59,   55,   52,   56,   60,
+       53,   54,   57,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,   51,   71,   75,    0,    0,   20,   20,
+       16,    0,    0,    0,    5,    0,    9,   24,    8,   85,
+      124,  124,  124,  106,  124,  124,  124,  124,  124,  124,
+      124,  124,  124,   33,  124,  124,  124,  124,  124,  124,
+      124,  124,   37,  124,  124,  124,  124,  124,  124,  124,
+      124,  124,  120,  107,  124,   98,  124,  124,   95,  124,
+
+      124,  124,  102,  124,  124,  124,  124,  124,  113,  124,
+      124,  124,  124,   59,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,   76,    0,   18,   17,   21,    0,
+        0,    0,    0,    0,  124,  124,  124,  124,  124,  124,
+      124,  124,  124,  124,   94,  124,   34,  124,  122,   44,
+      124,   78,  124,   82,  124,  101,   42,  124,  124,  112,
+      124,  124,  108,   96,  124,  124,  115,  124,  124,   45,
+      124,   39,  124,  124,  124,  124,   79,  124,   84,  124,
+       70,   65,   61,   66,   69,   63,   64,   62,   68,   67,
+       77,   19,   22,    0,    0,   24,   25,  124,   89,  124,
+
+      124,  124,  124,  124,   87,   26,  124,  124,   35,  111,
+        3,   81,  104,  105,  124,  124,  124,   46,  124,  121,
+      124,  116,  124,  124,  124,  100,   83,  124,   23,    0,
+       99,  124,   90,  103,  124,  124,  124,   91,  124,  124,
+      124,  124,  124,  124,  124,  110,   30,    0,   25,  124,
+      123,  124,  124,  124,   88,  124,  109,   36,  118,   80,
+       92,  124,  124,   38,   93,  124,  117,  124,  119,    0
+    } ;
+
+static const YY_CHAR yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        4,    4,    2,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    5,    6,    7,    8,    8,    8,    8,    9,   10,
+       11,   12,   13,    8,   14,   15,    8,   16,   17,   17,
+       17,   17,   17,   17,   17,   18,   18,    8,    8,   19,
+        8,   20,    8,   21,   22,   22,   23,   24,   22,   25,
+       26,    8,   27,    8,   28,   29,    8,    8,    8,   30,
+        8,   31,   32,    8,    8,    8,    8,    8,    8,    8,
+        8,   33,    8,    8,   34,    8,   35,   36,   37,   38,
+
+       39,   40,   41,   42,   43,   44,   45,   46,   47,   48,
+       49,   50,   51,   52,   53,   54,   55,   56,   57,   58,
+       59,   51,    8,   60,    8,    8,    1,   61,   61,   61,
+       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
+       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
+       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
+       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
+       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
+       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
+       61,   62,   62,   62,   62,   62,   62,   62,   62,   62,
+
+       62,   62,   62,   62,   62,   62,   62,   62,   62,   62,
+       62,   62,   62,   62,   62,   62,   62,   62,   62,   62,
+       62,   62,   62,   63,   63,   63,   63,   63,   63,   63,
+       63,   63,   63,   63,   63,   63,   63,   63,   63,   64,
+       64,   64,   64,   64,   64,   64,   64,   65,   65,   65,
+       65,   65,   65,   65,   65
+    } ;
+
+static const YY_CHAR yy_meta[66] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    2,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    3,    3,    3,    3,    3,    3,
+        3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
+        3,    3,    3,    3,    3,    3,    3,    3,    3,    1,
+        4,    1,    1,    1,    4
+    } ;
+
+static const flex_int16_t yy_base[376] =
+    {   0,
+        0,    0,   65,  130,  194,  258,  629,  630,  630,  630,
+      630,  630,   74,   68,   64,   68,   77,   72,  630,  630,
+      630,   53,   61,   58,   59,  570,   57,  581,   65,   57,
+        0,  587,   73,   74,  100,  106,  107,  104,  112,  113,
+      587,  630,  630,  630,  630,  615,  630,  117,  148,  162,
+      630,  630,  630,  630,  322,  630,  562,  561,  560,  611,
+      610,  609,  556,  555,  554,  165,  630,  630,  107,  154,
+      162,  157,  166,  193,  170,    0,  160,  571,  560,  558,
+      563,   24,   63,  153,  560,  173,  561,  148,  559,  572,
+      567,  570,  550,  564,  550,  184,  566,  180,  168,  106,
+
+        0,  560,    0,  545,  182,  550,  542,    0,  548,  538,
+      548,  556,  549,  539,  554,  539,  539,  552,  547,  542,
+      630,  228,  233,  237,  241,  243,  247,  630,  630,  630,
+      630,  630,  630,  250,  253,  257,  263,  266,  269,  272,
+      276,  279,  282,  630,  630,  630,  523,  522,  630,  573,
+      572,  571,  518,  517,  285,  288,  299,  291,  354,    0,
+      522,  535,  536,    0,  520,  518,  518,  528,  516,  530,
+      529,  530,  531,  519,  511,  509,  523,  511,  502,  522,
+      504,  516,    0,  509,  507,  515,  512,  498,  513,  515,
+      504,  506,    0,    0,  492,    0,  500,  506,  509,  508,
+
+      489,  500,    0,  501,  485,  498,  498,  490,    0,  477,
+      497,  479,  485,  249,  357,  364,  367,  370,  375,  378,
+      388,  396,  399,  402,  630,  470,  630,  521,  630,  520,
+      467,  421,  409,  431,  474,  478,  479,  485,  476,  483,
+      473,  478,  471,  479,    0,  450,  451,  439,    0,    0,
+      450,    0,  446,    0,  451,    0,    0,  439,  429,    0,
+      444,  421,    0,    0,  421,  430,    0,  422,  416,    0,
+      422,    0,  417,  398,  416,  411,    0,  397,    0,  402,
+      630,  630,  630,  630,  630,  630,  630,  630,  630,  630,
+      630,  630,  630,  431,  315,  630,  441,  380,    0,  390,
+
+      379,  382,  380,  381,    0,    0,  356,  371,    0,    0,
+        0,    0,    0,    0,  372,  350,  346,    0,  351,    0,
+      344,    0,  340,  317,  297,    0,    0,  292,  630,  454,
+        0,  289,    0,    0,  281,  280,  279,    0,  285,  265,
+      224,  225,  203,  205,  209,    0,    0,  464,  478,  202,
+        0,  186,  172,  163,    0,  151,    0,    0,    0,    0,
+        0,  140,  100,    0,    0,  109,    0,   61,    0,  630,
+      503,  507,  511,  514,   70
+    } ;
+
+static const flex_int16_t yy_def[376] =
+    {   0,
+      370,    1,  371,  371,  372,  372,  370,  370,  370,  370,
+      370,  370,  373,  374,  370,  370,  370,  370,  370,  370,
+      370,  375,  375,  375,  375,  375,  375,  375,  375,  375,
+      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
+      375,  370,  370,  370,  370,  370,  370,  370,  370,  370,
+      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
+      370,  370,  370,  370,  370,  374,  370,  370,  370,  370,
+      370,  370,  370,  370,  370,  375,  375,  375,  375,  375,
+      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
+      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
+
+      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
+      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
+      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
+      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
+      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
+      370,  370,  370,  370,  370,  370,  370,  370,  370,  375,
+      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
+      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
+      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
+      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
+
+      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
+      375,  375,  375,  370,  370,  370,  370,  370,  370,  370,
+      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
+      370,  370,  370,  370,  375,  375,  375,  375,  375,  375,
+      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
+      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
+      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
+      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
+      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
+      370,  370,  370,  370,  370,  370,  370,  375,  375,  375,
+
+      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
+      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
+      375,  375,  375,  375,  375,  375,  375,  375,  370,  370,
+      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
+      375,  375,  375,  375,  375,  375,  375,  370,  370,  375,
+      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
+      375,  375,  375,  375,  375,  375,  375,  375,  375,    0,
+      370,  370,  370,  370,  370
+    } ;
+
+static const flex_int16_t yy_nxt[696] =
+    {   0,
+        8,    9,   10,    9,    9,   11,   12,    8,   13,   14,
+        8,   15,   16,   16,    8,   17,   18,   18,   19,   20,
+        8,    8,    8,    8,    8,    8,    8,    8,    8,    8,
+        8,    8,    8,   21,   22,   23,   24,   25,   26,   27,
+       28,   29,   30,   31,   32,   33,   34,   31,   35,   36,
+       31,   37,   38,   39,   31,   40,   31,   41,   31,   42,
+        8,    8,    8,    8,    8,   43,   43,   44,   43,  166,
+       67,  167,   76,   46,   60,   60,   60,   60,   67,   68,
+       69,   69,   62,   70,   71,   71,   72,   75,   75,   75,
+       77,   72,   73,   73,   73,   79,   81,   83,   78,   86,
+
+       89,   84,  168,   92,   93,   87,   82,   96,   99,   80,
+       94,   97,  169,  369,   90,   98,  100,   91,  122,  123,
+      101,  122,  155,  155,  155,   43,   43,   43,   43,   43,
+       43,   43,   44,   43,   74,   63,   64,   65,   46,  102,
+      105,  109,  112,  194,  106,  113,  115,  103,  117,  124,
+      123,  107,  124,  195,  104,  110,  368,  114,  367,  108,
+      116,  111,  118,  122,  123,  119,  122,   67,   72,   73,
+       73,   73,  158,  158,  158,   67,   72,  157,  157,  157,
+       72,   73,   73,   73,   72,   75,   75,   75,  366,  365,
+       43,   43,   43,   43,   43,   48,   49,  160,   50,  170,
+
+       51,  364,  177,  161,  171,  172,  178,   52,  159,  159,
+      159,  156,   53,   54,  159,  159,  159,  159,  174,  186,
+      190,  192,  198,  363,  175,  193,   55,  191,  362,  122,
+      123,  187,  122,  199,  124,  123,  188,  124,  124,  123,
+      361,  124,  125,  126,  214,  125,  360,  214,  125,  126,
+      214,  125,  359,  214,   56,   57,   58,   59,   56,   48,
+       49,  358,   50,  357,   51,  215,  215,  215,  216,  216,
+      216,   52,  217,  217,  217,  356,   53,   54,  218,  218,
+      218,  219,  219,  219,  220,  220,  220,  221,  221,  221,
+       55,  222,  222,  222,  223,  223,  223,  224,  224,  224,
+
+      155,  155,  155,  232,  232,  232,  158,  158,  158,  232,
+      232,  232,  232,   72,  157,  157,  157,  355,   56,   57,
+       58,   59,   56,  125,  126,  354,  127,  353,  128,  233,
+      296,  296,  296,  352,  351,  129,  350,  130,  130,  347,
+      131,  132,  133,  346,  134,  135,  136,  137,  138,  139,
+      140,  141,  142,  143,  144,  345,  145,  145,  145,  145,
+      145,  145,  145,  145,  145,  145,  145,  145,  234,  159,
+      159,  159,  215,  215,  215,  159,  159,  159,  159,  216,
+      216,  216,  217,  217,  217,  218,  218,  218,  344,  281,
+      219,  219,  219,  220,  220,  220,  282,  343,  342,  283,
+
+      341,  340,  284,  221,  221,  221,  339,  285,  338,  337,
+      286,  222,  222,  222,  223,  223,  223,  224,  224,  224,
+      287,  295,  295,  336,  296,  296,  296,  335,  288,  334,
+      333,  289,  332,  331,  290,  234,  232,  232,  232,  329,
+      328,  327,  232,  232,  232,  232,  297,  297,  297,  326,
+      325,  324,  297,  297,  297,  297,  297,  297,  297,  323,
+      322,  321,  297,  297,  297,  297,  348,  348,  320,  349,
+      349,  349,  319,  318,  317,  349,  349,  349,  349,  349,
+      349,  349,  316,  315,  314,  349,  349,  349,  349,  313,
+      312,  311,  310,  349,  349,  349,  309,  308,  330,  349,
+
+      349,  349,  349,   45,   45,   45,   45,   47,   47,   47,
+       47,   61,   61,   61,   66,  307,   66,   66,  306,  305,
+      304,  303,  302,  301,  300,  299,  298,  294,  293,  292,
+      291,  280,  279,  278,  277,  276,  275,  274,  273,  272,
+      271,  270,  269,  268,  267,  266,  265,  264,  263,  262,
+      261,  260,  259,  258,  257,  256,  255,  254,  253,  252,
+      251,  250,  249,  248,  247,  246,  245,  244,  243,  242,
+      241,  240,  239,  238,  237,  236,  235,  231,  230,  229,
+      228,  227,  226,  225,  213,  212,  211,  210,  209,  208,
+      207,  206,  205,  204,  203,  202,  201,  200,  197,  196,
+
+      189,  185,  184,  183,  182,  181,  180,  179,  176,  173,
+      165,  164,  163,  162,  154,  153,  152,  151,  150,  149,
+      148,  147,  146,  121,  120,   95,   88,   85,  370,    7,
+      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
+      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
+      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
+      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
+      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
+      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
+      370,  370,  370,  370,  370
+
+    } ;
+
+static const flex_int16_t yy_chk[696] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    3,    3,    3,    3,   82,
+       14,   82,  375,    3,   13,   13,   13,   13,   14,   15,
+       15,   15,   13,   16,   16,   16,   18,   18,   18,   18,
+       22,   17,   17,   17,   17,   23,   24,   25,   22,   27,
+
+       29,   25,   83,   30,   30,   27,   24,   33,   34,   23,
+       30,   33,   83,  368,   29,   33,   34,   29,   48,   48,
+       34,   48,   69,   69,   69,    3,    3,    3,    3,    3,
+        4,    4,    4,    4,   17,   13,   13,   13,    4,   35,
+       36,   37,   38,  100,   36,   38,   39,   35,   40,   49,
+       49,   36,   49,  100,   35,   37,  366,   38,  363,   36,
+       39,   37,   40,   50,   50,   40,   50,   66,   70,   70,
+       70,   70,   72,   72,   72,   66,   71,   71,   71,   71,
+       73,   73,   73,   73,   75,   75,   75,   75,  362,  356,
+        4,    4,    4,    4,    4,    5,    5,   77,    5,   84,
+
+        5,  354,   88,   77,   84,   84,   88,    5,   74,   74,
+       74,   70,    5,    5,   74,   74,   74,   74,   86,   96,
+       98,   99,  105,  353,   86,   99,    5,   98,  352,  122,
+      122,   96,  122,  105,  123,  123,   96,  123,  124,  124,
+      350,  124,  125,  125,  126,  125,  345,  126,  127,  127,
+      214,  127,  344,  214,    5,    5,    5,    5,    5,    6,
+        6,  343,    6,  342,    6,  134,  134,  134,  135,  135,
+      135,    6,  136,  136,  136,  341,    6,    6,  137,  137,
+      137,  138,  138,  138,  139,  139,  139,  140,  140,  140,
+        6,  141,  141,  141,  142,  142,  142,  143,  143,  143,
+
+      155,  155,  155,  156,  156,  156,  158,  158,  158,  156,
+      156,  156,  156,  157,  157,  157,  157,  340,    6,    6,
+        6,    6,    6,   55,   55,  339,   55,  337,   55,  158,
+      295,  295,  295,  336,  335,   55,  332,   55,   55,  328,
+       55,   55,   55,  325,   55,   55,   55,   55,   55,   55,
+       55,   55,   55,   55,   55,  324,   55,   55,   55,   55,
+       55,   55,   55,   55,   55,   55,   55,   55,  159,  159,
+      159,  159,  215,  215,  215,  159,  159,  159,  159,  216,
+      216,  216,  217,  217,  217,  218,  218,  218,  323,  215,
+      219,  219,  219,  220,  220,  220,  216,  321,  319,  217,
+
+      317,  316,  218,  221,  221,  221,  315,  219,  308,  307,
+      220,  222,  222,  222,  223,  223,  223,  224,  224,  224,
+      221,  233,  233,  304,  233,  233,  233,  303,  222,  302,
+      301,  223,  300,  298,  224,  232,  232,  232,  232,  294,
+      280,  278,  232,  232,  232,  232,  234,  234,  234,  276,
+      275,  274,  234,  234,  234,  234,  297,  297,  297,  273,
+      271,  269,  297,  297,  297,  297,  330,  330,  268,  330,
+      330,  330,  266,  265,  262,  330,  330,  330,  330,  348,
+      348,  348,  261,  259,  258,  348,  348,  348,  348,  255,
+      253,  251,  248,  349,  349,  349,  247,  246,  297,  349,
+
+      349,  349,  349,  371,  371,  371,  371,  372,  372,  372,
+      372,  373,  373,  373,  374,  244,  374,  374,  243,  242,
+      241,  240,  239,  238,  237,  236,  235,  231,  230,  228,
+      226,  213,  212,  211,  210,  208,  207,  206,  205,  204,
+      202,  201,  200,  199,  198,  197,  195,  192,  191,  190,
+      189,  188,  187,  186,  185,  184,  182,  181,  180,  179,
+      178,  177,  176,  175,  174,  173,  172,  171,  170,  169,
+      168,  167,  166,  165,  163,  162,  161,  154,  153,  152,
+      151,  150,  148,  147,  120,  119,  118,  117,  116,  115,
+      114,  113,  112,  111,  110,  109,  107,  106,  104,  102,
+
+       97,   95,   94,   93,   92,   91,   90,   89,   87,   85,
+       81,   80,   79,   78,   65,   64,   63,   62,   61,   60,
+       59,   58,   57,   46,   41,   32,   28,   26,    7,  370,
+      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
+      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
+      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
+      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
+      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
+      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
+      370,  370,  370,  370,  370
+
+    } ;
+
+/* Table of booleans, true if rule could match eol. */
+static const flex_int32_t yy_rule_can_match_eol[127] =
+    {   0,
+0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 
+    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0,     };
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+extern int yy_flex_debug;
+int yy_flex_debug = 1;
+
+static const flex_int16_t yy_rule_linenum[126] =
+    {   0,
+      171,  172,  173,  174,  175,  176,  177,  179,  181,  183,
+      185,  186,  187,  188,  189,  194,  195,  196,  197,  198,
+      199,  200,  201,  203,  205,  207,  208,  209,  210,  212,
+      213,  214,  216,  217,  218,  220,  221,  223,  225,  226,
+      227,  229,  230,  232,  233,  234,  236,  239,  241,  242,
+      244,  245,  246,  247,  248,  249,  250,  252,  253,  255,
+      257,  258,  259,  260,  261,  262,  263,  264,  265,  268,
+      270,  271,  272,  274,  275,  276,  277,  280,  281,  282,
+      284,  285,  286,  287,  288,  289,  290,  292,  293,  294,
+      295,  297,  299,  301,  303,  305,  307,  308,  310,  312,
+
+      313,  314,  315,  317,  319,  320,  321,  323,  325,  327,
+      328,  329,  330,  331,  333,  335,  337,  338,  340,  342,
+      344,  346,  348,  350,  351
+    } ;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "lexer.l"
+#line 2 "lexer.l"
+	/*509:*/
+	#line 10171 "format.w"
+	
+#include "hibasetypes.h"
+#include "hierror.h"
+#include "hiformat.h"
+#include "hiput.h"
+
+	/*423:*/
+#ifdef DEBUG
+#define  YYDEBUG 1
+extern int yydebug;
+#else
+#define YYDEBUG 0
+#endif
+	/*:423*/
+#include "hiparser.h"
+
+	/*22:*/
+#define SCAN_UDEC(S) yylval.u= strtoul(S,NULL,10)
+	/*:22*/	/*25:*/
+#define SCAN_HEX(S) yylval.u= strtoul(S,NULL,16)
+	/*:25*/	/*28:*/
+#define SCAN_DEC(S) yylval.i= strtol(S,NULL,10)
+	/*:28*/	/*31:*/
+#define MAX_STR    (1<<10) 
+static char str_buffer[MAX_STR];
+static int str_length;
+#define STR_START      (str_length= 0)
+#define STR_PUT(C) (str_buffer[str_length++]= (C))
+#define STR_ADD(C) STR_PUT(C);RNG("String length",str_length,0,MAX_STR-1)
+#define STR_END        str_buffer[str_length]= 0
+#define SCAN_STR       yylval.s= str_buffer
+	/*:31*/	/*40:*/
+#define SCAN_UTF8_1(S)   yylval.u= ((S)[0]&0x7F)
+	/*:40*/	/*42:*/
+#define SCAN_UTF8_2(S)   yylval.u= (((S)[0]&0x1F)<<6)+((S)[1]&0x3F)
+	/*:42*/	/*44:*/
+#define SCAN_UTF8_3(S)   yylval.u= (((S)[0]&0x0F)<<12)+(((S)[1]&0x3F)<<6)+((S)[2]&0x3F)
+	/*:44*/	/*46:*/
+#define SCAN_UTF8_4(S)   yylval.u= (((S)[0]&0x03)<<18)+(((S)[1]&0x3F)<<12)+(((S)[2]&0x3F)<<6)+((S)[3]&0x3F)
+	/*:46*/	/*57:*/
+#define SCAN_DECFLOAT       yylval.f= atof(yytext)
+	/*:57*/	/*60:*/
+#define SCAN_HEXFLOAT       yylval.f= xtof(yytext)
+	/*:60*/	/*152:*/
+#define SCAN_REF(K) yylval.rf.k= K; yylval.rf.n= atoi(yytext+2)
+static int scan_level= 0;
+#define SCAN_START          yy_push_state(INITIAL);if (1==scan_level++) hpos0= hpos;
+#define SCAN_END            if (scan_level--) yy_pop_state(); else QUIT("Too many '>' in line %d",yylineno)
+#define SCAN_TXT_START      BEGIN(TXT)
+#define SCAN_TXT_END        BEGIN(INITIAL)
+	/*:152*/
+	/*61:*/
+
+float64_t xtof(char*x)
+{
+	#line 1369 "format.w"
+	int sign,digits,exp;
+	uint64_t mantissa= 0;
+	DBG(DBGFLOAT,"converting %s:\n",x);
+		/*62:*/
+	if(*x=='-'){sign= -1;x++;}
+	else if(*x=='+'){sign= +1;x++;}
+	else sign= +1;
+	DBG(DBGFLOAT,"\tsign=%d\n",sign);
+		/*:62*/
+	x= x+2;
+		/*63:*/
+	digits= 0;
+	while(*x=='0')x++;
+	while(*x!='.')
+	{mantissa= mantissa<<4;
+	if(*x<'A')mantissa= mantissa+*x-'0';
+	else mantissa= mantissa+*x-'A'+10;
+	x++;
+	digits++;
+	}
+	x++;
+	exp= 0;
+	while(*x!=0&&*x!='x')
+	{mantissa= mantissa<<4;
+	exp= exp-4;
+	if(*x<'A')mantissa= mantissa+*x-'0';
+	else mantissa= mantissa+*x-'A'+10;
+	x++;
+	digits++;
+	}
+	DBG(DBGFLOAT,"\tdigits=%d mantissa=0x%"PRIx64", exp=%d\n",digits,mantissa,exp);
+		/*:63*/
+		/*64:*/
+	if(mantissa==0)return 0.0;
+	{int s;
+	s= digits-DBL_M_BITS/4;
+	if(s>1)
+	mantissa= mantissa>>(4*(s-1));
+	else if(s<1)
+	mantissa= mantissa<<(4*(1-s));
+	exp= exp+4*(digits-1);
+	DBG(DBGFLOAT,"\tdigits=%d mantissa=0x%"PRIx64", exp=%d\n",digits,mantissa,exp);
+	while((mantissa>>DBL_M_BITS)>1){mantissa= mantissa>>1;exp++;}
+	DBG(DBGFLOAT,"\tdigits=%d mantissa=0x%"PRIx64", exp=%d\n",digits,mantissa,exp);
+	mantissa= mantissa&~((uint64_t)1<<DBL_M_BITS);
+	DBG(DBGFLOAT,"\tdigits=%d mantissa=0x%"PRIx64", exp=%d\n",digits,mantissa,exp);
+	}
+		/*:64*/
+		/*65:*/
+	if(*x=='x')
+	{int s;
+	x++;
+	if(*x=='-'){s= -1;x++;}
+	else if(*x=='+'){s= +1;x++;}
+	else s= +1;
+	DBG(DBGFLOAT,"\texpsign=%d\n",s);
+	DBG(DBGFLOAT,"\texp=%d\n",exp);
+	while(*x!=0)
+	{if(*x<'A')exp= exp+4*s*(*x-'0');
+	else exp= exp+4*s*(*x-'A'+10);
+	x++;
+	DBG(DBGFLOAT,"\texp=%d\n",exp);
+	}
+	}
+	RNG("Floating point exponent",exp,-DBL_EXCESS,DBL_EXCESS);
+		/*:65*/
+		/*66:*/
+	{union{float64_t d;uint64_t bits;}u;
+	if(sign<0)sign= 1;else sign= 0;
+	exp= exp+DBL_EXCESS;
+	u.bits= ((uint64_t)sign<<63)
+		|((uint64_t)exp<<DBL_M_BITS)	|mantissa;
+	DBG(DBGFLOAT," return %f\n",u.d);
+	return u.d;
+	}
+		/*:66*/
+	}
+	/*:61*/
+int yywrap(void){
+	#line 10182 "format.w"
+	return 1;}
+#ifdef _MSC_VER
+#pragma  warning( disable : 4267)
+#endif
+
+#line 989 "lexer.c"
+#define YY_NO_UNISTD_H 1
+#define YY_NO_INPUT 1
+#line 152 "lexer.l"
+	/*23:*/
+	/*:23*/	/*32:*/
+
+	/*:32*/	/*39:*/
+	/*:39*/	/*41:*/
+	/*:41*/	/*43:*/
+	/*:43*/	/*45:*/
+	/*:45*/	/*149:*/
+
+	/*:149*/
+#line 1003 "lexer.c"
+
+#define INITIAL 0
+#define STR 1
+#define TXT 2
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "hiunistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+/* %if-c-only */
+#include <unistd.h>
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* %if-c-only Reentrant structure and macros (non-C++). */
+/* %if-reentrant */
+/* %if-c-only */
+
+static int yy_init_globals ( void );
+
+/* %endif */
+/* %if-reentrant */
+/* %endif */
+/* %endif End reentrant structures and macros. */
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy ( void );
+
+int yyget_debug ( void );
+
+void yyset_debug ( int debug_flag  );
+
+YY_EXTRA_TYPE yyget_extra ( void );
+
+void yyset_extra ( YY_EXTRA_TYPE user_defined  );
+
+FILE *yyget_in ( void );
+
+void yyset_in  ( FILE * _in_str  );
+
+FILE *yyget_out ( void );
+
+void yyset_out  ( FILE * _out_str  );
+
+			int yyget_leng ( void );
+
+char *yyget_text ( void );
+
+int yyget_lineno ( void );
+
+void yyset_lineno ( int _line_number  );
+
+/* %if-bison-bridge */
+/* %endif */
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap ( void );
+#else
+extern int yywrap ( void );
+#endif
+#endif
+
+/* %not-for-header */
+#ifndef YY_NO_UNPUT
+    
+#endif
+/* %ok-for-header */
+
+/* %endif */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy ( char *, const char *, int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen ( const char * );
+#endif
+
+#ifndef YY_NO_INPUT
+/* %if-c-only Standard (non-C++) definition */
+/* %not-for-header */
+#ifdef __cplusplus
+static int yyinput ( void );
+#else
+static int input ( void );
+#endif
+/* %ok-for-header */
+
+/* %endif */
+#endif
+
+/* %if-c-only */
+
+        static int yy_start_stack_ptr = 0;
+        static int yy_start_stack_depth = 0;
+        static int *yy_start_stack = NULL;
+    
+    static void yy_push_state ( int _new_state );
+    
+    static void yy_pop_state ( void );
+    
+/* %endif */
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* %if-c-only Standard (non-C++) definition */
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0)
+/* %endif */
+/* %if-c++-only C++ definition */
+/* %endif */
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+/* %% [5.0] fread()/read() definition of YY_INPUT goes here unless we're doing C++ \ */\
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+		{ \
+		int c = '*'; \
+		int n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( yyin ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else \
+		{ \
+		errno=0; \
+		while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \
+			{ \
+			if( errno != EINTR) \
+				{ \
+				YY_FATAL_ERROR( "input in flex scanner failed" ); \
+				break; \
+				} \
+			errno=0; \
+			clearerr(yyin); \
+			} \
+		}\
+\
+/* %if-c++-only C++ definition \ */\
+/* %endif */
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+/* %if-c-only */
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+#endif
+
+/* %if-tables-serialization structures and prototypes */
+/* %not-for-header */
+/* %ok-for-header */
+
+/* %not-for-header */
+/* %tables-yydmap generated elements */
+/* %endif */
+/* end tables serialization structures and prototypes */
+
+/* %ok-for-header */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+/* %if-c-only Standard (non-C++) definition */
+
+extern int yylex (void);
+
+#define YY_DECL int yylex (void)
+/* %endif */
+/* %if-c++-only C++ definition */
+/* %endif */
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK /*LINTED*/break;
+#endif
+
+/* %% [6.0] YY_RULE_SETUP definition goes here */
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+/* %not-for-header */
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+	yy_state_type yy_current_state;
+	char *yy_cp, *yy_bp;
+	int yy_act;
+    
+	if ( !(yy_init) )
+		{
+		(yy_init) = 1;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! (yy_start) )
+			(yy_start) = 1;	/* first start state */
+
+		if ( ! yyin )
+/* %if-c-only */
+			yyin = stdin;
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+
+		if ( ! yyout )
+/* %if-c-only */
+			yyout = stdout;
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+
+		if ( ! YY_CURRENT_BUFFER ) {
+			yyensure_buffer_stack ();
+			YY_CURRENT_BUFFER_LVALUE =
+				yy_create_buffer( yyin, YY_BUF_SIZE );
+		}
+
+		yy_load_buffer_state(  );
+		}
+
+	{
+/* %% [7.0] user's declarations go here */
+#line 168 "lexer.l"
+
+
+	/*3:*/
+#line 1295 "lexer.c"
+
+	while ( /*CONSTCOND*/1 )		/* loops until end-of-file is reached */
+		{
+/* %% [8.0] yymore()-related code goes here */
+		yy_cp = (yy_c_buf_p);
+
+		/* Support of yytext. */
+		*yy_cp = (yy_hold_char);
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+/* %% [9.0] code to set up and find next match goes here */
+		yy_current_state = (yy_start);
+yy_match:
+		do
+			{
+			YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
+			if ( yy_accept[yy_current_state] )
+				{
+				(yy_last_accepting_state) = yy_current_state;
+				(yy_last_accepting_cpos) = yy_cp;
+				}
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 371 )
+					yy_c = yy_meta[yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+			++yy_cp;
+			}
+		while ( yy_current_state != 370 );
+		yy_cp = (yy_last_accepting_cpos);
+		yy_current_state = (yy_last_accepting_state);
+
+yy_find_action:
+/* %% [10.0] code to find the action number goes here */
+		yy_act = yy_accept[yy_current_state];
+
+		YY_DO_BEFORE_ACTION;
+
+/* %% [11.0] code for yylineno update goes here */
+
+		if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
+			{
+			int yyl;
+			for ( yyl = 0; yyl < yyleng; ++yyl )
+				if ( yytext[yyl] == '\n' )
+					
+    yylineno++;
+;
+			}
+
+do_action:	/* This label is used only to access EOF actions. */
+
+/* %% [12.0] debug code goes here */
+		if ( yy_flex_debug )
+			{
+			if ( yy_act == 0 )
+				fprintf( stderr, "--scanner backing up\n" );
+			else if ( yy_act < 126 )
+				fprintf( stderr, "--accepting rule at line %ld (\"%s\")\n",
+				         (long)yy_rule_linenum[yy_act], yytext );
+			else if ( yy_act == 126 )
+				fprintf( stderr, "--accepting default rule (\"%s\")\n",
+				         yytext );
+			else if ( yy_act == 127 )
+				fprintf( stderr, "--(end of buffer or a NUL)\n" );
+			else
+				fprintf( stderr, "--EOF (start condition %d)\n", YY_START );
+			}
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+/* %% [13.0] actions go here */
+			case 0: /* must back up */
+			/* undo the effects of YY_DO_BEFORE_ACTION */
+			*yy_cp = (yy_hold_char);
+			yy_cp = (yy_last_accepting_cpos);
+			yy_current_state = (yy_last_accepting_state);
+			goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 171 "lexer.l"
+SCAN_START;return START;
+	YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 172 "lexer.l"
+SCAN_END;return END;
+	YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 173 "lexer.l"
+return GLYPH;
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 174 "lexer.l"
+SCAN_UDEC(yytext);return UNSIGNED;
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 175 "lexer.l"
+SCAN_UDEC(yytext+1);return REFERENCE;
+	YY_BREAK
+case 6:
+/* rule 6 can match eol */
+YY_RULE_SETUP
+#line 176 "lexer.l"
+;
+	YY_BREAK
+case 7:
+/* rule 7 can match eol */
+YY_RULE_SETUP
+#line 177 "lexer.l"
+;
+	YY_BREAK
+/*:3*/	/*24:*/
+case 8:
+YY_RULE_SETUP
+#line 179 "lexer.l"
+SCAN_HEX(yytext+2);return UNSIGNED;
+	YY_BREAK
+/*:24*/	/*27:*/
+case 9:
+YY_RULE_SETUP
+#line 181 "lexer.l"
+SCAN_DEC(yytext);return SIGNED;
+	YY_BREAK
+/*:27*/	/*34:*/
+case 10:
+YY_RULE_SETUP
+#line 183 "lexer.l"
+STR_START;BEGIN(STR);
+	YY_BREAK
+
+case 11:
+YY_RULE_SETUP
+#line 185 "lexer.l"
+STR_END;SCAN_STR;BEGIN(INITIAL);return STRING;
+	YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 186 "lexer.l"
+STR_ADD('\'');
+	YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 187 "lexer.l"
+STR_ADD(yytext[0]);
+	YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 188 "lexer.l"
+RNG("String character",yytext[0],0x20,0x7E);
+	YY_BREAK
+case 15:
+/* rule 15 can match eol */
+YY_RULE_SETUP
+#line 189 "lexer.l"
+QUIT("Unterminated String in line %d",yylineno);
+	YY_BREAK
+
+/*:34*/	/*48:*/
+case 16:
+YY_RULE_SETUP
+#line 194 "lexer.l"
+STR_START;STR_PUT('\'');BEGIN(STR);
+	YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 195 "lexer.l"
+SCAN_UTF8_1(yytext+1);return CHARCODE;
+	YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 196 "lexer.l"
+STR_START;STR_PUT(yytext[1]);STR_PUT('\'');BEGIN(STR);
+	YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 197 "lexer.l"
+STR_START;STR_PUT('\'');STR_PUT('\'');BEGIN(STR);
+	YY_BREAK
+case 20:
+/* rule 20 can match eol */
+YY_RULE_SETUP
+#line 198 "lexer.l"
+SCAN_UTF8_1(yytext+1);return CHARCODE;
+	YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 199 "lexer.l"
+SCAN_UTF8_2(yytext+1);return CHARCODE;
+	YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 200 "lexer.l"
+SCAN_UTF8_3(yytext+1);return CHARCODE;
+	YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 201 "lexer.l"
+SCAN_UTF8_4(yytext+1);return CHARCODE;
+	YY_BREAK
+/*:48*/	/*55:*/
+case 24:
+YY_RULE_SETUP
+#line 203 "lexer.l"
+SCAN_DECFLOAT;return FPNUM;
+	YY_BREAK
+/*:55*/	/*59:*/
+case 25:
+YY_RULE_SETUP
+#line 205 "lexer.l"
+SCAN_HEXFLOAT;return FPNUM;
+	YY_BREAK
+/*:59*/	/*80:*/
+case 26:
+YY_RULE_SETUP
+#line 207 "lexer.l"
+return DIMEN;
+	YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 208 "lexer.l"
+return PT;
+	YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 209 "lexer.l"
+return MM;
+	YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 210 "lexer.l"
+return INCH;
+	YY_BREAK
+/*:80*/	/*88:*/
+case 30:
+YY_RULE_SETUP
+#line 212 "lexer.l"
+return XDIMEN;
+	YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 213 "lexer.l"
+return H;
+	YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 214 "lexer.l"
+return V;
+	YY_BREAK
+/*:88*/	/*99:*/
+case 33:
+YY_RULE_SETUP
+#line 216 "lexer.l"
+return FIL;
+	YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 217 "lexer.l"
+return FILL;
+	YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 218 "lexer.l"
+return FILLL;
+	YY_BREAK
+/*:99*/	/*103:*/
+case 36:
+YY_RULE_SETUP
+#line 220 "lexer.l"
+return PENALTY;
+	YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 221 "lexer.l"
+return INTEGER;
+	YY_BREAK
+/*:103*/	/*109:*/
+case 38:
+YY_RULE_SETUP
+#line 223 "lexer.l"
+return LANGUAGE;
+	YY_BREAK
+/*:109*/	/*115:*/
+case 39:
+YY_RULE_SETUP
+#line 225 "lexer.l"
+return RULE;
+	YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 226 "lexer.l"
+return RUNNING;
+	YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 227 "lexer.l"
+return RUNNING;
+	YY_BREAK
+/*:115*/	/*124:*/
+case 42:
+YY_RULE_SETUP
+#line 229 "lexer.l"
+return KERN;
+	YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 230 "lexer.l"
+return EXPLICIT;
+	YY_BREAK
+/*:124*/	/*133:*/
+case 44:
+YY_RULE_SETUP
+#line 232 "lexer.l"
+return GLUE;
+	YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 233 "lexer.l"
+return PLUS;
+	YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 234 "lexer.l"
+return MINUS;
+	YY_BREAK
+/*:133*/	/*151:*/
+case 47:
+YY_RULE_SETUP
+#line 236 "lexer.l"
+SCAN_TXT_START;return TXT_START;
+	YY_BREAK
+
+case 48:
+YY_RULE_SETUP
+#line 239 "lexer.l"
+SCAN_TXT_END;return TXT_END;
+	YY_BREAK
+case 49:
+YY_RULE_SETUP
+#line 241 "lexer.l"
+SCAN_START;return START;
+	YY_BREAK
+case 50:
+YY_RULE_SETUP
+#line 242 "lexer.l"
+QUIT("> not allowed in text mode");
+	YY_BREAK
+case 51:
+YY_RULE_SETUP
+#line 244 "lexer.l"
+yylval.u= '\\';return TXT_CC;
+	YY_BREAK
+case 52:
+YY_RULE_SETUP
+#line 245 "lexer.l"
+yylval.u= '"';return TXT_CC;
+	YY_BREAK
+case 53:
+YY_RULE_SETUP
+#line 246 "lexer.l"
+yylval.u= '<';return TXT_CC;
+	YY_BREAK
+case 54:
+YY_RULE_SETUP
+#line 247 "lexer.l"
+yylval.u= '>';return TXT_CC;
+	YY_BREAK
+case 55:
+YY_RULE_SETUP
+#line 248 "lexer.l"
+yylval.u= ' ';return TXT_CC;
+	YY_BREAK
+case 56:
+YY_RULE_SETUP
+#line 249 "lexer.l"
+yylval.u= '-';return TXT_CC;
+	YY_BREAK
+case 57:
+YY_RULE_SETUP
+#line 250 "lexer.l"
+return TXT_IGNORE;
+	YY_BREAK
+case 58:
+/* rule 58 can match eol */
+YY_RULE_SETUP
+#line 252 "lexer.l"
+return TXT_FONT_GLUE;
+	YY_BREAK
+case 59:
+/* rule 59 can match eol */
+YY_RULE_SETUP
+#line 253 "lexer.l"
+;
+	YY_BREAK
+case 60:
+YY_RULE_SETUP
+#line 255 "lexer.l"
+yylval.u= yytext[1]-'0';return TXT_FONT;
+	YY_BREAK
+case 61:
+YY_RULE_SETUP
+#line 257 "lexer.l"
+SCAN_REF(font_kind);return TXT_GLOBAL;
+	YY_BREAK
+case 62:
+YY_RULE_SETUP
+#line 258 "lexer.l"
+SCAN_REF(penalty_kind);return TXT_GLOBAL;
+	YY_BREAK
+case 63:
+YY_RULE_SETUP
+#line 259 "lexer.l"
+SCAN_REF(kern_kind);return TXT_GLOBAL;
+	YY_BREAK
+case 64:
+YY_RULE_SETUP
+#line 260 "lexer.l"
+SCAN_REF(ligature_kind);return TXT_GLOBAL;
+	YY_BREAK
+case 65:
+YY_RULE_SETUP
+#line 261 "lexer.l"
+SCAN_REF(disc_kind);return TXT_GLOBAL;
+	YY_BREAK
+case 66:
+YY_RULE_SETUP
+#line 262 "lexer.l"
+SCAN_REF(glue_kind);return TXT_GLOBAL;
+	YY_BREAK
+case 67:
+YY_RULE_SETUP
+#line 263 "lexer.l"
+SCAN_REF(language_kind);return TXT_GLOBAL;
+	YY_BREAK
+case 68:
+YY_RULE_SETUP
+#line 264 "lexer.l"
+SCAN_REF(rule_kind);return TXT_GLOBAL;
+	YY_BREAK
+case 69:
+YY_RULE_SETUP
+#line 265 "lexer.l"
+SCAN_REF(image_kind);return TXT_GLOBAL;
+	YY_BREAK
+case 70:
+YY_RULE_SETUP
+#line 268 "lexer.l"
+SCAN_UDEC(yytext+2);return TXT_CC;
+	YY_BREAK
+case 71:
+YY_RULE_SETUP
+#line 270 "lexer.l"
+yylval.u= yytext[1]-'a';return TXT_LOCAL;
+	YY_BREAK
+case 72:
+YY_RULE_SETUP
+#line 271 "lexer.l"
+return TXT_FONT_GLUE;
+	YY_BREAK
+case 73:
+YY_RULE_SETUP
+#line 272 "lexer.l"
+return TXT_FONT_HYPHEN;
+	YY_BREAK
+case 74:
+/* rule 74 can match eol */
+YY_RULE_SETUP
+#line 274 "lexer.l"
+SCAN_UTF8_1(yytext);return TXT_CC;
+	YY_BREAK
+case 75:
+YY_RULE_SETUP
+#line 275 "lexer.l"
+SCAN_UTF8_2(yytext);return TXT_CC;
+	YY_BREAK
+case 76:
+YY_RULE_SETUP
+#line 276 "lexer.l"
+SCAN_UTF8_3(yytext);return TXT_CC;
+	YY_BREAK
+case 77:
+YY_RULE_SETUP
+#line 277 "lexer.l"
+SCAN_UTF8_4(yytext);return TXT_CC;
+	YY_BREAK
+
+/*:151*/	/*162:*/
+case 78:
+YY_RULE_SETUP
+#line 280 "lexer.l"
+return HBOX;
+	YY_BREAK
+case 79:
+YY_RULE_SETUP
+#line 281 "lexer.l"
+return VBOX;
+	YY_BREAK
+case 80:
+YY_RULE_SETUP
+#line 282 "lexer.l"
+return SHIFTED;
+	YY_BREAK
+/*:162*/	/*170:*/
+case 81:
+YY_RULE_SETUP
+#line 284 "lexer.l"
+return HPACK;
+	YY_BREAK
+case 82:
+YY_RULE_SETUP
+#line 285 "lexer.l"
+return HSET;
+	YY_BREAK
+case 83:
+YY_RULE_SETUP
+#line 286 "lexer.l"
+return VPACK;
+	YY_BREAK
+case 84:
+YY_RULE_SETUP
+#line 287 "lexer.l"
+return VSET;
+	YY_BREAK
+case 85:
+YY_RULE_SETUP
+#line 288 "lexer.l"
+return ADD;
+	YY_BREAK
+case 86:
+YY_RULE_SETUP
+#line 289 "lexer.l"
+return TO;
+	YY_BREAK
+case 87:
+YY_RULE_SETUP
+#line 290 "lexer.l"
+return DEPTH;
+	YY_BREAK
+/*:170*/	/*175:*/
+case 88:
+YY_RULE_SETUP
+#line 292 "lexer.l"
+return LEADERS;
+	YY_BREAK
+case 89:
+YY_RULE_SETUP
+#line 293 "lexer.l"
+return ALIGN;
+	YY_BREAK
+case 90:
+YY_RULE_SETUP
+#line 294 "lexer.l"
+return CENTER;
+	YY_BREAK
+case 91:
+YY_RULE_SETUP
+#line 295 "lexer.l"
+return EXPAND;
+	YY_BREAK
+/*:175*/	/*182:*/
+case 92:
+YY_RULE_SETUP
+#line 297 "lexer.l"
+return BASELINE;
+	YY_BREAK
+/*:182*/	/*189:*/
+case 93:
+YY_RULE_SETUP
+#line 299 "lexer.l"
+return LIGATURE;
+	YY_BREAK
+/*:189*/	/*197:*/
+case 94:
+YY_RULE_SETUP
+#line 301 "lexer.l"
+return DISC;
+	YY_BREAK
+/*:197*/	/*205:*/
+case 95:
+YY_RULE_SETUP
+#line 303 "lexer.l"
+return PAR;
+	YY_BREAK
+/*:205*/	/*210:*/
+case 96:
+YY_RULE_SETUP
+#line 305 "lexer.l"
+return MATH;
+	YY_BREAK
+/*:210*/	/*215:*/
+case 97:
+YY_RULE_SETUP
+#line 307 "lexer.l"
+return ON;
+	YY_BREAK
+case 98:
+YY_RULE_SETUP
+#line 308 "lexer.l"
+return OFF;
+	YY_BREAK
+/*:215*/	/*219:*/
+case 99:
+YY_RULE_SETUP
+#line 310 "lexer.l"
+return ADJUST;
+	YY_BREAK
+/*:219*/	/*223:*/
+case 100:
+YY_RULE_SETUP
+#line 312 "lexer.l"
+return TABLE;
+	YY_BREAK
+case 101:
+YY_RULE_SETUP
+#line 313 "lexer.l"
+return ITEM;
+	YY_BREAK
+case 102:
+YY_RULE_SETUP
+#line 314 "lexer.l"
+return ITEM;
+	YY_BREAK
+case 103:
+YY_RULE_SETUP
+#line 315 "lexer.l"
+return ITEM;
+	YY_BREAK
+/*:223*/	/*230:*/
+case 104:
+YY_RULE_SETUP
+#line 317 "lexer.l"
+return IMAGE;
+	YY_BREAK
+/*:230*/	/*247:*/
+case 105:
+YY_RULE_SETUP
+#line 319 "lexer.l"
+return LABEL;
+	YY_BREAK
+case 106:
+YY_RULE_SETUP
+#line 320 "lexer.l"
+return BOT;
+	YY_BREAK
+case 107:
+YY_RULE_SETUP
+#line 321 "lexer.l"
+return MID;
+	YY_BREAK
+/*:247*/	/*261:*/
+case 108:
+YY_RULE_SETUP
+#line 323 "lexer.l"
+return LINK;
+	YY_BREAK
+/*:261*/	/*271:*/
+case 109:
+YY_RULE_SETUP
+#line 325 "lexer.l"
+return OUTLINE;
+	YY_BREAK
+/*:271*/	/*278:*/
+case 110:
+YY_RULE_SETUP
+#line 327 "lexer.l"
+if(section_no==1)return STREAMDEF;else return STREAM;
+	YY_BREAK
+case 111:
+YY_RULE_SETUP
+#line 328 "lexer.l"
+return FIRST;
+	YY_BREAK
+case 112:
+YY_RULE_SETUP
+#line 329 "lexer.l"
+return LAST;
+	YY_BREAK
+case 113:
+YY_RULE_SETUP
+#line 330 "lexer.l"
+return TOP;
+	YY_BREAK
+case 114:
+YY_RULE_SETUP
+#line 331 "lexer.l"
+return NOREFERENCE;
+	YY_BREAK
+/*:278*/	/*288:*/
+case 115:
+YY_RULE_SETUP
+#line 333 "lexer.l"
+return PAGE;
+	YY_BREAK
+/*:288*/	/*296:*/
+case 116:
+YY_RULE_SETUP
+#line 335 "lexer.l"
+return RANGE;
+	YY_BREAK
+/*:296*/	/*323:*/
+case 117:
+YY_RULE_SETUP
+#line 337 "lexer.l"
+return DIRECTORY;
+	YY_BREAK
+case 118:
+YY_RULE_SETUP
+#line 338 "lexer.l"
+return SECTION;
+	YY_BREAK
+/*:323*/	/*342:*/
+case 119:
+YY_RULE_SETUP
+#line 340 "lexer.l"
+return DEFINITIONS;
+	YY_BREAK
+/*:342*/	/*350:*/
+case 120:
+YY_RULE_SETUP
+#line 342 "lexer.l"
+return MAX;
+	YY_BREAK
+/*:350*/	/*365:*/
+case 121:
+YY_RULE_SETUP
+#line 344 "lexer.l"
+return PARAM;
+	YY_BREAK
+/*:365*/	/*374:*/
+case 122:
+YY_RULE_SETUP
+#line 346 "lexer.l"
+return FONT;
+	YY_BREAK
+/*:374*/	/*402:*/
+case 123:
+YY_RULE_SETUP
+#line 348 "lexer.l"
+return CONTENT;
+	YY_BREAK
+/*:402*/
+case 124:
+YY_RULE_SETUP
+#line 350 "lexer.l"
+QUIT("Unexpected keyword '%s' in line %d",yytext,yylineno);
+	YY_BREAK
+case 125:
+YY_RULE_SETUP
+#line 351 "lexer.l"
+QUIT("Unexpected character '%c' (0x%02X) in line %d",yytext[0]>' '?yytext[0]:' ',yytext[0],yylineno);
+	YY_BREAK
+case 126:
+YY_RULE_SETUP
+#line 353 "lexer.l"
+ECHO;
+	YY_BREAK
+#line 2062 "lexer.c"
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(STR):
+case YY_STATE_EOF(TXT):
+	yyterminate();
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = (yy_hold_char);
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed yyin at a new source and called
+			 * yylex().  If so, then we have to assure
+			 * consistency between YY_CURRENT_BUFFER and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+/* %if-c-only */
+			YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			(yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state(  );
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+			yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++(yy_c_buf_p);
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+/* %% [14.0] code to do back-up for compressed tables and set up yy_cp goes here */
+				yy_cp = (yy_last_accepting_cpos);
+				yy_current_state = (yy_last_accepting_state);
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer(  ) )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				(yy_did_buffer_switch_on_eof) = 0;
+
+				if ( yywrap(  ) )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * yytext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					(yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				(yy_c_buf_p) =
+					(yytext_ptr) + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				(yy_c_buf_p) =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+	} /* end of user's declarations */
+} /* end of yylex */
+/* %ok-for-header */
+
+/* %if-c++-only */
+/* %not-for-header */
+/* %ok-for-header */
+
+/* %endif */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+/* %if-c-only */
+static int yy_get_next_buffer (void)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+    	char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+	char *source = (yytext_ptr);
+	int number_to_move, i;
+	int ret_val;
+
+	if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr) - 1);
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+	else
+		{
+			int num_to_read =
+			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+			int yy_c_buf_p_offset =
+				(int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				int new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					yyrealloc( (void *) b->yy_ch_buf,
+							 (yy_size_t) (b->yy_buf_size + 2)  );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = NULL;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			(yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+						number_to_move - 1;
+
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+			(yy_n_chars), num_to_read );
+
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	if ( (yy_n_chars) == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			yyrestart( yyin  );
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	if (((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+		/* Extend the array by 50%, plus the number we really need. */
+		int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc(
+			(void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size  );
+		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+		/* "- 2" to take care of EOB's */
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2);
+	}
+
+	(yy_n_chars) += number_to_move;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+	(yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+/* %if-c-only */
+/* %not-for-header */
+    static yy_state_type yy_get_previous_state (void)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+	yy_state_type yy_current_state;
+	char *yy_cp;
+    
+/* %% [15.0] code to get the start state into yy_current_state goes here */
+	yy_current_state = (yy_start);
+
+	for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+		{
+/* %% [16.0] code to find the next state goes here */
+		YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if ( yy_accept[yy_current_state] )
+			{
+			(yy_last_accepting_state) = yy_current_state;
+			(yy_last_accepting_cpos) = yy_cp;
+			}
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 371 )
+				yy_c = yy_meta[yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+		}
+
+	return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+/* %if-c-only */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state )
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+	int yy_is_jam;
+    /* %% [17.0] code to find the next state, and perhaps do backing up, goes here */
+	char *yy_cp = (yy_c_buf_p);
+
+	YY_CHAR yy_c = 1;
+	if ( yy_accept[yy_current_state] )
+		{
+		(yy_last_accepting_state) = yy_current_state;
+		(yy_last_accepting_cpos) = yy_cp;
+		}
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 371 )
+			yy_c = yy_meta[yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+	yy_is_jam = (yy_current_state == 370);
+
+		return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_UNPUT
+/* %if-c-only */
+
+/* %endif */
+#endif
+
+/* %if-c-only */
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (void)
+#else
+    static int input  (void)
+#endif
+
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+	int c;
+    
+	*(yy_c_buf_p) = (yy_hold_char);
+
+	if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			/* This was really a NUL. */
+			*(yy_c_buf_p) = '\0';
+
+		else
+			{ /* need more input */
+			int offset = (int) ((yy_c_buf_p) - (yytext_ptr));
+			++(yy_c_buf_p);
+
+			switch ( yy_get_next_buffer(  ) )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					yyrestart( yyin );
+
+					/*FALLTHROUGH*/
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( yywrap(  ) )
+						return 0;
+
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					(yy_c_buf_p) = (yytext_ptr) + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) (yy_c_buf_p);	/* cast for 8-bit char's */
+	*(yy_c_buf_p) = '\0';	/* preserve yytext */
+	(yy_hold_char) = *++(yy_c_buf_p);
+
+/* %% [19.0] update BOL and yylineno */
+	if ( c == '\n' )
+		
+    yylineno++;
+;
+
+	return c;
+}
+/* %if-c-only */
+#endif	/* ifndef YY_NO_INPUT */
+/* %endif */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * 
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+/* %if-c-only */
+    void yyrestart  (FILE * input_file )
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+    
+	if ( ! YY_CURRENT_BUFFER ){
+        yyensure_buffer_stack ();
+		YY_CURRENT_BUFFER_LVALUE =
+            yy_create_buffer( yyin, YY_BUF_SIZE );
+	}
+
+	yy_init_buffer( YY_CURRENT_BUFFER, input_file );
+	yy_load_buffer_state(  );
+}
+
+/* %if-c++-only */
+/* %endif */
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * 
+ */
+/* %if-c-only */
+    void yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer )
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+    
+	/* TODO. We should be able to replace this entire function body
+	 * with
+	 *		yypop_buffer_state();
+	 *		yypush_buffer_state(new_buffer);
+     */
+	yyensure_buffer_stack ();
+	if ( YY_CURRENT_BUFFER == new_buffer )
+		return;
+
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+	yy_load_buffer_state(  );
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (yywrap()) processing, but the only time this flag
+	 * is looked at is after yywrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+/* %if-c-only */
+static void yy_load_buffer_state  (void)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+    	(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+	(yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+/* %if-c-only */
+	yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+	(yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * 
+ * @return the allocated buffer state.
+ */
+/* %if-c-only */
+    YY_BUFFER_STATE yy_create_buffer  (FILE * file, int  size )
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+	YY_BUFFER_STATE b;
+    
+	b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2)  );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	yy_init_buffer( b, file );
+
+	return b;
+}
+
+/* %if-c++-only */
+/* %endif */
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ * 
+ */
+/* %if-c-only */
+    void yy_delete_buffer (YY_BUFFER_STATE  b )
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+    
+	if ( ! b )
+		return;
+
+	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		yyfree( (void *) b->yy_ch_buf  );
+
+	yyfree( (void *) b  );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+/* %if-c-only */
+    static void yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file )
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+
+{
+	int oerrno = errno;
+    
+	yy_flush_buffer( b );
+
+/* %if-c-only */
+	b->yy_input_file = file;
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+	b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then yy_init_buffer was _probably_
+     * called from yyrestart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+/* %if-c-only */
+
+        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+    
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+	errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * 
+ */
+/* %if-c-only */
+    void yy_flush_buffer (YY_BUFFER_STATE  b )
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+    	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == YY_CURRENT_BUFFER )
+		yy_load_buffer_state(  );
+}
+
+/* %if-c-or-c++ */
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  
+ */
+/* %if-c-only */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+    	if (new_buffer == NULL)
+		return;
+
+	yyensure_buffer_stack();
+
+	/* This block is copied from yy_switch_to_buffer. */
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	/* Only push if top exists. Otherwise, replace top. */
+	if (YY_CURRENT_BUFFER)
+		(yy_buffer_stack_top)++;
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+	/* copied from yy_switch_to_buffer. */
+	yy_load_buffer_state(  );
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+/* %endif */
+
+/* %if-c-or-c++ */
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  
+ */
+/* %if-c-only */
+void yypop_buffer_state (void)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+    	if (!YY_CURRENT_BUFFER)
+		return;
+
+	yy_delete_buffer(YY_CURRENT_BUFFER );
+	YY_CURRENT_BUFFER_LVALUE = NULL;
+	if ((yy_buffer_stack_top) > 0)
+		--(yy_buffer_stack_top);
+
+	if (YY_CURRENT_BUFFER) {
+		yy_load_buffer_state(  );
+		(yy_did_buffer_switch_on_eof) = 1;
+	}
+}
+/* %endif */
+
+/* %if-c-or-c++ */
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+/* %if-c-only */
+static void yyensure_buffer_stack (void)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+	yy_size_t num_to_alloc;
+    
+	if (!(yy_buffer_stack)) {
+
+		/* First allocation is just for 2 elements, since we don't know if this
+		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
+		 * immediate realloc on the next call.
+         */
+      num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
+		(yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
+								(num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+		memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+		(yy_buffer_stack_max) = num_to_alloc;
+		(yy_buffer_stack_top) = 0;
+		return;
+	}
+
+	if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+		/* Increase the buffer to prepare for a possible push. */
+		yy_size_t grow_size = 8 /* arbitrary grow size */;
+
+		num_to_alloc = (yy_buffer_stack_max) + grow_size;
+		(yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
+								((yy_buffer_stack),
+								num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+		/* zero only the new slots.*/
+		memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+		(yy_buffer_stack_max) = num_to_alloc;
+	}
+}
+/* %endif */
+
+/* %if-c-only */
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * 
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size )
+{
+	YY_BUFFER_STATE b;
+    
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return NULL;
+
+	b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+	b->yy_buf_size = (int) (size - 2);	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = NULL;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	yy_switch_to_buffer( b  );
+
+	return b;
+}
+/* %endif */
+
+/* %if-c-only */
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * 
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (const char * yystr )
+{
+    
+	return yy_scan_bytes( yystr, (int) strlen(yystr) );
+}
+/* %endif */
+
+/* %if-c-only */
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * 
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes  (const char * yybytes, int  _yybytes_len )
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+    
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = (yy_size_t) (_yybytes_len + 2);
+	buf = (char *) yyalloc( n  );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+	for ( i = 0; i < _yybytes_len; ++i )
+		buf[i] = yybytes[i];
+
+	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = yy_scan_buffer( buf, n );
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+/* %endif */
+
+/* %if-c-only */
+    static void yy_push_state (int  _new_state )
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+    	if ( (yy_start_stack_ptr) >= (yy_start_stack_depth) )
+		{
+		yy_size_t new_size;
+
+		(yy_start_stack_depth) += YY_START_STACK_INCR;
+		new_size = (yy_size_t) (yy_start_stack_depth) * sizeof( int );
+
+		if ( ! (yy_start_stack) )
+			(yy_start_stack) = (int *) yyalloc( new_size  );
+
+		else
+			(yy_start_stack) = (int *) yyrealloc(
+					(void *) (yy_start_stack), new_size  );
+
+		if ( ! (yy_start_stack) )
+			YY_FATAL_ERROR( "out of memory expanding start-condition stack" );
+		}
+
+	(yy_start_stack)[(yy_start_stack_ptr)++] = YY_START;
+
+	BEGIN(_new_state);
+}
+
+/* %if-c-only */
+    static void yy_pop_state  (void)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+    	if ( --(yy_start_stack_ptr) < 0 )
+		YY_FATAL_ERROR( "start-condition stack underflow" );
+
+	BEGIN((yy_start_stack)[(yy_start_stack_ptr)]);
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+/* %if-c-only */
+static void yynoreturn yy_fatal_error (const char* msg )
+{
+			fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+}
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		yytext[yyleng] = (yy_hold_char); \
+		(yy_c_buf_p) = yytext + yyless_macro_arg; \
+		(yy_hold_char) = *(yy_c_buf_p); \
+		*(yy_c_buf_p) = '\0'; \
+		yyleng = yyless_macro_arg; \
+		} \
+	while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/* %if-c-only */
+/* %if-reentrant */
+/* %endif */
+
+/** Get the current line number.
+ * 
+ */
+int yyget_lineno  (void)
+{
+    
+    return yylineno;
+}
+
+/** Get the input stream.
+ * 
+ */
+FILE *yyget_in  (void)
+{
+        return yyin;
+}
+
+/** Get the output stream.
+ * 
+ */
+FILE *yyget_out  (void)
+{
+        return yyout;
+}
+
+/** Get the length of the current token.
+ * 
+ */
+int yyget_leng  (void)
+{
+        return yyleng;
+}
+
+/** Get the current token.
+ * 
+ */
+
+char *yyget_text  (void)
+{
+        return yytext;
+}
+
+/* %if-reentrant */
+/* %endif */
+
+/** Set the current line number.
+ * @param _line_number line number
+ * 
+ */
+void yyset_lineno (int  _line_number )
+{
+    
+    yylineno = _line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param _in_str A readable stream.
+ * 
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE *  _in_str )
+{
+        yyin = _in_str ;
+}
+
+void yyset_out (FILE *  _out_str )
+{
+        yyout = _out_str ;
+}
+
+int yyget_debug  (void)
+{
+        return yy_flex_debug;
+}
+
+void yyset_debug (int  _bdebug )
+{
+        yy_flex_debug = _bdebug ;
+}
+
+/* %endif */
+
+/* %if-reentrant */
+/* %if-bison-bridge */
+/* %endif */
+/* %endif if-c-only */
+
+/* %if-c-only */
+static int yy_init_globals (void)
+{
+        /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from yylex_destroy(), so don't allocate here.
+     */
+
+    /* We do not touch yylineno unless the option is enabled. */
+    yylineno =  1;
+    
+    (yy_buffer_stack) = NULL;
+    (yy_buffer_stack_top) = 0;
+    (yy_buffer_stack_max) = 0;
+    (yy_c_buf_p) = NULL;
+    (yy_init) = 0;
+    (yy_start) = 0;
+
+    (yy_start_stack_ptr) = 0;
+    (yy_start_stack_depth) = 0;
+    (yy_start_stack) =  NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    yyin = stdin;
+    yyout = stdout;
+#else
+    yyin = NULL;
+    yyout = NULL;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * yylex_init()
+     */
+    return 0;
+}
+/* %endif */
+
+/* %if-c-only SNIP! this currently causes conflicts with the c++ scanner */
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy  (void)
+{
+    
+    /* Pop the buffer stack, destroying each element. */
+	while(YY_CURRENT_BUFFER){
+		yy_delete_buffer( YY_CURRENT_BUFFER  );
+		YY_CURRENT_BUFFER_LVALUE = NULL;
+		yypop_buffer_state();
+	}
+
+	/* Destroy the stack itself. */
+	yyfree((yy_buffer_stack) );
+	(yy_buffer_stack) = NULL;
+
+    /* Destroy the start condition stack. */
+        yyfree( (yy_start_stack)  );
+        (yy_start_stack) = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * yylex() is called, initialization will occur. */
+    yy_init_globals( );
+
+/* %if-reentrant */
+/* %endif */
+    return 0;
+}
+/* %endif */
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, const char * s2, int n )
+{
+		
+	int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (const char * s )
+{
+	int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+}
+#endif
+
+void *yyalloc (yy_size_t  size )
+{
+			return malloc(size);
+}
+
+void *yyrealloc  (void * ptr, yy_size_t  size )
+{
+		
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return realloc(ptr, size);
+}
+
+void yyfree (void * ptr )
+{
+			free( (char *) ptr );	/* see yyrealloc() for (char *) cast */
+}
+
+/* %if-tables-serialization definitions */
+/* %define-yytables   The name for this specific scanner's tables. */
+#define YYTABLES_NAME "yytables"
+/* %endif */
+
+/* %ok-for-header */
+
+#line 353 "lexer.l"
+
+	/*:509*/
+


Property changes on: trunk/Build/source/texk/web2c/hitexdir/hilexer.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Build/source/texk/web2c/hitexdir/hilexer.l
===================================================================
--- trunk/Build/source/texk/web2c/hitexdir/hilexer.l	                        (rev 0)
+++ trunk/Build/source/texk/web2c/hitexdir/hilexer.l	2021-11-12 11:09:17 UTC (rev 61033)
@@ -0,0 +1,353 @@
+	/*509:*/
+%{
+	#line 10171 "format.w"
+	
+#include "hibasetypes.h"
+#include "hierror.h"
+#include "hiformat.h"
+#include "hiput.h"
+
+	/*423:*/
+#ifdef DEBUG
+#define  YYDEBUG 1
+extern int yydebug;
+#else
+#define YYDEBUG 0
+#endif
+	/*:423*/
+#include "hiparser.h"
+
+	/*22:*/
+#define SCAN_UDEC(S) yylval.u= strtoul(S,NULL,10)
+	/*:22*/	/*25:*/
+#define SCAN_HEX(S) yylval.u= strtoul(S,NULL,16)
+	/*:25*/	/*28:*/
+#define SCAN_DEC(S) yylval.i= strtol(S,NULL,10)
+	/*:28*/	/*31:*/
+#define MAX_STR    (1<<10) 
+static char str_buffer[MAX_STR];
+static int str_length;
+#define STR_START      (str_length= 0)
+#define STR_PUT(C) (str_buffer[str_length++]= (C))
+#define STR_ADD(C) STR_PUT(C);RNG("String length",str_length,0,MAX_STR-1)
+#define STR_END        str_buffer[str_length]= 0
+#define SCAN_STR       yylval.s= str_buffer
+	/*:31*/	/*40:*/
+#define SCAN_UTF8_1(S)   yylval.u= ((S)[0]&0x7F)
+	/*:40*/	/*42:*/
+#define SCAN_UTF8_2(S)   yylval.u= (((S)[0]&0x1F)<<6)+((S)[1]&0x3F)
+	/*:42*/	/*44:*/
+#define SCAN_UTF8_3(S)   yylval.u= (((S)[0]&0x0F)<<12)+(((S)[1]&0x3F)<<6)+((S)[2]&0x3F)
+	/*:44*/	/*46:*/
+#define SCAN_UTF8_4(S)   yylval.u= (((S)[0]&0x03)<<18)+(((S)[1]&0x3F)<<12)+(((S)[2]&0x3F)<<6)+((S)[3]&0x3F)
+	/*:46*/	/*57:*/
+#define SCAN_DECFLOAT       yylval.f= atof(yytext)
+	/*:57*/	/*60:*/
+#define SCAN_HEXFLOAT       yylval.f= xtof(yytext)
+	/*:60*/	/*152:*/
+#define SCAN_REF(K) yylval.rf.k= K; yylval.rf.n= atoi(yytext+2)
+static int scan_level= 0;
+#define SCAN_START          yy_push_state(INITIAL);if (1==scan_level++) hpos0= hpos;
+#define SCAN_END            if (scan_level--) yy_pop_state(); else QUIT("Too many '>' in line %d",yylineno)
+#define SCAN_TXT_START      BEGIN(TXT)
+#define SCAN_TXT_END        BEGIN(INITIAL)
+	/*:152*/
+	/*61:*/
+
+float64_t xtof(char*x)
+{
+	#line 1369 "format.w"
+	int sign,digits,exp;
+	uint64_t mantissa= 0;
+	DBG(DBGFLOAT,"converting %s:\n",x);
+		/*62:*/
+	if(*x=='-'){sign= -1;x++;}
+	else if(*x=='+'){sign= +1;x++;}
+	else sign= +1;
+	DBG(DBGFLOAT,"\tsign=%d\n",sign);
+		/*:62*/
+	x= x+2;
+		/*63:*/
+	digits= 0;
+	while(*x=='0')x++;
+	while(*x!='.')
+	{mantissa= mantissa<<4;
+	if(*x<'A')mantissa= mantissa+*x-'0';
+	else mantissa= mantissa+*x-'A'+10;
+	x++;
+	digits++;
+	}
+	x++;
+	exp= 0;
+	while(*x!=0&&*x!='x')
+	{mantissa= mantissa<<4;
+	exp= exp-4;
+	if(*x<'A')mantissa= mantissa+*x-'0';
+	else mantissa= mantissa+*x-'A'+10;
+	x++;
+	digits++;
+	}
+	DBG(DBGFLOAT,"\tdigits=%d mantissa=0x%"PRIx64", exp=%d\n",digits,mantissa,exp);
+		/*:63*/
+		/*64:*/
+	if(mantissa==0)return 0.0;
+	{int s;
+	s= digits-DBL_M_BITS/4;
+	if(s>1)
+	mantissa= mantissa>>(4*(s-1));
+	else if(s<1)
+	mantissa= mantissa<<(4*(1-s));
+	exp= exp+4*(digits-1);
+	DBG(DBGFLOAT,"\tdigits=%d mantissa=0x%"PRIx64", exp=%d\n",digits,mantissa,exp);
+	while((mantissa>>DBL_M_BITS)>1){mantissa= mantissa>>1;exp++;}
+	DBG(DBGFLOAT,"\tdigits=%d mantissa=0x%"PRIx64", exp=%d\n",digits,mantissa,exp);
+	mantissa= mantissa&~((uint64_t)1<<DBL_M_BITS);
+	DBG(DBGFLOAT,"\tdigits=%d mantissa=0x%"PRIx64", exp=%d\n",digits,mantissa,exp);
+	}
+		/*:64*/
+		/*65:*/
+	if(*x=='x')
+	{int s;
+	x++;
+	if(*x=='-'){s= -1;x++;}
+	else if(*x=='+'){s= +1;x++;}
+	else s= +1;
+	DBG(DBGFLOAT,"\texpsign=%d\n",s);
+	DBG(DBGFLOAT,"\texp=%d\n",exp);
+	while(*x!=0)
+	{if(*x<'A')exp= exp+4*s*(*x-'0');
+	else exp= exp+4*s*(*x-'A'+10);
+	x++;
+	DBG(DBGFLOAT,"\texp=%d\n",exp);
+	}
+	}
+	RNG("Floating point exponent",exp,-DBL_EXCESS,DBL_EXCESS);
+		/*:65*/
+		/*66:*/
+	{union{float64_t d;uint64_t bits;}u;
+	if(sign<0)sign= 1;else sign= 0;
+	exp= exp+DBL_EXCESS;
+	u.bits= ((uint64_t)sign<<63)
+		|((uint64_t)exp<<DBL_M_BITS)	|mantissa;
+	DBG(DBGFLOAT," return %f\n",u.d);
+	return u.d;
+	}
+		/*:66*/
+	}
+	/*:61*/
+int yywrap(void){
+	#line 10182 "format.w"
+	return 1;}
+#ifdef _MSC_VER
+#pragma  warning( disable : 4267)
+#endif
+
+%}
+
+%option yylineno batch stack
+%option debug
+%option  nounistd nounput noinput noyy_top_state
+
+	/*23:*/
+HEX	[0-9A-F]
+	/*:23*/	/*32:*/
+%x STR
+	/*:32*/	/*39:*/
+UTF8_1	[\x00-\x7F]
+	/*:39*/	/*41:*/
+UTF8_2	[\xC0-\xDF][\x80-\xBF]
+	/*:41*/	/*43:*/
+UTF8_3	[\xE0-\xEF][\x80-\xBF][\x80-\xBF]
+	/*:43*/	/*45:*/
+UTF8_4	[\xF0-\xF7][\x80-\xBF][\x80-\xBF][\x80-\xBF]
+	/*:45*/	/*149:*/
+%x TXT
+	/*:149*/
+
+%%
+
+	/*3:*/
+"<"	SCAN_START;return START;
+">"	SCAN_END;return END;
+glyph	return GLYPH;
+0|[1-9][0-9]*	SCAN_UDEC(yytext);return UNSIGNED;
+\*(0|[1-9][0-9]*)	SCAN_UDEC(yytext+1);return REFERENCE;
+[[:space:]]	;
+\([^()\n]*[)\n]	;
+	/*:3*/	/*24:*/
+0x{HEX}+	SCAN_HEX(yytext+2);return UNSIGNED;
+	/*:24*/	/*27:*/
+[+-](0|[1-9][0-9]*)	SCAN_DEC(yytext);return SIGNED;
+	/*:27*/	/*34:*/
+'	STR_START;BEGIN(STR);
+<STR>{
+'	STR_END;SCAN_STR;BEGIN(INITIAL);return STRING;
+''	STR_ADD('\'');
+[\x20-\x7E]	STR_ADD(yytext[0]);
+.	RNG("String character",yytext[0],0x20,0x7E);
+\n	QUIT("Unterminated String in line %d",yylineno);
+}
+
+
+	/*:34*/	/*48:*/
+'''	STR_START;STR_PUT('\'');BEGIN(STR);
+''''	SCAN_UTF8_1(yytext+1);return CHARCODE;
+'[\x20-\x7E]''	STR_START;STR_PUT(yytext[1]);STR_PUT('\'');BEGIN(STR);
+'''''	STR_START;STR_PUT('\'');STR_PUT('\'');BEGIN(STR);
+'{UTF8_1}'	SCAN_UTF8_1(yytext+1);return CHARCODE;
+'{UTF8_2}'	SCAN_UTF8_2(yytext+1);return CHARCODE;
+'{UTF8_3}'	SCAN_UTF8_3(yytext+1);return CHARCODE;
+'{UTF8_4}'	SCAN_UTF8_4(yytext+1);return CHARCODE;
+	/*:48*/	/*55:*/
+[+-]?[0-9]+\.[0-9]+(e[+-]?[0-9])?	SCAN_DECFLOAT;return FPNUM;
+	/*:55*/	/*59:*/
+[+-]?0x{HEX}+\.{HEX}+(x[+-]?{HEX}+)?	SCAN_HEXFLOAT;return FPNUM;
+	/*:59*/	/*80:*/
+dimen	return DIMEN;
+pt	return PT;
+mm	return MM;
+in	return INCH;
+	/*:80*/	/*88:*/
+xdimen	return XDIMEN;
+h	return H;
+v	return V;
+	/*:88*/	/*99:*/
+fil	return FIL;
+fill	return FILL;
+filll	return FILLL;
+	/*:99*/	/*103:*/
+penalty	return PENALTY;
+int	return INTEGER;
+	/*:103*/	/*109:*/
+language	return LANGUAGE;
+	/*:109*/	/*115:*/
+rule	return RULE;
+"|"	return RUNNING;
+"_"	return RUNNING;
+	/*:115*/	/*124:*/
+kern	return KERN;
+!	return EXPLICIT;
+	/*:124*/	/*133:*/
+glue	return GLUE;
+plus	return PLUS;
+minus	return MINUS;
+	/*:133*/	/*151:*/
+\"	SCAN_TXT_START;return TXT_START;
+
+<TXT>{
+\"	SCAN_TXT_END;return TXT_END;
+
+"<"	SCAN_START;return START;
+">"	QUIT("> not allowed in text mode");
+
+\\\\	yylval.u= '\\';return TXT_CC;
+\\\"	yylval.u= '"';return TXT_CC;
+\\"<"	yylval.u= '<';return TXT_CC;
+\\">"	yylval.u= '>';return TXT_CC;
+\\" "	yylval.u= ' ';return TXT_CC;
+\\"-"	yylval.u= '-';return TXT_CC;
+\\"@"	return TXT_IGNORE;
+
+[ \t\r]*(\n[ \t\r]*)+	return TXT_FONT_GLUE;
+\\[ \t\r]*\n[ \t\r]*	;
+
+\\[0-7]	yylval.u= yytext[1]-'0';return TXT_FONT;
+
+\\F[0-9]+\\	SCAN_REF(font_kind);return TXT_GLOBAL;
+\\P[0-9]+\\	SCAN_REF(penalty_kind);return TXT_GLOBAL;
+\\K[0-9]+\\	SCAN_REF(kern_kind);return TXT_GLOBAL;
+\\L[0-9]+\\	SCAN_REF(ligature_kind);return TXT_GLOBAL;
+\\D[0-9]+\\	SCAN_REF(disc_kind);return TXT_GLOBAL;
+\\G[0-9]+\\	SCAN_REF(glue_kind);return TXT_GLOBAL;
+\\S[0-9]+\\	SCAN_REF(language_kind);return TXT_GLOBAL;
+\\R[0-9]+\\	SCAN_REF(rule_kind);return TXT_GLOBAL;
+\\I[0-9]+\\	SCAN_REF(image_kind);return TXT_GLOBAL;
+
+
+\\C[0-9]+\\	SCAN_UDEC(yytext+2);return TXT_CC;
+
+\\[a-l]	yylval.u= yytext[1]-'a';return TXT_LOCAL;
+" "	return TXT_FONT_GLUE;
+"-"	return TXT_FONT_HYPHEN;
+
+{UTF8_1}	SCAN_UTF8_1(yytext);return TXT_CC;
+{UTF8_2}	SCAN_UTF8_2(yytext);return TXT_CC;
+{UTF8_3}	SCAN_UTF8_3(yytext);return TXT_CC;
+{UTF8_4}	SCAN_UTF8_4(yytext);return TXT_CC;
+}
+	/*:151*/	/*162:*/
+hbox	return HBOX;
+vbox	return VBOX;
+shifted	return SHIFTED;
+	/*:162*/	/*170:*/
+hpack	return HPACK;
+hset	return HSET;
+vpack	return VPACK;
+vset	return VSET;
+add	return ADD;
+to	return TO;
+depth	return DEPTH;
+	/*:170*/	/*175:*/
+leaders	return LEADERS;
+align	return ALIGN;
+center	return CENTER;
+expand	return EXPAND;
+	/*:175*/	/*182:*/
+baseline	return BASELINE;
+	/*:182*/	/*189:*/
+ligature	return LIGATURE;
+	/*:189*/	/*197:*/
+disc	return DISC;
+	/*:197*/	/*205:*/
+par	return PAR;
+	/*:205*/	/*210:*/
+math	return MATH;
+	/*:210*/	/*215:*/
+on	return ON;
+off	return OFF;
+	/*:215*/	/*219:*/
+adjust	return ADJUST;
+	/*:219*/	/*223:*/
+table	return TABLE;
+item	return ITEM;
+row	return ITEM;
+column	return ITEM;
+	/*:223*/	/*230:*/
+image	return IMAGE;
+	/*:230*/	/*247:*/
+label	return LABEL;
+bot	return BOT;
+mid	return MID;
+	/*:247*/	/*261:*/
+link	return LINK;
+	/*:261*/	/*271:*/
+outline	return OUTLINE;
+	/*:271*/	/*278:*/
+stream	if(section_no==1)return STREAMDEF;else return STREAM;
+first	return FIRST;
+last	return LAST;
+top	return TOP;
+\*	return NOREFERENCE;
+	/*:278*/	/*288:*/
+page	return PAGE;
+	/*:288*/	/*296:*/
+range	return RANGE;
+	/*:296*/	/*323:*/
+directory	return DIRECTORY;
+section	return SECTION;
+	/*:323*/	/*342:*/
+definitions	return DEFINITIONS;
+	/*:342*/	/*350:*/
+max	return MAX;
+	/*:350*/	/*365:*/
+param	return PARAM;
+	/*:365*/	/*374:*/
+font	return FONT;
+	/*:374*/	/*402:*/
+content	return CONTENT;
+	/*:402*/
+[a-z]+	QUIT("Unexpected keyword '%s' in line %d",yytext,yylineno);
+.	QUIT("Unexpected character '%c' (0x%02X) in line %d",yytext[0]>' '?yytext[0]:' ',yytext[0],yylineno);
+
+%%
+	/*:509*/


Property changes on: trunk/Build/source/texk/web2c/hitexdir/hilexer.l
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Build/source/texk/web2c/hitexdir/hiparser.c
===================================================================
--- trunk/Build/source/texk/web2c/hitexdir/hiparser.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/hitexdir/hiparser.c	2021-11-12 11:09:17 UTC (rev 61033)
@@ -0,0 +1,4132 @@
+/* A Bison parser, made by GNU Bison 3.8.2.  */
+
+/* Bison implementation for Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation,
+   Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+   especially those whose name start with YY_ or yy_.  They are
+   private implementation details that can be changed or removed.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output, and Bison version.  */
+#define YYBISON 30802
+
+/* Bison version string.  */
+#define YYBISON_VERSION "3.8.2"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 0
+
+/* Push parsers.  */
+#define YYPUSH 0
+
+/* Pull parsers.  */
+#define YYPULL 1
+
+
+
+
+/* First part of user prologue.  */
+#line 2 "parser.y"
+
+	#line 10212 "format.w"
+	
+#include "hibasetypes.h"
+#include <string.h>
+#include <math.h>
+#include "hierror.h"
+#include "hiformat.h"
+#include "hiput.h"
+extern char**hfont_name;
+
+	/*356:*/
+uint32_t definition_bits[0x100/32][32]= {
+	#line 7578 "format.w"
+	{0}};
+
+#define SET_DBIT(N,K) ((N)>0xFF?1:(definition_bits[N/32][K]	|= (1<<((N)&(32-1)))))
+#define GET_DBIT(N,K) ((N)>0xFF?1:((definition_bits[N/32][K]>>((N)&(32-1)))&1))
+#define DEF(D,K,N) (D).k= K; (D).n= (N);SET_DBIT((D).n,(D).k);\
+ DBG(DBGDEF,"Defining %s %d\n",definition_name[(D).k],(D).n);\
+ RNG("Definition",(D).n,max_fixed[(D).k]+1,max_ref[(D).k]);
+#define REF(K,N) REF_RNG(K,N);if(!GET_DBIT(N,K)) \
+ QUIT("Reference %d to %s before definition",(N),definition_name[K])
+	/*:356*/	/*360:*/
+#define DEF_REF(D,K,M,N)  DEF(D,K,M);\
+if ((M)>max_default[K]) QUIT("Defining non default reference %d for %s",M,definition_name[K]); \
+if ((N)>max_fixed[K]) QUIT("Defining reference %d for %s by non fixed reference %d",M,definition_name[K],N);
+	/*:360*/
+
+extern void hset_entry(entry_t*e,uint16_t i,uint32_t size,
+uint32_t xsize,char*file_name);
+
+	/*423:*/
+#ifdef DEBUG
+#define  YYDEBUG 1
+extern int yydebug;
+#else
+#define YYDEBUG 0
+#endif
+	/*:423*/
+extern int yylex(void);
+
+	/*352:*/
+void hset_max(kind_t k,int n)
+{
+	#line 7421 "format.w"
+	DBG(DBGDEF,"Setting max %s to %d\n",definition_name[k],n);
+	RNG("Maximum",n,max_fixed[k]+1,MAX_REF(k));
+	if(n>max_ref[k])
+	max_ref[k]= n;
+	}
+	/*:352*/	/*363:*/
+void check_param_def(ref_t*df)
+{
+	#line 7727 "format.w"
+	if(df->k!=int_kind&&df->k!=dimen_kind&&df->k!=glue_kind)
+	QUIT("Kind %s not allowed in parameter list",definition_name[df->k]);
+	if(df->n<=max_fixed[df->k]||max_default[df->k]<df->n)
+	QUIT("Parameter %d for %s not allowed in parameter list",df->n,definition_name[df->k]);
+	}
+	/*:363*/	/*422:*/
+extern int yylineno;
+int yyerror(const char*msg)
+{
+	#line 8799 "format.w"
+	QUIT(" in line %d %s",yylineno,msg);
+	return 0;
+	}
+	/*:422*/
+
+
+
+#line 144 "parser.c"
+
+# ifndef YY_CAST
+#  ifdef __cplusplus
+#   define YY_CAST(Type, Val) static_cast<Type> (Val)
+#   define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast<Type> (Val)
+#  else
+#   define YY_CAST(Type, Val) ((Type) (Val))
+#   define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val))
+#  endif
+# endif
+# ifndef YY_NULLPTR
+#  if defined __cplusplus
+#   if 201103L <= __cplusplus
+#    define YY_NULLPTR nullptr
+#   else
+#    define YY_NULLPTR 0
+#   endif
+#  else
+#   define YY_NULLPTR ((void*)0)
+#  endif
+# endif
+
+#include "hiparser.h"
+/* Symbol kind.  */
+enum yysymbol_kind_t
+{
+  YYSYMBOL_YYEMPTY = -2,
+  YYSYMBOL_YYEOF = 0,                      /* "end of file"  */
+  YYSYMBOL_YYerror = 1,                    /* error  */
+  YYSYMBOL_YYUNDEF = 2,                    /* "invalid token"  */
+  YYSYMBOL_START = 3,                      /* "<"  */
+  YYSYMBOL_END = 4,                        /* ">"  */
+  YYSYMBOL_GLYPH = 5,                      /* "glyph"  */
+  YYSYMBOL_UNSIGNED = 6,                   /* UNSIGNED  */
+  YYSYMBOL_REFERENCE = 7,                  /* REFERENCE  */
+  YYSYMBOL_SIGNED = 8,                     /* SIGNED  */
+  YYSYMBOL_STRING = 9,                     /* STRING  */
+  YYSYMBOL_CHARCODE = 10,                  /* CHARCODE  */
+  YYSYMBOL_FPNUM = 11,                     /* FPNUM  */
+  YYSYMBOL_DIMEN = 12,                     /* "dimen"  */
+  YYSYMBOL_PT = 13,                        /* "pt"  */
+  YYSYMBOL_MM = 14,                        /* "mm"  */
+  YYSYMBOL_INCH = 15,                      /* "in"  */
+  YYSYMBOL_XDIMEN = 16,                    /* "xdimen"  */
+  YYSYMBOL_H = 17,                         /* "h"  */
+  YYSYMBOL_V = 18,                         /* "v"  */
+  YYSYMBOL_FIL = 19,                       /* "fil"  */
+  YYSYMBOL_FILL = 20,                      /* "fill"  */
+  YYSYMBOL_FILLL = 21,                     /* "filll"  */
+  YYSYMBOL_PENALTY = 22,                   /* "penalty"  */
+  YYSYMBOL_INTEGER = 23,                   /* "int"  */
+  YYSYMBOL_LANGUAGE = 24,                  /* "language"  */
+  YYSYMBOL_RULE = 25,                      /* "rule"  */
+  YYSYMBOL_RUNNING = 26,                   /* "|"  */
+  YYSYMBOL_KERN = 27,                      /* "kern"  */
+  YYSYMBOL_EXPLICIT = 28,                  /* "!"  */
+  YYSYMBOL_GLUE = 29,                      /* "glue"  */
+  YYSYMBOL_PLUS = 30,                      /* "plus"  */
+  YYSYMBOL_MINUS = 31,                     /* "minus"  */
+  YYSYMBOL_TXT_START = 32,                 /* TXT_START  */
+  YYSYMBOL_TXT_END = 33,                   /* TXT_END  */
+  YYSYMBOL_TXT_IGNORE = 34,                /* TXT_IGNORE  */
+  YYSYMBOL_TXT_FONT_GLUE = 35,             /* TXT_FONT_GLUE  */
+  YYSYMBOL_TXT_FONT_HYPHEN = 36,           /* TXT_FONT_HYPHEN  */
+  YYSYMBOL_TXT_FONT = 37,                  /* TXT_FONT  */
+  YYSYMBOL_TXT_LOCAL = 38,                 /* TXT_LOCAL  */
+  YYSYMBOL_TXT_GLOBAL = 39,                /* TXT_GLOBAL  */
+  YYSYMBOL_TXT_CC = 40,                    /* TXT_CC  */
+  YYSYMBOL_HBOX = 41,                      /* "hbox"  */
+  YYSYMBOL_VBOX = 42,                      /* "vbox"  */
+  YYSYMBOL_SHIFTED = 43,                   /* "shifted"  */
+  YYSYMBOL_HPACK = 44,                     /* "hpack"  */
+  YYSYMBOL_HSET = 45,                      /* "hset"  */
+  YYSYMBOL_VPACK = 46,                     /* "vpack"  */
+  YYSYMBOL_VSET = 47,                      /* "vset"  */
+  YYSYMBOL_DEPTH = 48,                     /* "depth"  */
+  YYSYMBOL_ADD = 49,                       /* "add"  */
+  YYSYMBOL_TO = 50,                        /* "to"  */
+  YYSYMBOL_LEADERS = 51,                   /* "leaders"  */
+  YYSYMBOL_ALIGN = 52,                     /* "align"  */
+  YYSYMBOL_CENTER = 53,                    /* "center"  */
+  YYSYMBOL_EXPAND = 54,                    /* "expand"  */
+  YYSYMBOL_BASELINE = 55,                  /* "baseline"  */
+  YYSYMBOL_LIGATURE = 56,                  /* "ligature"  */
+  YYSYMBOL_DISC = 57,                      /* "disc"  */
+  YYSYMBOL_PAR = 58,                       /* "par"  */
+  YYSYMBOL_MATH = 59,                      /* "math"  */
+  YYSYMBOL_ON = 60,                        /* "on"  */
+  YYSYMBOL_OFF = 61,                       /* "off"  */
+  YYSYMBOL_ADJUST = 62,                    /* "adjust"  */
+  YYSYMBOL_TABLE = 63,                     /* "table"  */
+  YYSYMBOL_ITEM = 64,                      /* "item"  */
+  YYSYMBOL_IMAGE = 65,                     /* "image"  */
+  YYSYMBOL_LABEL = 66,                     /* "label"  */
+  YYSYMBOL_BOT = 67,                       /* "bot"  */
+  YYSYMBOL_MID = 68,                       /* "mid"  */
+  YYSYMBOL_LINK = 69,                      /* "link"  */
+  YYSYMBOL_OUTLINE = 70,                   /* "outline"  */
+  YYSYMBOL_STREAM = 71,                    /* "stream"  */
+  YYSYMBOL_STREAMDEF = 72,                 /* "stream (definition)"  */
+  YYSYMBOL_FIRST = 73,                     /* "first"  */
+  YYSYMBOL_LAST = 74,                      /* "last"  */
+  YYSYMBOL_TOP = 75,                       /* "top"  */
+  YYSYMBOL_NOREFERENCE = 76,               /* "*"  */
+  YYSYMBOL_PAGE = 77,                      /* "page"  */
+  YYSYMBOL_RANGE = 78,                     /* "range"  */
+  YYSYMBOL_DIRECTORY = 79,                 /* "directory"  */
+  YYSYMBOL_SECTION = 80,                   /* "entry"  */
+  YYSYMBOL_DEFINITIONS = 81,               /* "definitions"  */
+  YYSYMBOL_MAX = 82,                       /* "max"  */
+  YYSYMBOL_PARAM = 83,                     /* "param"  */
+  YYSYMBOL_FONT = 84,                      /* "font"  */
+  YYSYMBOL_CONTENT = 85,                   /* "content"  */
+  YYSYMBOL_YYACCEPT = 86,                  /* $accept  */
+  YYSYMBOL_glyph = 87,                     /* glyph  */
+  YYSYMBOL_content_node = 88,              /* content_node  */
+  YYSYMBOL_start = 89,                     /* start  */
+  YYSYMBOL_integer = 90,                   /* integer  */
+  YYSYMBOL_string = 91,                    /* string  */
+  YYSYMBOL_number = 92,                    /* number  */
+  YYSYMBOL_dimension = 93,                 /* dimension  */
+  YYSYMBOL_xdimen = 94,                    /* xdimen  */
+  YYSYMBOL_xdimen_node = 95,               /* xdimen_node  */
+  YYSYMBOL_order = 96,                     /* order  */
+  YYSYMBOL_stretch = 97,                   /* stretch  */
+  YYSYMBOL_penalty = 98,                   /* penalty  */
+  YYSYMBOL_rule_dimension = 99,            /* rule_dimension  */
+  YYSYMBOL_rule = 100,                     /* rule  */
+  YYSYMBOL_rule_node = 101,                /* rule_node  */
+  YYSYMBOL_explicit = 102,                 /* explicit  */
+  YYSYMBOL_kern = 103,                     /* kern  */
+  YYSYMBOL_plus = 104,                     /* plus  */
+  YYSYMBOL_minus = 105,                    /* minus  */
+  YYSYMBOL_glue = 106,                     /* glue  */
+  YYSYMBOL_glue_node = 107,                /* glue_node  */
+  YYSYMBOL_position = 108,                 /* position  */
+  YYSYMBOL_content_list = 109,             /* content_list  */
+  YYSYMBOL_estimate = 110,                 /* estimate  */
+  YYSYMBOL_list = 111,                     /* list  */
+  YYSYMBOL_112_1 = 112,                    /* $@1  */
+  YYSYMBOL_text = 113,                     /* text  */
+  YYSYMBOL_txt = 114,                      /* txt  */
+  YYSYMBOL_115_2 = 115,                    /* $@2  */
+  YYSYMBOL_box_dimen = 116,                /* box_dimen  */
+  YYSYMBOL_box_shift = 117,                /* box_shift  */
+  YYSYMBOL_box_glue_set = 118,             /* box_glue_set  */
+  YYSYMBOL_box = 119,                      /* box  */
+  YYSYMBOL_hbox_node = 120,                /* hbox_node  */
+  YYSYMBOL_vbox_node = 121,                /* vbox_node  */
+  YYSYMBOL_box_flex = 122,                 /* box_flex  */
+  YYSYMBOL_xbox = 123,                     /* xbox  */
+  YYSYMBOL_box_goal = 124,                 /* box_goal  */
+  YYSYMBOL_hpack = 125,                    /* hpack  */
+  YYSYMBOL_vpack = 126,                    /* vpack  */
+  YYSYMBOL_127_3 = 127,                    /* $@3  */
+  YYSYMBOL_vxbox_node = 128,               /* vxbox_node  */
+  YYSYMBOL_hxbox_node = 129,               /* hxbox_node  */
+  YYSYMBOL_ltype = 130,                    /* ltype  */
+  YYSYMBOL_leaders = 131,                  /* leaders  */
+  YYSYMBOL_baseline = 132,                 /* baseline  */
+  YYSYMBOL_133_4 = 133,                    /* $@4  */
+  YYSYMBOL_cc_list = 134,                  /* cc_list  */
+  YYSYMBOL_lig_cc = 135,                   /* lig_cc  */
+  YYSYMBOL_ref = 136,                      /* ref  */
+  YYSYMBOL_ligature = 137,                 /* ligature  */
+  YYSYMBOL_138_5 = 138,                    /* $@5  */
+  YYSYMBOL_replace_count = 139,            /* replace_count  */
+  YYSYMBOL_disc = 140,                     /* disc  */
+  YYSYMBOL_disc_node = 141,                /* disc_node  */
+  YYSYMBOL_par_dimen = 142,                /* par_dimen  */
+  YYSYMBOL_par = 143,                      /* par  */
+  YYSYMBOL_144_6 = 144,                    /* $@6  */
+  YYSYMBOL_math = 145,                     /* math  */
+  YYSYMBOL_on_off = 146,                   /* on_off  */
+  YYSYMBOL_span_count = 147,               /* span_count  */
+  YYSYMBOL_table = 148,                    /* table  */
+  YYSYMBOL_image_dimen = 149,              /* image_dimen  */
+  YYSYMBOL_image = 150,                    /* image  */
+  YYSYMBOL_max_value = 151,                /* max_value  */
+  YYSYMBOL_placement = 152,                /* placement  */
+  YYSYMBOL_def_node = 153,                 /* def_node  */
+  YYSYMBOL_stream_link = 154,              /* stream_link  */
+  YYSYMBOL_stream_split = 155,             /* stream_split  */
+  YYSYMBOL_stream_info = 156,              /* stream_info  */
+  YYSYMBOL_157_7 = 157,                    /* $@7  */
+  YYSYMBOL_stream_type = 158,              /* stream_type  */
+  YYSYMBOL_stream_def_node = 159,          /* stream_def_node  */
+  YYSYMBOL_stream_ins_node = 160,          /* stream_ins_node  */
+  YYSYMBOL_stream = 161,                   /* stream  */
+  YYSYMBOL_page_priority = 162,            /* page_priority  */
+  YYSYMBOL_stream_def_list = 163,          /* stream_def_list  */
+  YYSYMBOL_page = 164,                     /* page  */
+  YYSYMBOL_165_8 = 165,                    /* $@8  */
+  YYSYMBOL_166_9 = 166,                    /* $@9  */
+  YYSYMBOL_hint = 167,                     /* hint  */
+  YYSYMBOL_directory_section = 168,        /* directory_section  */
+  YYSYMBOL_169_10 = 169,                   /* $@10  */
+  YYSYMBOL_entry_list = 170,               /* entry_list  */
+  YYSYMBOL_entry = 171,                    /* entry  */
+  YYSYMBOL_definition_section = 172,       /* definition_section  */
+  YYSYMBOL_173_11 = 173,                   /* $@11  */
+  YYSYMBOL_definition_list = 174,          /* definition_list  */
+  YYSYMBOL_max_definitions = 175,          /* max_definitions  */
+  YYSYMBOL_max_list = 176,                 /* max_list  */
+  YYSYMBOL_def_list = 177,                 /* def_list  */
+  YYSYMBOL_parameters = 178,               /* parameters  */
+  YYSYMBOL_empty_param_list = 179,         /* empty_param_list  */
+  YYSYMBOL_non_empty_param_list = 180,     /* non_empty_param_list  */
+  YYSYMBOL_181_12 = 181,                   /* $@12  */
+  YYSYMBOL_font = 182,                     /* font  */
+  YYSYMBOL_font_head = 183,                /* font_head  */
+  YYSYMBOL_font_param_list = 184,          /* font_param_list  */
+  YYSYMBOL_font_param = 185,               /* font_param  */
+  YYSYMBOL_fref = 186,                     /* fref  */
+  YYSYMBOL_xdimen_ref = 187,               /* xdimen_ref  */
+  YYSYMBOL_param_ref = 188,                /* param_ref  */
+  YYSYMBOL_stream_ref = 189,               /* stream_ref  */
+  YYSYMBOL_content_section = 190,          /* content_section  */
+  YYSYMBOL_191_13 = 191                    /* $@13  */
+};
+typedef enum yysymbol_kind_t yysymbol_kind_t;
+
+
+
+
+#ifdef short
+# undef short
+#endif
+
+/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure
+   <limits.h> and (if available) <stdint.h> are included
+   so that the code can choose integer types of a good width.  */
+
+#ifndef __PTRDIFF_MAX__
+# include <limits.h> /* INFRINGES ON USER NAME SPACE */
+# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
+#  include <stdint.h> /* INFRINGES ON USER NAME SPACE */
+#  define YY_STDINT_H
+# endif
+#endif
+
+/* Narrow types that promote to a signed type and that can represent a
+   signed or unsigned integer of at least N bits.  In tables they can
+   save space and decrease cache pressure.  Promoting to a signed type
+   helps avoid bugs in integer arithmetic.  */
+
+#ifdef __INT_LEAST8_MAX__
+typedef __INT_LEAST8_TYPE__ yytype_int8;
+#elif defined YY_STDINT_H
+typedef int_least8_t yytype_int8;
+#else
+typedef signed char yytype_int8;
+#endif
+
+#ifdef __INT_LEAST16_MAX__
+typedef __INT_LEAST16_TYPE__ yytype_int16;
+#elif defined YY_STDINT_H
+typedef int_least16_t yytype_int16;
+#else
+typedef short yytype_int16;
+#endif
+
+/* Work around bug in HP-UX 11.23, which defines these macros
+   incorrectly for preprocessor constants.  This workaround can likely
+   be removed in 2023, as HPE has promised support for HP-UX 11.23
+   (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of
+   <https://h20195.www2.hpe.com/V2/getpdf.aspx/4AA4-7673ENW.pdf>.  */
+#ifdef __hpux
+# undef UINT_LEAST8_MAX
+# undef UINT_LEAST16_MAX
+# define UINT_LEAST8_MAX 255
+# define UINT_LEAST16_MAX 65535
+#endif
+
+#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__
+typedef __UINT_LEAST8_TYPE__ yytype_uint8;
+#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \
+       && UINT_LEAST8_MAX <= INT_MAX)
+typedef uint_least8_t yytype_uint8;
+#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX
+typedef unsigned char yytype_uint8;
+#else
+typedef short yytype_uint8;
+#endif
+
+#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__
+typedef __UINT_LEAST16_TYPE__ yytype_uint16;
+#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \
+       && UINT_LEAST16_MAX <= INT_MAX)
+typedef uint_least16_t yytype_uint16;
+#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX
+typedef unsigned short yytype_uint16;
+#else
+typedef int yytype_uint16;
+#endif
+
+#ifndef YYPTRDIFF_T
+# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__
+#  define YYPTRDIFF_T __PTRDIFF_TYPE__
+#  define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__
+# elif defined PTRDIFF_MAX
+#  ifndef ptrdiff_t
+#   include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  endif
+#  define YYPTRDIFF_T ptrdiff_t
+#  define YYPTRDIFF_MAXIMUM PTRDIFF_MAX
+# else
+#  define YYPTRDIFF_T long
+#  define YYPTRDIFF_MAXIMUM LONG_MAX
+# endif
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM                                  \
+  YY_CAST (YYPTRDIFF_T,                                 \
+           (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1)  \
+            ? YYPTRDIFF_MAXIMUM                         \
+            : YY_CAST (YYSIZE_T, -1)))
+
+#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X))
+
+
+/* Stored state numbers (used for stacks). */
+typedef yytype_int16 yy_state_t;
+
+/* State numbers in computations.  */
+typedef int yy_state_fast_t;
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(Msgid) Msgid
+# endif
+#endif
+
+
+#ifndef YY_ATTRIBUTE_PURE
+# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__)
+#  define YY_ATTRIBUTE_PURE __attribute__ ((__pure__))
+# else
+#  define YY_ATTRIBUTE_PURE
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE_UNUSED
+# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__)
+#  define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+# else
+#  define YY_ATTRIBUTE_UNUSED
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YY_USE(E) ((void) (E))
+#else
+# define YY_USE(E) /* empty */
+#endif
+
+/* Suppress an incorrect diagnostic about yylval being uninitialized.  */
+#if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__
+# if __GNUC__ * 100 + __GNUC_MINOR__ < 407
+#  define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN                           \
+    _Pragma ("GCC diagnostic push")                                     \
+    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")
+# else
+#  define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN                           \
+    _Pragma ("GCC diagnostic push")                                     \
+    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")              \
+    _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# endif
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END      \
+    _Pragma ("GCC diagnostic pop")
+#else
+# define YY_INITIAL_VALUE(Value) Value
+#endif
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
+#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__
+# define YY_IGNORE_USELESS_CAST_BEGIN                          \
+    _Pragma ("GCC diagnostic push")                            \
+    _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"")
+# define YY_IGNORE_USELESS_CAST_END            \
+    _Pragma ("GCC diagnostic pop")
+#endif
+#ifndef YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_END
+#endif
+
+
+#define YY_ASSERT(E) ((void) (0 && (E)))
+
+#if 1
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+      /* Use EXIT_SUCCESS as a witness for stdlib.h.  */
+#     ifndef EXIT_SUCCESS
+#      define EXIT_SUCCESS 0
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's 'empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined EXIT_SUCCESS \
+       && ! ((defined YYMALLOC || defined malloc) \
+             && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef EXIT_SUCCESS
+#    define EXIT_SUCCESS 0
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if ! defined malloc && ! defined EXIT_SUCCESS
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if ! defined free && ! defined EXIT_SUCCESS
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* 1 */
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+         || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  yy_state_t yyss_alloc;
+  YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \
+      + YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack)                           \
+    do                                                                  \
+      {                                                                 \
+        YYPTRDIFF_T yynewbytes;                                         \
+        YYCOPY (&yyptr->Stack_alloc, Stack, yysize);                    \
+        Stack = &yyptr->Stack_alloc;                                    \
+        yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \
+        yyptr += yynewbytes / YYSIZEOF (*yyptr);                        \
+      }                                                                 \
+    while (0)
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(Dst, Src, Count) \
+      __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src)))
+#  else
+#   define YYCOPY(Dst, Src, Count)              \
+      do                                        \
+        {                                       \
+          YYPTRDIFF_T yyi;                      \
+          for (yyi = 0; yyi < (Count); yyi++)   \
+            (Dst)[yyi] = (Src)[yyi];            \
+        }                                       \
+      while (0)
+#  endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  5
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   657
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  86
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  106
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  266
+/* YYNSTATES -- Number of states.  */
+#define YYNSTATES  566
+
+/* YYMAXUTOK -- Last valid token kind.  */
+#define YYMAXUTOK   340
+
+
+/* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM
+   as returned by yylex, with out-of-bounds checking.  */
+#define YYTRANSLATE(YYX)                                \
+  (0 <= (YYX) && (YYX) <= YYMAXUTOK                     \
+   ? YY_CAST (yysymbol_kind_t, yytranslate[YYX])        \
+   : YYSYMBOL_YYUNDEF)
+
+/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
+   as returned by yylex.  */
+static const yytype_int8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
+      35,    36,    37,    38,    39,    40,    41,    42,    43,    44,
+      45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
+      55,    56,    57,    58,    59,    60,    61,    62,    63,    64,
+      65,    66,    67,    68,    69,    70,    71,    72,    73,    74,
+      75,    76,    77,    78,    79,    80,    81,    82,    83,    84,
+      85
+};
+
+#if YYDEBUG
+/* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
+static const yytype_int16 yyrline[] =
+{
+       0,   264,   264,   267,   270,   274,   274,   278,   282,   282,
+     288,   290,   292,   294,   297,   300,   304,   307,   310,   313,
+     319,   324,   326,   328,   330,   334,   338,   341,   345,   345,
+     348,   354,   357,   359,   361,   364,   367,   371,   373,   376,
+     378,   381,   384,   388,   394,   397,   398,   399,   402,   405,
+     412,   411,   420,   420,   422,   425,   428,   431,   434,   437,
+     440,   443,   443,   448,   452,   455,   459,   462,   465,   470,
+     474,   477,   480,   480,   482,   485,   488,   492,   495,   498,
+     501,   505,   508,   508,   514,   517,   522,   525,   529,   529,
+     531,   533,   535,   537,   540,   543,   546,   549,   553,   553,
+     562,   567,   567,   570,   573,   576,   579,   579,   586,   590,
+     593,   597,   601,   604,   609,   614,   616,   619,   622,   625,
+     628,   628,   633,   636,   640,   644,   647,   650,   653,   656,
+     659,   662,   665,   668,   672,   676,   678,   681,   685,   689,
+     692,   695,   698,   702,   705,   709,   713,   715,   718,   721,
+     725,   732,   734,   736,   738,   741,   746,   751,   761,   763,
+     766,   769,   769,   773,   775,   777,   779,   783,   789,   794,
+     794,   796,   799,   802,   805,   810,   813,   817,   817,   819,
+     821,   819,   828,   831,   835,   837,   837,   840,   840,   841,
+     846,   846,   853,   853,   855,   880,   880,   882,   885,   888,
+     891,   894,   897,   900,   903,   906,   909,   912,   915,   918,
+     921,   924,   927,   930,   936,   939,   942,   945,   948,   951,
+     954,   957,   960,   963,   966,   969,   972,   975,   980,   983,
+     986,   990,   991,   994,   998,  1001,  1001,  1009,  1011,  1016,
+    1016,  1019,  1022,  1025,  1028,  1031,  1034,  1037,  1040,  1044,
+    1048,  1051,  1054,  1060,  1063,  1067,  1071,  1074,  1077,  1080,
+    1083,  1086,  1089,  1092,  1096,  1103,  1103
+};
+#endif
+
+/** Accessing symbol of state STATE.  */
+#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State])
+
+#if 1
+/* The user-facing name of the symbol whose (internal) number is
+   YYSYMBOL.  No bounds checking.  */
+static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED;
+
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "\"end of file\"", "error", "\"invalid token\"", "\"<\"", "\">\"",
+  "\"glyph\"", "UNSIGNED", "REFERENCE", "SIGNED", "STRING", "CHARCODE",
+  "FPNUM", "\"dimen\"", "\"pt\"", "\"mm\"", "\"in\"", "\"xdimen\"",
+  "\"h\"", "\"v\"", "\"fil\"", "\"fill\"", "\"filll\"", "\"penalty\"",
+  "\"int\"", "\"language\"", "\"rule\"", "\"|\"", "\"kern\"", "\"!\"",
+  "\"glue\"", "\"plus\"", "\"minus\"", "TXT_START", "TXT_END",
+  "TXT_IGNORE", "TXT_FONT_GLUE", "TXT_FONT_HYPHEN", "TXT_FONT",
+  "TXT_LOCAL", "TXT_GLOBAL", "TXT_CC", "\"hbox\"", "\"vbox\"",
+  "\"shifted\"", "\"hpack\"", "\"hset\"", "\"vpack\"", "\"vset\"",
+  "\"depth\"", "\"add\"", "\"to\"", "\"leaders\"", "\"align\"",
+  "\"center\"", "\"expand\"", "\"baseline\"", "\"ligature\"", "\"disc\"",
+  "\"par\"", "\"math\"", "\"on\"", "\"off\"", "\"adjust\"", "\"table\"",
+  "\"item\"", "\"image\"", "\"label\"", "\"bot\"", "\"mid\"", "\"link\"",
+  "\"outline\"", "\"stream\"", "\"stream (definition)\"", "\"first\"",
+  "\"last\"", "\"top\"", "\"*\"", "\"page\"", "\"range\"", "\"directory\"",
+  "\"entry\"", "\"definitions\"", "\"max\"", "\"param\"", "\"font\"",
+  "\"content\"", "$accept", "glyph", "content_node", "start", "integer",
+  "string", "number", "dimension", "xdimen", "xdimen_node", "order",
+  "stretch", "penalty", "rule_dimension", "rule", "rule_node", "explicit",
+  "kern", "plus", "minus", "glue", "glue_node", "position", "content_list",
+  "estimate", "list", "$@1", "text", "txt", "$@2", "box_dimen",
+  "box_shift", "box_glue_set", "box", "hbox_node", "vbox_node", "box_flex",
+  "xbox", "box_goal", "hpack", "vpack", "$@3", "vxbox_node", "hxbox_node",
+  "ltype", "leaders", "baseline", "$@4", "cc_list", "lig_cc", "ref",
+  "ligature", "$@5", "replace_count", "disc", "disc_node", "par_dimen",
+  "par", "$@6", "math", "on_off", "span_count", "table", "image_dimen",
+  "image", "max_value", "placement", "def_node", "stream_link",
+  "stream_split", "stream_info", "$@7", "stream_type", "stream_def_node",
+  "stream_ins_node", "stream", "page_priority", "stream_def_list", "page",
+  "$@8", "$@9", "hint", "directory_section", "$@10", "entry_list", "entry",
+  "definition_section", "$@11", "definition_list", "max_definitions",
+  "max_list", "def_list", "parameters", "empty_param_list",
+  "non_empty_param_list", "$@12", "font", "font_head", "font_param_list",
+  "font_param", "fref", "xdimen_ref", "param_ref", "stream_ref",
+  "content_section", "$@13", YY_NULLPTR
+};
+
+static const char *
+yysymbol_name (yysymbol_kind_t yysymbol)
+{
+  return yytname[yysymbol];
+}
+#endif
+
+#define YYPACT_NINF (-326)
+
+#define yypact_value_is_default(Yyn) \
+  ((Yyn) == YYPACT_NINF)
+
+#define YYTABLE_NINF (-1)
+
+#define yytable_value_is_error(Yyn) \
+  0
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+static const yytype_int16 yypact[] =
+{
+      48,    -4,   110,   113,   107,  -326,    52,   137,  -326,  -326,
+      74,  -326,  -326,   153,  -326,   211,    85,  -326,  -326,    94,
+    -326,  -326,  -326,   275,  -326,   278,   190,   280,   159,  -326,
+     313,  -326,    31,  -326,  -326,   585,  -326,  -326,  -326,  -326,
+    -326,  -326,  -326,  -326,   223,   467,  -326,   203,   234,   234,
+     234,   234,   234,   234,   234,   234,   234,   234,   234,   234,
+     234,   234,   240,   248,   116,   219,   253,   140,   210,   229,
+     182,   182,   220,   182,   220,   182,   121,   229,   234,    71,
+     229,    41,    66,   271,    79,   301,   261,   234,   234,  -326,
+    -326,   268,   270,   279,   284,   286,   288,   294,   297,   315,
+     325,   326,   327,   328,   333,   334,   335,   337,   338,   339,
+     343,   242,  -326,   229,   182,   219,   223,   152,   229,   345,
+     182,   234,   210,   348,   223,   350,   223,    82,   251,   323,
+     342,   353,  -326,  -326,  -326,   355,   357,   358,  -326,  -326,
+    -326,  -326,   231,  -326,   152,   359,   361,  -326,   165,   362,
+     182,   341,   372,   373,   182,   220,   375,   377,   182,   264,
+     379,   220,   380,   305,   384,   385,  -326,   363,   200,   387,
+     389,  -326,   390,   391,   395,   396,   398,   397,    66,   401,
+     234,  -326,  -326,   404,   234,  -326,  -326,  -326,  -326,   405,
+    -326,    66,    66,  -326,   350,   406,   264,   264,   407,  -326,
+     408,   530,   409,   399,   182,   410,   411,   255,  -326,   234,
+      80,  -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,
+    -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,
+    -326,  -326,   413,   414,   416,   417,   418,   419,   421,   422,
+     423,   427,   429,  -326,   430,   432,   433,  -326,   435,  -326,
+    -326,   436,   182,   437,   345,  -326,  -326,  -326,   438,   440,
+     441,  -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,
+     152,  -326,  -326,   234,  -326,   442,  -326,   302,   182,   420,
+    -326,  -326,   182,   293,  -326,  -326,  -326,   121,   121,    66,
+    -326,   341,  -326,   400,  -326,  -326,   229,  -326,  -326,  -326,
+     345,  -326,  -326,   345,  -326,  -326,  -326,   176,  -326,  -326,
+    -326,    66,  -326,  -326,    66,  -326,    66,    66,  -326,    38,
+     345,    66,    66,    53,   345,    66,  -326,  -326,  -326,    66,
+      66,  -326,  -326,  -326,   445,   182,   341,  -326,  -326,   446,
+     448,    66,    66,  -326,  -326,  -326,  -326,   439,   450,  -326,
+      66,    66,  -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,
+    -326,  -326,  -326,  -326,  -326,  -326,   452,  -326,  -326,   451,
+    -326,   453,  -326,   345,   345,  -326,  -326,  -326,  -326,   456,
+    -326,   182,  -326,   164,  -326,   182,  -326,  -326,   182,   182,
+      66,  -326,  -326,  -326,  -326,  -326,   420,   121,   182,   458,
+     460,    49,  -326,  -326,  -326,   345,  -326,  -326,   434,  -326,
+      66,    35,  -326,    66,  -326,    66,  -326,  -326,   424,  -326,
+    -326,   345,    66,  -326,  -326,  -326,   324,    66,    66,  -326,
+    -326,   420,  -326,  -326,  -326,    66,  -326,   182,  -326,   345,
+     463,  -326,   345,  -326,   462,   412,  -326,   105,  -326,  -326,
+     454,  -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,
+    -326,    66,    66,  -326,  -326,  -326,   152,  -326,  -326,  -326,
+    -326,  -326,   350,  -326,  -326,  -326,   184,  -326,  -326,  -326,
+    -326,  -326,   466,    39,   345,  -326,   182,  -326,   210,   234,
+     234,   234,   234,   234,   234,   234,   234,  -326,  -326,  -326,
+     264,    72,   471,  -326,  -326,  -326,  -326,  -326,  -326,  -326,
+    -326,  -326,   399,  -326,  -326,  -326,    39,  -326,    66,  -326,
+    -326,   242,   223,   152,   210,   182,   234,   210,   348,    66,
+    -326,  -326,  -326,  -326,   470,   345,   345,   473,   476,   478,
+     182,   480,   481,   482,   483,   484,  -326,  -326,   489,   345,
+    -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,    66,
+    -326,   345,   425,  -326,   234,    69
+};
+
+/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+   Performed when YYTABLE does not specify something else to do.  Zero
+   means the default is an error.  */
+static const yytype_int16 yydefact[] =
+{
+       0,     0,     0,     0,     0,     1,     0,     0,   185,   190,
+       0,   184,   187,     0,   265,     0,     0,   192,    44,     0,
+     186,   188,   195,     0,    45,     0,     0,     0,     4,   191,
+       0,   193,     4,   266,    46,     0,    32,    72,    73,    88,
+      89,   115,   169,   170,     0,     0,   194,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,    33,     0,
+       0,     0,    64,     0,    64,     0,     0,     0,     0,    33,
+       0,    44,     0,     0,     0,     0,     0,     0,     0,     8,
+       9,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,   105,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,    33,     0,     0,    47,     0,   154,     0,     0,
+       0,     0,     6,     5,    26,     0,     0,     0,    10,    11,
+      12,    29,     0,    28,     0,     0,     0,    34,     0,     0,
+      19,    37,     0,     0,     0,    64,     0,     0,     0,     0,
+       0,    64,     0,     0,     0,     0,     4,     0,    90,     0,
+       0,    98,     0,     0,   106,     0,   109,     0,   113,     0,
+     116,   250,    44,     0,    44,   135,   136,   234,   251,     0,
+     137,     0,     0,    44,    47,     0,     0,     0,     0,   139,
+       0,    47,     0,     0,   147,     0,     0,     0,   252,    44,
+       0,   189,   199,   208,   198,   203,   204,   202,   206,   207,
+     200,   201,   205,   213,   150,   210,   211,   212,   209,   197,
+     196,    44,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,   106,     0,     0,     0,   179,     0,    48,
+      44,     0,     0,     0,     0,   152,   153,   151,     0,     0,
+       0,     2,     7,     3,    27,   253,   263,    13,    15,    14,
+       0,    31,   259,     0,    35,     0,    36,     0,     0,    39,
+      42,   256,     0,    66,    70,    71,    65,     0,     0,     0,
+      87,    37,    86,     0,    85,    84,     0,    91,    92,    93,
+       0,    97,   261,     0,   100,   262,   257,     0,   108,   110,
+     258,   112,   114,   120,     0,   124,     0,     0,   134,    47,
+     128,     0,     0,    47,   125,     0,    50,    44,   138,     0,
+       0,   145,   140,   142,     0,     0,    37,   260,   149,     0,
+       0,     0,     0,   168,   164,   165,   166,     0,     0,   163,
+       0,     0,   216,   229,   219,   215,   228,   217,   220,   218,
+     230,   221,   222,   223,   224,   225,   175,   227,   231,   233,
+     226,     0,   214,     0,   237,   155,   182,   183,    30,     0,
+     254,    17,    18,     0,    38,     0,    41,    63,     0,     0,
+       0,    80,    78,    79,    77,    81,    39,     0,     0,     0,
+       0,     0,    94,    95,    96,     0,   103,   104,     0,   111,
+       0,    47,   123,     0,   119,     0,   117,   235,     0,   129,
+     130,   131,     0,   126,   127,    44,     0,     0,     0,   141,
+     146,    39,   156,   174,   171,     0,   173,     0,   161,     0,
+       0,   176,     0,   232,     0,     0,   239,     0,   240,   255,
+       0,    21,    22,    23,    24,    25,    40,    67,    68,    69,
+      74,     0,     0,    82,    43,   264,     0,    99,   101,   121,
+     122,   118,    47,   132,   133,    52,    61,    49,   143,   144,
+     148,   172,     0,     0,     0,   157,     0,   238,    33,     0,
+       0,     0,     0,     0,     0,     0,     0,    16,    76,    75,
+       0,     0,     0,    51,    60,    58,    59,    55,    57,    56,
+      54,    53,     0,    20,   159,   158,     0,   162,     0,   180,
+     249,     0,     0,     0,    33,     0,     0,    33,     0,     0,
+     107,   102,   236,    62,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,    83,   160,     0,     0,
+     241,   246,   247,   242,   245,   243,   244,   248,   167,     0,
+     177,   181,     0,   178,     0,     0
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int16 yypgoto[] =
+{
+    -326,  -326,   -65,   -23,    97,   -79,   -83,   -13,   -62,  -232,
+    -326,  -191,   -27,  -118,   -94,   195,   -67,   -26,  -228,  -325,
+     -97,  -226,    -1,   172,   -86,   -55,  -326,  -326,  -326,  -326,
+     198,   -36,  -326,   431,  -111,   201,  -326,   428,  -147,  -326,
+    -326,  -326,  -326,  -326,  -326,   381,   386,  -326,  -326,  -326,
+     -45,   -96,  -326,  -326,   -95,   132,  -326,  -326,  -326,  -326,
+     300,  -326,  -326,  -326,   -93,  -326,  -326,   139,    -7,  -326,
+    -326,  -326,  -326,   -50,  -326,  -326,  -326,  -326,  -326,  -326,
+    -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,
+    -326,  -326,    42,   -89,  -227,  -326,  -326,  -326,  -326,  -326,
+    -290,  -222,   -92,  -326,  -326,  -326
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int16 yydefgoto[] =
+{
+       0,   131,    34,   194,   134,    91,   142,   150,   151,   348,
+     455,   384,   135,   144,   145,    36,   176,   149,   279,   386,
+     152,   168,   187,    25,   327,   195,   425,   476,   511,   512,
+     155,   159,   390,   156,    37,    38,   397,   162,   289,   160,
+     164,   500,    39,    40,   300,   169,   172,   303,   501,   408,
+     520,   175,   307,   178,   179,    41,   182,   183,   410,   189,
+     190,   203,   198,   336,   206,   110,   258,    31,   516,   517,
+     349,   483,   350,    42,    43,   340,   442,   561,   248,   366,
+     536,     2,     3,    12,    15,    21,     7,    13,    23,    17,
+      27,   369,   251,   191,   322,   472,   253,   254,   374,   448,
+     521,   184,   192,   209,    11,    18
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule whose
+   number is the opposite.  If YYTABLE_NINF, syntax error.  */
+static const yytype_int16 yytable[] =
+{
+      30,   148,    35,   113,   114,   115,   116,   117,   118,   119,
+     120,   121,   122,   123,   124,   125,   126,    24,   180,   200,
+     136,   239,   146,   238,   153,   244,   270,   245,   373,   202,
+     246,   170,   173,   174,   177,   181,   188,   237,   163,   250,
+     205,   249,   208,   210,   249,   247,   112,   252,   112,   329,
+     330,     1,   234,   167,   143,   391,   393,   154,   154,   249,
+     154,   201,   154,   396,   171,   392,   394,   277,   233,   166,
+     236,   460,   166,   240,   466,     4,   243,   405,   112,    70,
+     321,   325,    32,   166,   343,   199,   274,   413,   313,   415,
+      70,    71,   317,   314,    70,   316,   167,    62,   193,   147,
+     232,   185,   186,   275,   143,   530,   480,   171,   431,    63,
+       5,   193,   531,     8,   435,   514,     6,   342,   417,   283,
+     341,   417,   129,   311,   166,   291,   130,   489,   112,   490,
+     491,   143,   492,     9,   493,   188,   320,   324,   334,   188,
+      10,   282,   344,   345,   346,   286,   138,   112,   139,   255,
+     256,   140,   378,   344,   345,   346,    16,   257,   138,    14,
+     139,   494,   495,   140,   188,   461,   141,    22,   319,   323,
+     496,   138,   112,   139,    26,   462,   140,   451,   141,   467,
+      35,   273,   406,   452,   453,   454,   407,   347,   138,   403,
+     139,   335,   326,   140,   456,   383,    44,   457,   458,   399,
+     522,   523,   524,   525,   526,   527,   528,   484,   231,   419,
+     111,   422,   235,   423,    19,    20,   486,   503,   504,   505,
+     506,   507,   508,   509,   510,   132,   112,   133,   379,    47,
+     351,   167,    89,    90,   395,   138,   112,   139,   147,   371,
+     140,   112,   181,   181,   267,   268,   269,   127,   132,   368,
+     133,   400,   297,   298,   299,   128,   409,   143,   518,   412,
+     137,   414,   416,   158,   347,   347,   420,   421,   207,   387,
+     424,   161,   211,   161,   427,   428,   212,   401,    28,    29,
+     167,    32,    33,    45,    46,   213,   434,   436,   196,   197,
+     214,   411,   215,   411,   216,   439,   440,   418,   450,   323,
+     217,   418,   383,   218,   549,   383,   383,   204,   112,   548,
+     473,   259,   260,   287,   288,   185,   186,   559,   411,   381,
+     382,   219,   430,   388,   389,    48,    24,    32,   477,    49,
+     261,   220,   221,   222,   223,   459,    50,    51,    52,   224,
+     225,   226,    53,   227,   228,   229,    30,   230,   166,   262,
+     445,   447,   181,   529,   204,   469,   249,   263,   470,   264,
+     471,   265,   266,   271,    54,   272,   276,   474,    55,    56,
+      57,   278,   478,   479,   347,   482,   280,   281,    58,   284,
+     481,   285,   167,   290,   292,   463,   250,   293,   294,   295,
+      59,   301,   296,   302,   304,   305,    60,    61,   418,   306,
+     308,   310,    32,    35,   309,   312,   498,   499,   315,   318,
+     328,   331,   332,   333,   337,   338,   347,   352,   353,   167,
+     354,   355,   356,   357,   475,   358,   359,   360,   542,   539,
+     543,   361,   544,   362,   363,   545,   364,   365,   515,   367,
+     370,   372,   375,   538,   376,   377,   380,   533,   398,   429,
+     432,   385,   433,   143,    28,   437,   438,   540,   441,   444,
+     449,   167,   464,   535,   465,    70,   468,   485,   487,   488,
+     513,   515,   497,   519,   546,   532,   547,   550,   274,    92,
+     551,   243,   552,    93,   553,   554,   555,   556,   557,    35,
+      94,    95,    96,   558,   537,   402,    97,   564,   541,   426,
+     241,   404,   157,   165,   560,   446,   242,   339,   443,   534,
+     143,   563,   167,   347,   502,     0,     0,     0,    98,   565,
+       0,     0,    99,   100,   101,     0,   347,     0,     0,     0,
+       0,     0,   102,   103,     0,    64,   249,   104,   562,   105,
+       0,     0,   347,     0,   106,   107,     0,     0,     0,     0,
+     108,   109,    65,     0,    66,    67,     0,    68,     0,    69,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,    70,    71,     0,    72,    73,    74,    75,     0,     0,
+       0,    76,     0,     0,     0,    77,    78,    79,    80,    81,
+      64,     0,    82,    83,    84,    85,     0,     0,     0,    86,
+       0,    87,    88,     0,     0,     0,     0,    65,     0,    66,
+      67,     0,    68,     0,    69,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,    70,    71,     0,    72,
+      73,    74,    75,     0,     0,     0,    76,     0,     0,     0,
+      77,    78,    79,    80,    81,     0,     0,    82,    83,    84,
+      85,     0,     0,     0,    86,     0,    87,    88
+};
+
+static const yytype_int16 yycheck[] =
+{
+      23,    68,    25,    48,    49,    50,    51,    52,    53,    54,
+      55,    56,    57,    58,    59,    60,    61,    18,    80,    84,
+      65,   118,    67,   117,    69,   121,   144,   122,   254,    84,
+     123,    76,    77,    78,    79,    80,    81,   116,    74,   125,
+      85,     6,    87,    88,     6,   124,     7,   126,     7,   196,
+     197,     3,   114,    76,    67,   287,   288,    70,    71,     6,
+      73,    84,    75,   291,    77,   287,   288,   150,   113,     3,
+     115,   396,     3,   118,    25,    79,   121,   303,     7,    41,
+     191,   192,     3,     3,     4,     6,   148,   314,   180,   316,
+      41,    42,   184,   182,    41,   184,   119,    66,    32,    28,
+     113,    60,    61,   148,   117,    33,   431,   120,   336,    78,
+       0,    32,    40,     6,   341,    76,     3,   209,    83,   155,
+     209,    83,     6,   178,     3,   161,    10,    22,     7,    24,
+      25,   144,    27,    81,    29,   180,   191,   192,   203,   184,
+       3,   154,    73,    74,    75,   158,     6,     7,     8,    67,
+      68,    11,   270,    73,    74,    75,     3,    75,     6,    85,
+       8,    56,    57,    11,   209,   397,    26,    82,   191,   192,
+      65,     6,     7,     8,    80,   397,    11,    13,    26,   405,
+     203,    16,     6,    19,    20,    21,    10,   210,     6,   300,
+       8,   204,   193,    11,   385,   278,     6,   388,   389,   296,
+     490,   491,   492,   493,   494,   495,   496,   439,   111,   320,
+       7,   322,   115,   324,     3,     4,   442,    33,    34,    35,
+      36,    37,    38,    39,    40,     6,     7,     8,   273,    70,
+     231,   254,     9,    10,   289,     6,     7,     8,    28,   252,
+      11,     7,   287,   288,    13,    14,    15,     7,     6,   250,
+       8,   296,    52,    53,    54,     7,   311,   270,   484,   314,
+       7,   316,   317,    43,   287,   288,   321,   322,     7,   282,
+     325,    73,     4,    75,   329,   330,     6,   300,     3,     4,
+     303,     3,     4,     3,     4,     6,   341,   342,    17,    18,
+       6,   314,     6,   316,     6,   350,   351,   320,   381,   322,
+       6,   324,   385,     6,   536,   388,   389,     6,     7,   535,
+     421,    60,    61,    49,    50,    60,    61,   549,   341,    17,
+      18,     6,   335,    30,    31,    12,   327,     3,     4,    16,
+       7,     6,     6,     6,     6,   390,    23,    24,    25,     6,
+       6,     6,    29,     6,     6,     6,   369,     4,     3,     7,
+     373,   374,   397,   500,     6,   410,     6,     4,   413,     4,
+     415,     4,     4,     4,    51,     4,     4,   422,    55,    56,
+      57,    30,   427,   428,   397,   437,     4,     4,    65,     4,
+     435,     4,   405,     4,     4,   398,   472,    82,     4,     4,
+      77,     4,    29,     4,     4,     4,    83,    84,   421,     4,
+       4,     4,     3,   426,     6,     4,   461,   462,     4,     4,
+       4,     4,     4,     4,     4,     4,   439,     4,     4,   442,
+       4,     4,     4,     4,   425,     4,     4,     4,   525,   523,
+     526,     4,   527,     4,     4,   528,     4,     4,   483,     4,
+       4,     4,     4,   522,     4,     4,     4,   512,    48,     4,
+       4,    31,     4,   466,     3,    16,     6,   524,     6,     6,
+       4,   484,     4,   518,     4,    41,    32,     4,     6,    57,
+       4,   516,    18,   486,   529,     4,     6,     4,   540,    12,
+       4,   526,     4,    16,     4,     4,     4,     4,     4,   512,
+      23,    24,    25,     4,   521,   300,    29,    72,   524,   327,
+     119,   300,    71,    75,   559,   373,   120,   207,   369,   516,
+     523,   561,   535,   536,   472,    -1,    -1,    -1,    51,   564,
+      -1,    -1,    55,    56,    57,    -1,   549,    -1,    -1,    -1,
+      -1,    -1,    65,    66,    -1,     5,     6,    70,   561,    72,
+      -1,    -1,   565,    -1,    77,    78,    -1,    -1,    -1,    -1,
+      83,    84,    22,    -1,    24,    25,    -1,    27,    -1,    29,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    41,    42,    -1,    44,    45,    46,    47,    -1,    -1,
+      -1,    51,    -1,    -1,    -1,    55,    56,    57,    58,    59,
+       5,    -1,    62,    63,    64,    65,    -1,    -1,    -1,    69,
+      -1,    71,    72,    -1,    -1,    -1,    -1,    22,    -1,    24,
+      25,    -1,    27,    -1,    29,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    41,    42,    -1,    44,
+      45,    46,    47,    -1,    -1,    -1,    51,    -1,    -1,    -1,
+      55,    56,    57,    58,    59,    -1,    -1,    62,    63,    64,
+      65,    -1,    -1,    -1,    69,    -1,    71,    72
+};
+
+/* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of
+   state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,     3,   167,   168,    79,     0,     3,   172,     6,    81,
+       3,   190,   169,   173,    85,   170,     3,   175,   191,     3,
+       4,   171,    82,   174,   108,   109,    80,   176,     3,     4,
+      89,   153,     3,     4,    88,    89,   101,   120,   121,   128,
+     129,   141,   159,   160,     6,     3,     4,    70,    12,    16,
+      23,    24,    25,    29,    51,    55,    56,    57,    65,    77,
+      83,    84,    66,    78,     5,    22,    24,    25,    27,    29,
+      41,    42,    44,    45,    46,    47,    51,    55,    56,    57,
+      58,    59,    62,    63,    64,    65,    69,    71,    72,     9,
+      10,    91,    12,    16,    23,    24,    25,    29,    51,    55,
+      56,    57,    65,    66,    70,    72,    77,    78,    83,    84,
+     151,     7,     7,   136,   136,   136,   136,   136,   136,   136,
+     136,   136,   136,   136,   136,   136,   136,     7,     7,     6,
+      10,    87,     6,     8,    90,    98,   136,     7,     6,     8,
+      11,    26,    92,    93,    99,   100,   136,    28,   102,   103,
+      93,    94,   106,   136,    93,   116,   119,   119,    43,   117,
+     125,   116,   123,   117,   126,   123,     3,    89,   107,   131,
+     136,    93,   132,   136,   136,   137,   102,   136,   139,   140,
+      94,   136,   142,   143,   187,    60,    61,   108,   136,   145,
+     146,   179,   188,    32,    89,   111,    17,    18,   148,     6,
+      88,    89,   111,   147,     6,   136,   150,     7,   136,   189,
+     136,     4,     6,     6,     6,     6,     6,     6,     6,     6,
+       6,     6,     6,     6,     6,     6,     6,     6,     6,     6,
+       4,    90,    93,   136,    94,    90,   136,    91,   100,   106,
+     136,   131,   132,   136,   137,   140,   150,    91,   164,     6,
+     110,   178,    91,   182,   183,    67,    68,    75,   152,    60,
+      61,     7,     7,     4,     4,     4,     4,    13,    14,    15,
+      99,     4,     4,    16,    94,   136,     4,    92,    30,   104,
+       4,     4,    93,   117,     4,     4,    93,    49,    50,   124,
+       4,   117,     4,    82,     4,     4,    29,    52,    53,    54,
+     130,     4,     4,   133,     4,     4,     4,   138,     4,     6,
+       4,   111,     4,   188,   179,     4,   179,   188,     4,    89,
+     111,   120,   180,    89,   111,   120,   108,   110,     4,   124,
+     124,     4,     4,     4,    88,    93,   149,     4,     4,   146,
+     161,   179,   188,     4,    73,    74,    75,    89,    95,   156,
+     158,   108,     4,     4,     4,     4,     4,     4,     4,     4,
+       4,     4,     4,     4,     4,     4,   165,     4,   108,   177,
+       4,    93,     4,   107,   184,     4,     4,     4,    99,   136,
+       4,    17,    18,    92,    97,    31,   105,    93,    30,    31,
+     118,    95,   187,    95,   187,   111,   104,   122,    48,   106,
+     136,    89,   101,   120,   121,   107,     6,    10,   135,   111,
+     144,    89,   111,   180,   111,   180,   111,    83,    89,   120,
+     111,   111,   120,   120,   111,   112,   109,   111,   111,     4,
+      93,   104,     4,     4,   111,   180,   111,    16,     6,   111,
+     111,     6,   162,   153,     6,    89,   141,    89,   185,     4,
+      92,    13,    19,    20,    21,    96,    97,    97,    97,   111,
+     105,    95,   187,    93,     4,     4,    25,   107,    32,   111,
+     111,   111,   181,   120,   111,   108,   113,     4,   111,   111,
+     105,   111,    94,   157,    95,     4,   107,     6,    57,    22,
+      24,    25,    27,    29,    56,    57,    65,    18,   111,   111,
+     127,   134,   178,    33,    34,    35,    36,    37,    38,    39,
+      40,   114,   115,     4,    76,   136,   154,   155,   107,    93,
+     136,   186,   186,   186,   186,   186,   186,   186,   186,   124,
+      33,    40,     4,    88,   154,   111,   166,    98,    91,   100,
+     102,   103,   106,   137,   140,   150,   111,     6,   107,    95,
+       4,     4,     4,     4,     4,     4,     4,     4,     4,    95,
+     111,   163,    89,   159,    72,   136
+};
+
+/* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    86,    87,    88,    89,    90,    90,    87,    91,    91,
+      92,    92,    92,    93,    93,    93,    94,    94,    94,    94,
+      95,    96,    96,    96,    96,    97,    98,    88,    99,    99,
+     100,   101,    88,   102,   102,   103,    88,   104,   104,   105,
+     105,   106,    88,   107,   108,   109,   109,   110,   110,   111,
+     112,   111,   113,   113,   114,   114,   114,   114,   114,   114,
+     114,   115,   114,   116,   117,   117,   118,   118,   118,   119,
+     120,   121,    88,    88,   122,   123,   123,   124,   124,   124,
+     124,   125,   127,   126,   128,   128,   129,   129,    88,    88,
+     130,   130,   130,   130,   131,   131,   131,    88,   133,   132,
+      88,   134,   134,   135,   135,   136,   138,   137,    88,   139,
+     139,   140,   140,   140,   141,    88,   142,   143,   143,   143,
+     144,   143,   143,   143,    88,   145,   145,   145,   145,   145,
+     145,   145,   145,   145,    88,   146,   146,   145,    88,   147,
+      88,    88,    88,   148,   148,    88,   149,   149,   150,    88,
+     151,   152,   152,   152,   152,    88,    88,   153,   154,   154,
+     155,   157,   156,   158,   158,   158,   158,   159,   160,    88,
+      88,   161,   161,   161,    88,   162,   162,   163,   163,   165,
+     166,   164,    88,    88,   167,   169,   168,   170,   170,   171,
+     173,   172,   174,   174,   175,   176,   176,   151,   151,   151,
+     151,   151,   151,   151,   151,   151,   151,   151,   151,   151,
+     151,   151,   151,   151,   153,   153,   153,   153,   153,   153,
+     153,   153,   153,   153,   153,   153,   153,   153,   153,   153,
+     153,   177,   177,   178,   179,   181,   180,   182,   183,   184,
+     184,   185,   185,   185,   185,   185,   185,   185,   185,   186,
+     187,   188,   189,    88,    88,    88,    88,    88,    88,    88,
+      88,    88,    88,    88,   107,   191,   190
+};
+
+/* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM.  */
+static const yytype_int8 yyr2[] =
+{
+       0,     2,     2,     4,     1,     1,     1,     2,     1,     1,
+       1,     1,     1,     2,     2,     2,     5,     3,     3,     1,
+       4,     1,     1,     1,     1,     2,     1,     4,     1,     1,
+       3,     4,     1,     0,     1,     2,     4,     0,     2,     0,
+       2,     3,     4,     4,     0,     1,     2,     0,     1,     4,
+       0,     5,     1,     2,     1,     1,     1,     1,     1,     1,
+       1,     0,     2,     3,     0,     2,     0,     2,     2,     4,
+       4,     4,     1,     1,     2,     5,     5,     2,     2,     2,
+       2,     3,     0,     7,     4,     4,     4,     4,     1,     1,
+       0,     1,     1,     1,     3,     3,     3,     4,     0,     4,
+       4,     0,     2,     1,     1,     1,     0,     6,     4,     1,
+       2,     3,     2,     1,     4,     1,     1,     3,     4,     3,
+       0,     4,     4,     3,     4,     2,     3,     3,     2,     3,
+       3,     3,     4,     4,     4,     1,     1,     1,     4,     1,
+       4,     5,     4,     4,     4,     4,     2,     0,     4,     4,
+       2,     1,     1,     1,     0,     5,     5,     7,     1,     1,
+       3,     0,     4,     1,     1,     1,     1,    10,     4,     1,
+       1,     2,     3,     2,     5,     0,     1,     0,     2,     0,
+       0,    10,     5,     5,     3,     0,     6,     0,     2,     5,
+       0,     6,     0,     2,     4,     0,     4,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     5,     5,     5,     5,     5,     5,
+       5,     5,     5,     5,     5,     5,     5,     5,     5,     5,
+       5,     1,     2,     2,     1,     0,     5,     2,     4,     2,
+       2,     5,     5,     5,     5,     5,     5,     5,     5,     1,
+       1,     1,     1,     4,     5,     6,     4,     4,     4,     4,
+       4,     4,     4,     4,     4,     0,     5
+};
+
+
+enum { YYENOMEM = -2 };
+
+#define yyerrok         (yyerrstatus = 0)
+#define yyclearin       (yychar = YYEMPTY)
+
+#define YYACCEPT        goto yyacceptlab
+#define YYABORT         goto yyabortlab
+#define YYERROR         goto yyerrorlab
+#define YYNOMEM         goto yyexhaustedlab
+
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)                                    \
+  do                                                              \
+    if (yychar == YYEMPTY)                                        \
+      {                                                           \
+        yychar = (Token);                                         \
+        yylval = (Value);                                         \
+        YYPOPSTACK (yylen);                                       \
+        yystate = *yyssp;                                         \
+        goto yybackup;                                            \
+      }                                                           \
+    else                                                          \
+      {                                                           \
+        yyerror (YY_("syntax error: cannot back up")); \
+        YYERROR;                                                  \
+      }                                                           \
+  while (0)
+
+/* Backward compatibility with an undocumented macro.
+   Use YYerror or YYUNDEF. */
+#define YYERRCODE YYUNDEF
+
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)                        \
+do {                                            \
+  if (yydebug)                                  \
+    YYFPRINTF Args;                             \
+} while (0)
+
+
+
+
+# define YY_SYMBOL_PRINT(Title, Kind, Value, Location)                    \
+do {                                                                      \
+  if (yydebug)                                                            \
+    {                                                                     \
+      YYFPRINTF (stderr, "%s ", Title);                                   \
+      yy_symbol_print (stderr,                                            \
+                  Kind, Value); \
+      YYFPRINTF (stderr, "\n");                                           \
+    }                                                                     \
+} while (0)
+
+
+/*-----------------------------------.
+| Print this symbol's value on YYO.  |
+`-----------------------------------*/
+
+static void
+yy_symbol_value_print (FILE *yyo,
+                       yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep)
+{
+  FILE *yyoutput = yyo;
+  YY_USE (yyoutput);
+  if (!yyvaluep)
+    return;
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+  YY_USE (yykind);
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
+}
+
+
+/*---------------------------.
+| Print this symbol on YYO.  |
+`---------------------------*/
+
+static void
+yy_symbol_print (FILE *yyo,
+                 yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep)
+{
+  YYFPRINTF (yyo, "%s %s (",
+             yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind));
+
+  yy_symbol_value_print (yyo, yykind, yyvaluep);
+  YYFPRINTF (yyo, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+static void
+yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop)
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; yybottom <= yytop; yybottom++)
+    {
+      int yybot = *yybottom;
+      YYFPRINTF (stderr, " %d", yybot);
+    }
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)                            \
+do {                                                            \
+  if (yydebug)                                                  \
+    yy_stack_print ((Bottom), (Top));                           \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+static void
+yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp,
+                 int yyrule)
+{
+  int yylno = yyrline[yyrule];
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n",
+             yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      YYFPRINTF (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr,
+                       YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]),
+                       &yyvsp[(yyi + 1) - (yynrhs)]);
+      YYFPRINTF (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)          \
+do {                                    \
+  if (yydebug)                          \
+    yy_reduce_print (yyssp, yyvsp, Rule); \
+} while (0)
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args) ((void) 0)
+# define YY_SYMBOL_PRINT(Title, Kind, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+/* Context of a parse error.  */
+typedef struct
+{
+  yy_state_t *yyssp;
+  yysymbol_kind_t yytoken;
+} yypcontext_t;
+
+/* Put in YYARG at most YYARGN of the expected tokens given the
+   current YYCTX, and return the number of tokens stored in YYARG.  If
+   YYARG is null, return the number of expected tokens (guaranteed to
+   be less than YYNTOKENS).  Return YYENOMEM on memory exhaustion.
+   Return 0 if there are more than YYARGN expected tokens, yet fill
+   YYARG up to YYARGN. */
+static int
+yypcontext_expected_tokens (const yypcontext_t *yyctx,
+                            yysymbol_kind_t yyarg[], int yyargn)
+{
+  /* Actual size of YYARG. */
+  int yycount = 0;
+  int yyn = yypact[+*yyctx->yyssp];
+  if (!yypact_value_is_default (yyn))
+    {
+      /* Start YYX at -YYN if negative to avoid negative indexes in
+         YYCHECK.  In other words, skip the first -YYN actions for
+         this state because they are default actions.  */
+      int yyxbegin = yyn < 0 ? -yyn : 0;
+      /* Stay within bounds of both yycheck and yytname.  */
+      int yychecklim = YYLAST - yyn + 1;
+      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+      int yyx;
+      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+        if (yycheck[yyx + yyn] == yyx && yyx != YYSYMBOL_YYerror
+            && !yytable_value_is_error (yytable[yyx + yyn]))
+          {
+            if (!yyarg)
+              ++yycount;
+            else if (yycount == yyargn)
+              return 0;
+            else
+              yyarg[yycount++] = YY_CAST (yysymbol_kind_t, yyx);
+          }
+    }
+  if (yyarg && yycount == 0 && 0 < yyargn)
+    yyarg[0] = YYSYMBOL_YYEMPTY;
+  return yycount;
+}
+
+
+
+
+#ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+#  define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S)))
+# else
+/* Return the length of YYSTR.  */
+static YYPTRDIFF_T
+yystrlen (const char *yystr)
+{
+  YYPTRDIFF_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+# endif
+#endif
+
+#ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#  define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+# endif
+#endif
+
+#ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYPTRDIFF_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYPTRDIFF_T yyn = 0;
+      char const *yyp = yystr;
+      for (;;)
+        switch (*++yyp)
+          {
+          case '\'':
+          case ',':
+            goto do_not_strip_quotes;
+
+          case '\\':
+            if (*++yyp != '\\')
+              goto do_not_strip_quotes;
+            else
+              goto append;
+
+          append:
+          default:
+            if (yyres)
+              yyres[yyn] = *yyp;
+            yyn++;
+            break;
+
+          case '"':
+            if (yyres)
+              yyres[yyn] = '\0';
+            return yyn;
+          }
+    do_not_strip_quotes: ;
+    }
+
+  if (yyres)
+    return yystpcpy (yyres, yystr) - yyres;
+  else
+    return yystrlen (yystr);
+}
+#endif
+
+
+static int
+yy_syntax_error_arguments (const yypcontext_t *yyctx,
+                           yysymbol_kind_t yyarg[], int yyargn)
+{
+  /* Actual size of YYARG. */
+  int yycount = 0;
+  /* There are many possibilities here to consider:
+     - If this state is a consistent state with a default action, then
+       the only way this function was invoked is if the default action
+       is an error action.  In that case, don't check for expected
+       tokens because there are none.
+     - The only way there can be no lookahead present (in yychar) is if
+       this state is a consistent state with a default action.  Thus,
+       detecting the absence of a lookahead is sufficient to determine
+       that there is no unexpected or expected token to report.  In that
+       case, just report a simple "syntax error".
+     - Don't assume there isn't a lookahead just because this state is a
+       consistent state with a default action.  There might have been a
+       previous inconsistent state, consistent state with a non-default
+       action, or user semantic action that manipulated yychar.
+     - Of course, the expected token list depends on states to have
+       correct lookahead information, and it depends on the parser not
+       to perform extra reductions after fetching a lookahead from the
+       scanner and before detecting a syntax error.  Thus, state merging
+       (from LALR or IELR) and default reductions corrupt the expected
+       token list.  However, the list is correct for canonical LR with
+       one exception: it will still contain any token that will not be
+       accepted due to an error action in a later state.
+  */
+  if (yyctx->yytoken != YYSYMBOL_YYEMPTY)
+    {
+      int yyn;
+      if (yyarg)
+        yyarg[yycount] = yyctx->yytoken;
+      ++yycount;
+      yyn = yypcontext_expected_tokens (yyctx,
+                                        yyarg ? yyarg + 1 : yyarg, yyargn - 1);
+      if (yyn == YYENOMEM)
+        return YYENOMEM;
+      else
+        yycount += yyn;
+    }
+  return yycount;
+}
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+   about the unexpected token YYTOKEN for the state stack whose top is
+   YYSSP.
+
+   Return 0 if *YYMSG was successfully written.  Return -1 if *YYMSG is
+   not large enough to hold the message.  In that case, also set
+   *YYMSG_ALLOC to the required number of bytes.  Return YYENOMEM if the
+   required number of bytes is too large to store.  */
+static int
+yysyntax_error (YYPTRDIFF_T *yymsg_alloc, char **yymsg,
+                const yypcontext_t *yyctx)
+{
+  enum { YYARGS_MAX = 5 };
+  /* Internationalized format string. */
+  const char *yyformat = YY_NULLPTR;
+  /* Arguments of yyformat: reported tokens (one for the "unexpected",
+     one per "expected"). */
+  yysymbol_kind_t yyarg[YYARGS_MAX];
+  /* Cumulated lengths of YYARG.  */
+  YYPTRDIFF_T yysize = 0;
+
+  /* Actual size of YYARG. */
+  int yycount = yy_syntax_error_arguments (yyctx, yyarg, YYARGS_MAX);
+  if (yycount == YYENOMEM)
+    return YYENOMEM;
+
+  switch (yycount)
+    {
+#define YYCASE_(N, S)                       \
+      case N:                               \
+        yyformat = S;                       \
+        break
+    default: /* Avoid compiler warnings. */
+      YYCASE_(0, YY_("syntax error"));
+      YYCASE_(1, YY_("syntax error, unexpected %s"));
+      YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+      YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+      YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+      YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+#undef YYCASE_
+    }
+
+  /* Compute error message size.  Don't count the "%s"s, but reserve
+     room for the terminator.  */
+  yysize = yystrlen (yyformat) - 2 * yycount + 1;
+  {
+    int yyi;
+    for (yyi = 0; yyi < yycount; ++yyi)
+      {
+        YYPTRDIFF_T yysize1
+          = yysize + yytnamerr (YY_NULLPTR, yytname[yyarg[yyi]]);
+        if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)
+          yysize = yysize1;
+        else
+          return YYENOMEM;
+      }
+  }
+
+  if (*yymsg_alloc < yysize)
+    {
+      *yymsg_alloc = 2 * yysize;
+      if (! (yysize <= *yymsg_alloc
+             && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+        *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+      return -1;
+    }
+
+  /* Avoid sprintf, as that infringes on the user's name space.
+     Don't have undefined behavior even if the translation
+     produced a string with the wrong number of "%s"s.  */
+  {
+    char *yyp = *yymsg;
+    int yyi = 0;
+    while ((*yyp = *yyformat) != '\0')
+      if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+        {
+          yyp += yytnamerr (yyp, yytname[yyarg[yyi++]]);
+          yyformat += 2;
+        }
+      else
+        {
+          ++yyp;
+          ++yyformat;
+        }
+  }
+  return 0;
+}
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+static void
+yydestruct (const char *yymsg,
+            yysymbol_kind_t yykind, YYSTYPE *yyvaluep)
+{
+  YY_USE (yyvaluep);
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp);
+
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+  YY_USE (yykind);
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
+}
+
+
+/* Lookahead token kind.  */
+int yychar;
+
+/* The semantic value of the lookahead symbol.  */
+YYSTYPE yylval;
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+int
+yyparse (void)
+{
+    yy_state_fast_t yystate = 0;
+    /* Number of tokens to shift before error messages enabled.  */
+    int yyerrstatus = 0;
+
+    /* Refer to the stacks through separate pointers, to allow yyoverflow
+       to reallocate them elsewhere.  */
+
+    /* Their size.  */
+    YYPTRDIFF_T yystacksize = YYINITDEPTH;
+
+    /* The state stack: array, bottom, top.  */
+    yy_state_t yyssa[YYINITDEPTH];
+    yy_state_t *yyss = yyssa;
+    yy_state_t *yyssp = yyss;
+
+    /* The semantic value stack: array, bottom, top.  */
+    YYSTYPE yyvsa[YYINITDEPTH];
+    YYSTYPE *yyvs = yyvsa;
+    YYSTYPE *yyvsp = yyvs;
+
+  int yyn;
+  /* The return value of yyparse.  */
+  int yyresult;
+  /* Lookahead symbol kind.  */
+  yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY;
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYPTRDIFF_T yymsg_alloc = sizeof yymsgbuf;
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yychar = YYEMPTY; /* Cause a token to be read.  */
+
+  goto yysetstate;
+
+
+/*------------------------------------------------------------.
+| yynewstate -- push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+
+/*--------------------------------------------------------------------.
+| yysetstate -- set current state (the top of the stack) to yystate.  |
+`--------------------------------------------------------------------*/
+yysetstate:
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+  YY_ASSERT (0 <= yystate && yystate < YYNSTATES);
+  YY_IGNORE_USELESS_CAST_BEGIN
+  *yyssp = YY_CAST (yy_state_t, yystate);
+  YY_IGNORE_USELESS_CAST_END
+  YY_STACK_PRINT (yyss, yyssp);
+
+  if (yyss + yystacksize - 1 <= yyssp)
+#if !defined yyoverflow && !defined YYSTACK_RELOCATE
+    YYNOMEM;
+#else
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYPTRDIFF_T yysize = yyssp - yyss + 1;
+
+# if defined yyoverflow
+      {
+        /* Give user a chance to reallocate the stack.  Use copies of
+           these so that the &'s don't force the real ones into
+           memory.  */
+        yy_state_t *yyss1 = yyss;
+        YYSTYPE *yyvs1 = yyvs;
+
+        /* Each stack pointer address is followed by the size of the
+           data in use in that stack, in bytes.  This used to be a
+           conditional around just the two extra args, but that might
+           be undefined if yyoverflow is a macro.  */
+        yyoverflow (YY_("memory exhausted"),
+                    &yyss1, yysize * YYSIZEOF (*yyssp),
+                    &yyvs1, yysize * YYSIZEOF (*yyvsp),
+                    &yystacksize);
+        yyss = yyss1;
+        yyvs = yyvs1;
+      }
+# else /* defined YYSTACK_RELOCATE */
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+        YYNOMEM;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+        yystacksize = YYMAXDEPTH;
+
+      {
+        yy_state_t *yyss1 = yyss;
+        union yyalloc *yyptr =
+          YY_CAST (union yyalloc *,
+                   YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize))));
+        if (! yyptr)
+          YYNOMEM;
+        YYSTACK_RELOCATE (yyss_alloc, yyss);
+        YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+#  undef YYSTACK_RELOCATE
+        if (yyss1 != yyssa)
+          YYSTACK_FREE (yyss1);
+      }
+# endif
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+      YY_IGNORE_USELESS_CAST_BEGIN
+      YYDPRINTF ((stderr, "Stack size increased to %ld\n",
+                  YY_CAST (long, yystacksize)));
+      YY_IGNORE_USELESS_CAST_END
+
+      if (yyss + yystacksize - 1 <= yyssp)
+        YYABORT;
+    }
+#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */
+
+
+  if (yystate == YYFINAL)
+    YYACCEPT;
+
+  goto yybackup;
+
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+  /* Do appropriate processing given the current state.  Read a
+     lookahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+  yyn = yypact[yystate];
+  if (yypact_value_is_default (yyn))
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* YYCHAR is either empty, or end-of-input, or a valid lookahead.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token\n"));
+      yychar = yylex ();
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = YYEOF;
+      yytoken = YYSYMBOL_YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else if (yychar == YYerror)
+    {
+      /* The scanner already issued an error message, process directly
+         to error recovery.  But do not keep the error token as
+         lookahead, it is too special and may lead us to an endless
+         loop in error recovery. */
+      yychar = YYUNDEF;
+      yytoken = YYSYMBOL_YYerror;
+      goto yyerrlab1;
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yytable_value_is_error (yyn))
+        goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the lookahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+  yystate = yyn;
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+  *++yyvsp = yylval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+  /* Discard the shifted token.  */
+  yychar = YYEMPTY;
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     '$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+  case 2: /* glyph: UNSIGNED REFERENCE  */
+#line 264 "parser.y"
+                        {
+	#line 418 "format.w"
+	(yyval.c).c= (yyvsp[-1].u);REF(font_kind,(yyvsp[0].u));(yyval.c).f= (yyvsp[0].u);}
+#line 2018 "parser.c"
+    break;
+
+  case 3: /* content_node: start "glyph" glyph ">"  */
+#line 267 "parser.y"
+                                  {
+	#line 419 "format.w"
+	hput_tags((yyvsp[-3].u),hput_glyph(&((yyvsp[-1].c))));}
+#line 2026 "parser.c"
+    break;
+
+  case 4: /* start: "<"  */
+#line 270 "parser.y"
+           {
+	#line 420 "format.w"
+	HPUTNODE;(yyval.u)= (uint32_t)(hpos++-hstart);}
+#line 2034 "parser.c"
+    break;
+
+  case 6: /* integer: UNSIGNED  */
+#line 274 "parser.y"
+                         {
+	#line 941 "format.w"
+	RNG("number",(yyvsp[0].u),0,0x7FFFFFFF);}
+#line 2042 "parser.c"
+    break;
+
+  case 7: /* glyph: CHARCODE REFERENCE  */
+#line 278 "parser.y"
+                        {
+	#line 1082 "format.w"
+	(yyval.c).c= (yyvsp[-1].u);REF(font_kind,(yyvsp[0].u));(yyval.c).f= (yyvsp[0].u);}
+#line 2050 "parser.c"
+    break;
+
+  case 9: /* string: CHARCODE  */
+#line 282 "parser.y"
+                         {
+	#line 1187 "format.w"
+	static char s[2];
+	RNG("String element",(yyvsp[0].u),0x20,0x7E);
+	s[0]= (yyvsp[0].u);s[1]= 0;(yyval.s)= s;}
+#line 2060 "parser.c"
+    break;
+
+  case 10: /* number: UNSIGNED  */
+#line 288 "parser.y"
+               {
+	#line 1339 "format.w"
+	(yyval.f)= (float64_t)(yyvsp[0].u);}
+#line 2068 "parser.c"
+    break;
+
+  case 11: /* number: SIGNED  */
+#line 290 "parser.y"
+                                       {
+	#line 1339 "format.w"
+	(yyval.f)= (float64_t)(yyvsp[0].i);}
+#line 2076 "parser.c"
+    break;
+
+  case 13: /* dimension: number "pt"  */
+#line 294 "parser.y"
+                   {
+	#line 1682 "format.w"
+	(yyval.d)= ROUND((yyvsp[-1].f)*ONE);RNG("Dimension",(yyval.d),-MAX_DIMEN,MAX_DIMEN);}
+#line 2084 "parser.c"
+    break;
+
+  case 14: /* dimension: number "in"  */
+#line 297 "parser.y"
+                    {
+	#line 1683 "format.w"
+	(yyval.d)= ROUND((yyvsp[-1].f)*ONE*72.27);RNG("Dimension",(yyval.d),-MAX_DIMEN,MAX_DIMEN);}
+#line 2092 "parser.c"
+    break;
+
+  case 15: /* dimension: number "mm"  */
+#line 300 "parser.y"
+                  {
+	#line 1684 "format.w"
+	(yyval.d)= ROUND((yyvsp[-1].f)*ONE*(72.27/25.4));RNG("Dimension",(yyval.d),-MAX_DIMEN,MAX_DIMEN);}
+#line 2100 "parser.c"
+    break;
+
+  case 16: /* xdimen: dimension number "h" number "v"  */
+#line 304 "parser.y"
+                                  {
+	#line 1762 "format.w"
+	(yyval.xd).w= (yyvsp[-4].d);(yyval.xd).h= (yyvsp[-3].f);(yyval.xd).v= (yyvsp[-1].f);}
+#line 2108 "parser.c"
+    break;
+
+  case 17: /* xdimen: dimension number "h"  */
+#line 307 "parser.y"
+                           {
+	#line 1763 "format.w"
+	(yyval.xd).w= (yyvsp[-2].d);(yyval.xd).h= (yyvsp[-1].f);(yyval.xd).v= 0.0;}
+#line 2116 "parser.c"
+    break;
+
+  case 18: /* xdimen: dimension number "v"  */
+#line 310 "parser.y"
+                           {
+	#line 1764 "format.w"
+	(yyval.xd).w= (yyvsp[-2].d);(yyval.xd).h= 0.0;(yyval.xd).v= (yyvsp[-1].f);}
+#line 2124 "parser.c"
+    break;
+
+  case 19: /* xdimen: dimension  */
+#line 313 "parser.y"
+                  {
+	#line 1765 "format.w"
+	(yyval.xd).w= (yyvsp[0].d);(yyval.xd).h= 0.0;(yyval.xd).v= 0.0;}
+#line 2132 "parser.c"
+    break;
+
+  case 20: /* xdimen_node: start "xdimen" xdimen ">"  */
+#line 319 "parser.y"
+                                   {
+	#line 1769 "format.w"
+	hput_tags((yyvsp[-3].u),hput_xdimen(&((yyvsp[-1].xd))));}
+#line 2140 "parser.c"
+    break;
+
+  case 21: /* order: "pt"  */
+#line 324 "parser.y"
+        {
+	#line 1947 "format.w"
+	(yyval.o)= normal_o;}
+#line 2148 "parser.c"
+    break;
+
+  case 22: /* order: "fil"  */
+#line 326 "parser.y"
+                            {
+	#line 1947 "format.w"
+	(yyval.o)= fil_o;}
+#line 2156 "parser.c"
+    break;
+
+  case 23: /* order: "fill"  */
+#line 328 "parser.y"
+                             {
+	#line 1947 "format.w"
+	(yyval.o)= fill_o;}
+#line 2164 "parser.c"
+    break;
+
+  case 24: /* order: "filll"  */
+#line 330 "parser.y"
+                              {
+	#line 1947 "format.w"
+	(yyval.o)= filll_o;}
+#line 2172 "parser.c"
+    break;
+
+  case 25: /* stretch: number order  */
+#line 334 "parser.y"
+                    {
+	#line 1949 "format.w"
+	(yyval.st).f= (yyvsp[-1].f);(yyval.st).o= (yyvsp[0].o);}
+#line 2180 "parser.c"
+    break;
+
+  case 26: /* penalty: integer  */
+#line 338 "parser.y"
+               {
+	#line 2003 "format.w"
+	RNG("Penalty",(yyvsp[0].i),-20000,+20000);(yyval.i)= (yyvsp[0].i);}
+#line 2188 "parser.c"
+    break;
+
+  case 27: /* content_node: start "penalty" penalty ">"  */
+#line 341 "parser.y"
+                                      {
+	#line 2004 "format.w"
+	hput_tags((yyvsp[-3].u),hput_int((yyvsp[-1].i)));}
+#line 2196 "parser.c"
+    break;
+
+  case 29: /* rule_dimension: "|"  */
+#line 345 "parser.y"
+                                        {
+	#line 2179 "format.w"
+	(yyval.d)= RUNNING_DIMEN;}
+#line 2204 "parser.c"
+    break;
+
+  case 30: /* rule: rule_dimension rule_dimension rule_dimension  */
+#line 349 "parser.y"
+{
+	#line 2181 "format.w"
+	(yyval.r).h= (yyvsp[-2].d);(yyval.r).d= (yyvsp[-1].d);(yyval.r).w= (yyvsp[0].d);
+	if((yyvsp[0].d)==RUNNING_DIMEN&&((yyvsp[-2].d)==RUNNING_DIMEN||(yyvsp[-1].d)==RUNNING_DIMEN))
+	QUIT("Incompatible running dimensions 0x%x 0x%x 0x%x",(yyvsp[-2].d),(yyvsp[-1].d),(yyvsp[0].d));}
+#line 2214 "parser.c"
+    break;
+
+  case 31: /* rule_node: start "rule" rule ">"  */
+#line 354 "parser.y"
+                             {
+	#line 2184 "format.w"
+	hput_tags((yyvsp[-3].u),hput_rule(&((yyvsp[-1].r))));}
+#line 2222 "parser.c"
+    break;
+
+  case 33: /* explicit: %empty  */
+#line 359 "parser.y"
+         {
+	#line 2292 "format.w"
+	(yyval.b)= false;}
+#line 2230 "parser.c"
+    break;
+
+  case 34: /* explicit: "!"  */
+#line 361 "parser.y"
+                                 {
+	#line 2292 "format.w"
+	(yyval.b)= true;}
+#line 2238 "parser.c"
+    break;
+
+  case 35: /* kern: explicit xdimen  */
+#line 364 "parser.y"
+                    {
+	#line 2293 "format.w"
+	(yyval.kt).x= (yyvsp[-1].b);(yyval.kt).d= (yyvsp[0].xd);}
+#line 2246 "parser.c"
+    break;
+
+  case 36: /* content_node: start "kern" kern ">"  */
+#line 367 "parser.y"
+                                {
+	#line 2294 "format.w"
+	hput_tags((yyvsp[-3].u),hput_kern(&((yyvsp[-1].kt))));}
+#line 2254 "parser.c"
+    break;
+
+  case 37: /* plus: %empty  */
+#line 371 "parser.y"
+     {
+	#line 2504 "format.w"
+	(yyval.st).f= 0.0;(yyval.st).o= 0;}
+#line 2262 "parser.c"
+    break;
+
+  case 38: /* plus: "plus" stretch  */
+#line 373 "parser.y"
+                                             {
+	#line 2504 "format.w"
+	(yyval.st)= (yyvsp[0].st);}
+#line 2270 "parser.c"
+    break;
+
+  case 39: /* minus: %empty  */
+#line 376 "parser.y"
+      {
+	#line 2505 "format.w"
+	(yyval.st).f= 0.0;(yyval.st).o= 0;}
+#line 2278 "parser.c"
+    break;
+
+  case 40: /* minus: "minus" stretch  */
+#line 378 "parser.y"
+                                              {
+	#line 2505 "format.w"
+	(yyval.st)= (yyvsp[0].st);}
+#line 2286 "parser.c"
+    break;
+
+  case 41: /* glue: xdimen plus minus  */
+#line 381 "parser.y"
+                      {
+	#line 2506 "format.w"
+	(yyval.g).w= (yyvsp[-2].xd);(yyval.g).p= (yyvsp[-1].st);(yyval.g).m= (yyvsp[0].st);}
+#line 2294 "parser.c"
+    break;
+
+  case 42: /* content_node: start "glue" glue ">"  */
+#line 384 "parser.y"
+                                {
+	#line 2507 "format.w"
+	if(ZERO_GLUE((yyvsp[-1].g))){HPUT8(zero_skip_no);
+	hput_tags((yyvsp[-3].u),TAG(glue_kind,0));}else hput_tags((yyvsp[-3].u),hput_glue(&((yyvsp[-1].g))));}
+#line 2303 "parser.c"
+    break;
+
+  case 43: /* glue_node: start "glue" glue ">"  */
+#line 389 "parser.y"
+{
+	#line 2510 "format.w"
+	if(ZERO_GLUE((yyvsp[-1].g))){hpos--;(yyval.b)= false;}
+	else{hput_tags((yyvsp[-3].u),hput_glue(&((yyvsp[-1].g))));(yyval.b)= true;}}
+#line 2312 "parser.c"
+    break;
+
+  case 44: /* position: %empty  */
+#line 394 "parser.y"
+         {
+	#line 2786 "format.w"
+	(yyval.u)= hpos-hstart;}
+#line 2320 "parser.c"
+    break;
+
+  case 47: /* estimate: %empty  */
+#line 399 "parser.y"
+         {
+	#line 2789 "format.w"
+	hpos+= 2;}
+#line 2328 "parser.c"
+    break;
+
+  case 48: /* estimate: UNSIGNED  */
+#line 402 "parser.y"
+                 {
+	#line 2790 "format.w"
+	hpos+= hsize_bytes((yyvsp[0].u))+1;}
+#line 2336 "parser.c"
+    break;
+
+  case 49: /* list: start estimate content_list ">"  */
+#line 406 "parser.y"
+{
+	#line 2792 "format.w"
+	(yyval.l).k= list_kind;(yyval.l).p= (yyvsp[-1].u);(yyval.l).s= (hpos-hstart)-(yyvsp[-1].u);
+	hput_tags((yyvsp[-3].u),hput_list((yyvsp[-3].u)+1,&((yyval.l))));}
+#line 2345 "parser.c"
+    break;
+
+  case 50: /* $@1: %empty  */
+#line 412 "parser.y"
+{
+	#line 3199 "format.w"
+	hpos+= 4;}
+#line 2353 "parser.c"
+    break;
+
+  case 51: /* list: TXT_START position $@1 text TXT_END  */
+#line 416 "parser.y"
+{
+	#line 3201 "format.w"
+	(yyval.l).k= text_kind;(yyval.l).p= (yyvsp[-1].u);(yyval.l).s= (hpos-hstart)-(yyvsp[-1].u);
+	hput_tags((yyvsp[-3].u),hput_list((yyvsp[-3].u)+1,&((yyval.l))));}
+#line 2362 "parser.c"
+    break;
+
+  case 54: /* txt: TXT_CC  */
+#line 422 "parser.y"
+          {
+	#line 3205 "format.w"
+	hput_txt_cc((yyvsp[0].u));}
+#line 2370 "parser.c"
+    break;
+
+  case 55: /* txt: TXT_FONT  */
+#line 425 "parser.y"
+                 {
+	#line 3206 "format.w"
+	REF(font_kind,(yyvsp[0].u));hput_txt_font((yyvsp[0].u));}
+#line 2378 "parser.c"
+    break;
+
+  case 56: /* txt: TXT_GLOBAL  */
+#line 428 "parser.y"
+                   {
+	#line 3207 "format.w"
+	REF((yyvsp[0].rf).k,(yyvsp[0].rf).n);hput_txt_global(&((yyvsp[0].rf)));}
+#line 2386 "parser.c"
+    break;
+
+  case 57: /* txt: TXT_LOCAL  */
+#line 431 "parser.y"
+                  {
+	#line 3208 "format.w"
+	RNG("Font parameter",(yyvsp[0].u),0,11);hput_txt_local((yyvsp[0].u));}
+#line 2394 "parser.c"
+    break;
+
+  case 58: /* txt: TXT_FONT_GLUE  */
+#line 434 "parser.y"
+                      {
+	#line 3209 "format.w"
+	HPUTX(1);HPUT8(txt_glue);}
+#line 2402 "parser.c"
+    break;
+
+  case 59: /* txt: TXT_FONT_HYPHEN  */
+#line 437 "parser.y"
+                        {
+	#line 3210 "format.w"
+	HPUTX(1);HPUT8(txt_hyphen);}
+#line 2410 "parser.c"
+    break;
+
+  case 60: /* txt: TXT_IGNORE  */
+#line 440 "parser.y"
+                   {
+	#line 3211 "format.w"
+	HPUTX(1);HPUT8(txt_ignore);}
+#line 2418 "parser.c"
+    break;
+
+  case 61: /* $@2: %empty  */
+#line 443 "parser.y"
+         {
+	#line 3212 "format.w"
+	HPUTX(1);HPUT8(txt_node);}
+#line 2426 "parser.c"
+    break;
+
+  case 63: /* box_dimen: dimension dimension dimension  */
+#line 449 "parser.y"
+{
+	#line 3470 "format.w"
+	(yyval.info)= hput_box_dimen((yyvsp[-2].d),(yyvsp[-1].d),(yyvsp[0].d));}
+#line 2434 "parser.c"
+    break;
+
+  case 64: /* box_shift: %empty  */
+#line 452 "parser.y"
+          {
+	#line 3471 "format.w"
+	(yyval.info)= b000;}
+#line 2442 "parser.c"
+    break;
+
+  case 65: /* box_shift: "shifted" dimension  */
+#line 455 "parser.y"
+                          {
+	#line 3472 "format.w"
+	(yyval.info)= hput_box_shift((yyvsp[0].d));}
+#line 2450 "parser.c"
+    break;
+
+  case 66: /* box_glue_set: %empty  */
+#line 459 "parser.y"
+             {
+	#line 3474 "format.w"
+	(yyval.info)= b000;}
+#line 2458 "parser.c"
+    break;
+
+  case 67: /* box_glue_set: "plus" stretch  */
+#line 462 "parser.y"
+                     {
+	#line 3475 "format.w"
+	(yyval.info)= hput_box_glue_set(+1,(yyvsp[0].st).f,(yyvsp[0].st).o);}
+#line 2466 "parser.c"
+    break;
+
+  case 68: /* box_glue_set: "minus" stretch  */
+#line 465 "parser.y"
+                      {
+	#line 3476 "format.w"
+	(yyval.info)= hput_box_glue_set(-1,(yyvsp[0].st).f,(yyvsp[0].st).o);}
+#line 2474 "parser.c"
+    break;
+
+  case 69: /* box: box_dimen box_shift box_glue_set list  */
+#line 470 "parser.y"
+                                         {
+	#line 3479 "format.w"
+	(yyval.info)= (yyvsp[-3].info)	|(yyvsp[-2].info)	|(yyvsp[-1].info);}
+#line 2482 "parser.c"
+    break;
+
+  case 70: /* hbox_node: start "hbox" box ">"  */
+#line 474 "parser.y"
+                            {
+	#line 3481 "format.w"
+	hput_tags((yyvsp[-3].u),TAG(hbox_kind,(yyvsp[-1].info)));}
+#line 2490 "parser.c"
+    break;
+
+  case 71: /* vbox_node: start "vbox" box ">"  */
+#line 477 "parser.y"
+                            {
+	#line 3482 "format.w"
+	hput_tags((yyvsp[-3].u),TAG(vbox_kind,(yyvsp[-1].info)));}
+#line 2498 "parser.c"
+    break;
+
+  case 74: /* box_flex: plus minus  */
+#line 482 "parser.y"
+                   {
+	#line 3663 "format.w"
+	hput_stretch(&((yyvsp[-1].st)));hput_stretch(&((yyvsp[0].st)));}
+#line 2506 "parser.c"
+    break;
+
+  case 75: /* xbox: box_dimen box_shift box_flex xdimen_ref list  */
+#line 485 "parser.y"
+                                                 {
+	#line 3664 "format.w"
+	(yyval.info)= (yyvsp[-4].info)	|(yyvsp[-3].info);}
+#line 2514 "parser.c"
+    break;
+
+  case 76: /* xbox: box_dimen box_shift box_flex xdimen_node list  */
+#line 488 "parser.y"
+                                                      {
+	#line 3665 "format.w"
+	(yyval.info)= (yyvsp[-4].info)	|(yyvsp[-3].info)	|b100;}
+#line 2522 "parser.c"
+    break;
+
+  case 77: /* box_goal: "to" xdimen_ref  */
+#line 492 "parser.y"
+                      {
+	#line 3667 "format.w"
+	(yyval.info)= b000;}
+#line 2530 "parser.c"
+    break;
+
+  case 78: /* box_goal: "add" xdimen_ref  */
+#line 495 "parser.y"
+                       {
+	#line 3668 "format.w"
+	(yyval.info)= b001;}
+#line 2538 "parser.c"
+    break;
+
+  case 79: /* box_goal: "to" xdimen_node  */
+#line 498 "parser.y"
+                       {
+	#line 3669 "format.w"
+	(yyval.info)= b100;}
+#line 2546 "parser.c"
+    break;
+
+  case 80: /* box_goal: "add" xdimen_node  */
+#line 501 "parser.y"
+                        {
+	#line 3670 "format.w"
+	(yyval.info)= b101;}
+#line 2554 "parser.c"
+    break;
+
+  case 81: /* hpack: box_shift box_goal list  */
+#line 505 "parser.y"
+                             {
+	#line 3672 "format.w"
+	(yyval.info)= (yyvsp[-1].info);}
+#line 2562 "parser.c"
+    break;
+
+  case 82: /* $@3: %empty  */
+#line 508 "parser.y"
+                                   {
+	#line 3673 "format.w"
+	HPUT32((yyvsp[0].d));}
+#line 2570 "parser.c"
+    break;
+
+  case 83: /* vpack: box_shift "max" "depth" dimension $@3 box_goal list  */
+#line 510 "parser.y"
+                                 {
+	#line 3673 "format.w"
+	(yyval.info)= (yyvsp[-6].info)	|(yyvsp[-1].info);}
+#line 2578 "parser.c"
+    break;
+
+  case 84: /* vxbox_node: start "vset" xbox ">"  */
+#line 514 "parser.y"
+                              {
+	#line 3675 "format.w"
+	hput_tags((yyvsp[-3].u),TAG(vset_kind,(yyvsp[-1].info)));}
+#line 2586 "parser.c"
+    break;
+
+  case 85: /* vxbox_node: start "vpack" vpack ">"  */
+#line 517 "parser.y"
+                              {
+	#line 3676 "format.w"
+	hput_tags((yyvsp[-3].u),TAG(vpack_kind,(yyvsp[-1].info)));}
+#line 2594 "parser.c"
+    break;
+
+  case 86: /* hxbox_node: start "hset" xbox ">"  */
+#line 522 "parser.y"
+                              {
+	#line 3679 "format.w"
+	hput_tags((yyvsp[-3].u),TAG(hset_kind,(yyvsp[-1].info)));}
+#line 2602 "parser.c"
+    break;
+
+  case 87: /* hxbox_node: start "hpack" hpack ">"  */
+#line 525 "parser.y"
+                              {
+	#line 3680 "format.w"
+	hput_tags((yyvsp[-3].u),TAG(hpack_kind,(yyvsp[-1].info)));}
+#line 2610 "parser.c"
+    break;
+
+  case 90: /* ltype: %empty  */
+#line 531 "parser.y"
+      {
+	#line 3790 "format.w"
+	(yyval.info)= 1;}
+#line 2618 "parser.c"
+    break;
+
+  case 91: /* ltype: "align"  */
+#line 533 "parser.y"
+                      {
+	#line 3790 "format.w"
+	(yyval.info)= 1;}
+#line 2626 "parser.c"
+    break;
+
+  case 92: /* ltype: "center"  */
+#line 535 "parser.y"
+                       {
+	#line 3790 "format.w"
+	(yyval.info)= 2;}
+#line 2634 "parser.c"
+    break;
+
+  case 93: /* ltype: "expand"  */
+#line 537 "parser.y"
+                       {
+	#line 3790 "format.w"
+	(yyval.info)= 3;}
+#line 2642 "parser.c"
+    break;
+
+  case 94: /* leaders: glue_node ltype rule_node  */
+#line 540 "parser.y"
+                                 {
+	#line 3791 "format.w"
+	if((yyvsp[-2].b))(yyval.info)= (yyvsp[-1].info)	|b100;else (yyval.info)= (yyvsp[-1].info);}
+#line 2650 "parser.c"
+    break;
+
+  case 95: /* leaders: glue_node ltype hbox_node  */
+#line 543 "parser.y"
+                                  {
+	#line 3792 "format.w"
+	if((yyvsp[-2].b))(yyval.info)= (yyvsp[-1].info)	|b100;else (yyval.info)= (yyvsp[-1].info);}
+#line 2658 "parser.c"
+    break;
+
+  case 96: /* leaders: glue_node ltype vbox_node  */
+#line 546 "parser.y"
+                                  {
+	#line 3793 "format.w"
+	if((yyvsp[-2].b))(yyval.info)= (yyvsp[-1].info)	|b100;else (yyval.info)= (yyvsp[-1].info);}
+#line 2666 "parser.c"
+    break;
+
+  case 97: /* content_node: start "leaders" leaders ">"  */
+#line 549 "parser.y"
+                                      {
+	#line 3794 "format.w"
+	hput_tags((yyvsp[-3].u),TAG(leaders_kind,(yyvsp[-1].info)));}
+#line 2674 "parser.c"
+    break;
+
+  case 98: /* $@4: %empty  */
+#line 553 "parser.y"
+                  {
+	#line 3900 "format.w"
+	if((yyvsp[0].d)!=0)HPUT32((yyvsp[0].d));}
+#line 2682 "parser.c"
+    break;
+
+  case 99: /* baseline: dimension $@4 glue_node glue_node  */
+#line 556 "parser.y"
+                   {
+	#line 3901 "format.w"
+	(yyval.info)= b000;if((yyvsp[-3].d)!=0)(yyval.info)	|= b001;
+	if((yyvsp[-1].b))(yyval.info)	|= b100;
+	if((yyvsp[0].b))(yyval.info)	|= b010;
+	}
+#line 2693 "parser.c"
+    break;
+
+  case 100: /* content_node: start "baseline" baseline ">"  */
+#line 563 "parser.y"
+{
+	#line 3906 "format.w"
+	if((yyvsp[-1].info)==b000)HPUT8(0);hput_tags((yyvsp[-3].u),TAG(baseline_kind,(yyvsp[-1].info)));}
+#line 2701 "parser.c"
+    break;
+
+  case 102: /* cc_list: cc_list TXT_CC  */
+#line 567 "parser.y"
+                               {
+	#line 3989 "format.w"
+	hput_utf8((yyvsp[0].u));}
+#line 2709 "parser.c"
+    break;
+
+  case 103: /* lig_cc: UNSIGNED  */
+#line 570 "parser.y"
+               {
+	#line 3990 "format.w"
+	RNG("UTF-8 code",(yyvsp[0].u),0,0x1FFFFF);(yyval.u)= hpos-hstart;hput_utf8((yyvsp[0].u));}
+#line 2717 "parser.c"
+    break;
+
+  case 104: /* lig_cc: CHARCODE  */
+#line 573 "parser.y"
+               {
+	#line 3991 "format.w"
+	(yyval.u)= hpos-hstart;hput_utf8((yyvsp[0].u));}
+#line 2725 "parser.c"
+    break;
+
+  case 105: /* ref: REFERENCE  */
+#line 576 "parser.y"
+             {
+	#line 3992 "format.w"
+	HPUT8((yyvsp[0].u));(yyval.u)= (yyvsp[0].u);}
+#line 2733 "parser.c"
+    break;
+
+  case 106: /* $@5: %empty  */
+#line 579 "parser.y"
+            {
+	#line 3993 "format.w"
+	REF(font_kind,(yyvsp[0].u));}
+#line 2741 "parser.c"
+    break;
+
+  case 107: /* ligature: ref $@5 lig_cc TXT_START cc_list TXT_END  */
+#line 582 "parser.y"
+{
+	#line 3994 "format.w"
+	(yyval.lg).f= (yyvsp[-5].u);(yyval.lg).l.p= (yyvsp[-3].u);(yyval.lg).l.s= (hpos-hstart)-(yyvsp[-3].u);
+	RNG("Ligature size",(yyval.lg).l.s,0,255);}
+#line 2750 "parser.c"
+    break;
+
+  case 108: /* content_node: start "ligature" ligature ">"  */
+#line 586 "parser.y"
+                                        {
+	#line 3996 "format.w"
+	hput_tags((yyvsp[-3].u),hput_ligature(&((yyvsp[-1].lg))));}
+#line 2758 "parser.c"
+    break;
+
+  case 109: /* replace_count: explicit  */
+#line 590 "parser.y"
+                      {
+	#line 4106 "format.w"
+	if((yyvsp[0].b)){(yyval.u)= 0x80;HPUT8(0x80);}else (yyval.u)= 0x00;}
+#line 2766 "parser.c"
+    break;
+
+  case 110: /* replace_count: explicit UNSIGNED  */
+#line 593 "parser.y"
+                          {
+	#line 4107 "format.w"
+	RNG("Replace count",(yyvsp[0].u),0,31);
+	(yyval.u)= ((yyvsp[0].u))	|(((yyvsp[-1].b))?0x80:0x00);if((yyval.u)!=0)HPUT8((yyval.u));}
+#line 2775 "parser.c"
+    break;
+
+  case 111: /* disc: replace_count list list  */
+#line 597 "parser.y"
+                            {
+	#line 4109 "format.w"
+	(yyval.dc).r= (yyvsp[-2].u);(yyval.dc).p= (yyvsp[-1].l);(yyval.dc).q= (yyvsp[0].l);
+	if((yyvsp[0].l).s==0){hpos= hpos-2;if((yyvsp[-1].l).s==0)hpos= hpos-2;}}
+#line 2784 "parser.c"
+    break;
+
+  case 112: /* disc: replace_count list  */
+#line 601 "parser.y"
+                           {
+	#line 4111 "format.w"
+	(yyval.dc).r= (yyvsp[-1].u);(yyval.dc).p= (yyvsp[0].l);if((yyvsp[0].l).s==0)hpos= hpos-2;(yyval.dc).q.s= 0;}
+#line 2792 "parser.c"
+    break;
+
+  case 113: /* disc: replace_count  */
+#line 604 "parser.y"
+                      {
+	#line 4112 "format.w"
+	(yyval.dc).r= (yyvsp[0].u);(yyval.dc).p.s= 0;(yyval.dc).q.s= 0;}
+#line 2800 "parser.c"
+    break;
+
+  case 114: /* disc_node: start "disc" disc ">"  */
+#line 610 "parser.y"
+{
+	#line 4116 "format.w"
+	hput_tags((yyvsp[-3].u),hput_disc(&((yyvsp[-1].dc))));}
+#line 2808 "parser.c"
+    break;
+
+  case 116: /* par_dimen: xdimen  */
+#line 616 "parser.y"
+                {
+	#line 4268 "format.w"
+	hput_xdimen_node(&((yyvsp[0].xd)));}
+#line 2816 "parser.c"
+    break;
+
+  case 117: /* par: xdimen_ref param_ref list  */
+#line 619 "parser.y"
+                             {
+	#line 4269 "format.w"
+	(yyval.info)= b000;}
+#line 2824 "parser.c"
+    break;
+
+  case 118: /* par: xdimen_ref empty_param_list non_empty_param_list list  */
+#line 622 "parser.y"
+                                                              {
+	#line 4270 "format.w"
+	(yyval.info)= b010;}
+#line 2832 "parser.c"
+    break;
+
+  case 119: /* par: xdimen_ref empty_param_list list  */
+#line 625 "parser.y"
+                                         {
+	#line 4271 "format.w"
+	(yyval.info)= b010;}
+#line 2840 "parser.c"
+    break;
+
+  case 120: /* $@6: %empty  */
+#line 628 "parser.y"
+                         {
+	#line 4272 "format.w"
+	hput_xdimen_node(&((yyvsp[-1].xd)));}
+#line 2848 "parser.c"
+    break;
+
+  case 121: /* par: xdimen param_ref $@6 list  */
+#line 630 "parser.y"
+                                     {
+	#line 4272 "format.w"
+	(yyval.info)= b100;}
+#line 2856 "parser.c"
+    break;
+
+  case 122: /* par: par_dimen empty_param_list non_empty_param_list list  */
+#line 633 "parser.y"
+                                                             {
+	#line 4273 "format.w"
+	(yyval.info)= b110;}
+#line 2864 "parser.c"
+    break;
+
+  case 123: /* par: par_dimen empty_param_list list  */
+#line 636 "parser.y"
+                                        {
+	#line 4274 "format.w"
+	(yyval.info)= b110;}
+#line 2872 "parser.c"
+    break;
+
+  case 124: /* content_node: start "par" par ">"  */
+#line 640 "parser.y"
+                              {
+	#line 4276 "format.w"
+	hput_tags((yyvsp[-3].u),TAG(par_kind,(yyvsp[-1].info)));}
+#line 2880 "parser.c"
+    break;
+
+  case 125: /* math: param_ref list  */
+#line 644 "parser.y"
+                   {
+	#line 4342 "format.w"
+	(yyval.info)= b000;}
+#line 2888 "parser.c"
+    break;
+
+  case 126: /* math: param_ref list hbox_node  */
+#line 647 "parser.y"
+                                 {
+	#line 4343 "format.w"
+	(yyval.info)= b001;}
+#line 2896 "parser.c"
+    break;
+
+  case 127: /* math: param_ref hbox_node list  */
+#line 650 "parser.y"
+                                 {
+	#line 4344 "format.w"
+	(yyval.info)= b010;}
+#line 2904 "parser.c"
+    break;
+
+  case 128: /* math: empty_param_list list  */
+#line 653 "parser.y"
+                              {
+	#line 4345 "format.w"
+	(yyval.info)= b100;}
+#line 2912 "parser.c"
+    break;
+
+  case 129: /* math: empty_param_list list hbox_node  */
+#line 656 "parser.y"
+                                        {
+	#line 4346 "format.w"
+	(yyval.info)= b101;}
+#line 2920 "parser.c"
+    break;
+
+  case 130: /* math: empty_param_list hbox_node list  */
+#line 659 "parser.y"
+                                        {
+	#line 4347 "format.w"
+	(yyval.info)= b110;}
+#line 2928 "parser.c"
+    break;
+
+  case 131: /* math: empty_param_list non_empty_param_list list  */
+#line 662 "parser.y"
+                                                   {
+	#line 4348 "format.w"
+	(yyval.info)= b100;}
+#line 2936 "parser.c"
+    break;
+
+  case 132: /* math: empty_param_list non_empty_param_list list hbox_node  */
+#line 665 "parser.y"
+                                                             {
+	#line 4349 "format.w"
+	(yyval.info)= b101;}
+#line 2944 "parser.c"
+    break;
+
+  case 133: /* math: empty_param_list non_empty_param_list hbox_node list  */
+#line 668 "parser.y"
+                                                             {
+	#line 4350 "format.w"
+	(yyval.info)= b110;}
+#line 2952 "parser.c"
+    break;
+
+  case 134: /* content_node: start "math" math ">"  */
+#line 672 "parser.y"
+                                {
+	#line 4352 "format.w"
+	hput_tags((yyvsp[-3].u),TAG(math_kind,(yyvsp[-1].info)));}
+#line 2960 "parser.c"
+    break;
+
+  case 135: /* on_off: "on"  */
+#line 676 "parser.y"
+         {
+	#line 4402 "format.w"
+	(yyval.i)= 1;}
+#line 2968 "parser.c"
+    break;
+
+  case 136: /* on_off: "off"  */
+#line 678 "parser.y"
+                    {
+	#line 4402 "format.w"
+	(yyval.i)= 0;}
+#line 2976 "parser.c"
+    break;
+
+  case 137: /* math: on_off  */
+#line 681 "parser.y"
+           {
+	#line 4403 "format.w"
+	(yyval.info)= b011	|((yyvsp[0].i)<<2);}
+#line 2984 "parser.c"
+    break;
+
+  case 138: /* content_node: start "adjust" list ">"  */
+#line 685 "parser.y"
+                                  {
+	#line 4434 "format.w"
+	hput_tags((yyvsp[-3].u),TAG(adjust_kind,1));}
+#line 2992 "parser.c"
+    break;
+
+  case 139: /* span_count: UNSIGNED  */
+#line 689 "parser.y"
+                   {
+	#line 4533 "format.w"
+	(yyval.info)= hput_span_count((yyvsp[0].u));}
+#line 3000 "parser.c"
+    break;
+
+  case 140: /* content_node: start "item" content_node ">"  */
+#line 692 "parser.y"
+                                        {
+	#line 4534 "format.w"
+	hput_tags((yyvsp[-3].u),TAG(item_kind,1));}
+#line 3008 "parser.c"
+    break;
+
+  case 141: /* content_node: start "item" span_count content_node ">"  */
+#line 695 "parser.y"
+                                                   {
+	#line 4535 "format.w"
+	hput_tags((yyvsp[-4].u),TAG(item_kind,(yyvsp[-2].info)));}
+#line 3016 "parser.c"
+    break;
+
+  case 142: /* content_node: start "item" list ">"  */
+#line 698 "parser.y"
+                                {
+	#line 4536 "format.w"
+	hput_tags((yyvsp[-3].u),TAG(item_kind,b000));}
+#line 3024 "parser.c"
+    break;
+
+  case 143: /* table: "h" box_goal list list  */
+#line 702 "parser.y"
+                          {
+	#line 4538 "format.w"
+	(yyval.info)= (yyvsp[-2].info);}
+#line 3032 "parser.c"
+    break;
+
+  case 144: /* table: "v" box_goal list list  */
+#line 705 "parser.y"
+                          {
+	#line 4539 "format.w"
+	(yyval.info)= (yyvsp[-2].info)	|b010;}
+#line 3040 "parser.c"
+    break;
+
+  case 145: /* content_node: start "table" table ">"  */
+#line 709 "parser.y"
+                                  {
+	#line 4541 "format.w"
+	hput_tags((yyvsp[-3].u),TAG(table_kind,(yyvsp[-1].info)));}
+#line 3048 "parser.c"
+    break;
+
+  case 146: /* image_dimen: dimension dimension  */
+#line 713 "parser.y"
+                               {
+	#line 4629 "format.w"
+	(yyval.x).w= (yyvsp[-1].d);(yyval.x).h= (yyvsp[0].d);}
+#line 3056 "parser.c"
+    break;
+
+  case 147: /* image_dimen: %empty  */
+#line 715 "parser.y"
+                                 {
+	#line 4629 "format.w"
+	(yyval.x).w= (yyval.x).h= 0;}
+#line 3064 "parser.c"
+    break;
+
+  case 148: /* image: UNSIGNED image_dimen plus minus  */
+#line 718 "parser.y"
+                                     {
+	#line 4630 "format.w"
+	(yyval.x).w= (yyvsp[-2].x).w;(yyval.x).h= (yyvsp[-2].x).h;(yyval.x).p= (yyvsp[-1].st);(yyval.x).m= (yyvsp[0].st);RNG("Section number",(yyvsp[-3].u),3,max_section_no);(yyval.x).n= (yyvsp[-3].u);}
+#line 3072 "parser.c"
+    break;
+
+  case 149: /* content_node: start "image" image ">"  */
+#line 721 "parser.y"
+                                  {
+	#line 4631 "format.w"
+	hput_tags((yyvsp[-3].u),hput_image(&((yyvsp[-1].x))));}
+#line 3080 "parser.c"
+    break;
+
+  case 150: /* max_value: "outline" UNSIGNED  */
+#line 725 "parser.y"
+                          {
+	#line 4868 "format.w"
+	max_outline= (yyvsp[0].u);
+	RNG("max outline",max_outline,0,0xFFFF);
+	DBG(DBGDEF	|DBGLABEL,"Setting max outline to %d\n",max_outline);
+	}
+#line 3091 "parser.c"
+    break;
+
+  case 151: /* placement: "top"  */
+#line 732 "parser.y"
+             {
+	#line 4960 "format.w"
+	(yyval.i)= LABEL_TOP;}
+#line 3099 "parser.c"
+    break;
+
+  case 152: /* placement: "bot"  */
+#line 734 "parser.y"
+                            {
+	#line 4960 "format.w"
+	(yyval.i)= LABEL_BOT;}
+#line 3107 "parser.c"
+    break;
+
+  case 153: /* placement: "mid"  */
+#line 736 "parser.y"
+                            {
+	#line 4960 "format.w"
+	(yyval.i)= LABEL_MID;}
+#line 3115 "parser.c"
+    break;
+
+  case 154: /* placement: %empty  */
+#line 738 "parser.y"
+                         {
+	#line 4960 "format.w"
+	(yyval.i)= LABEL_MID;}
+#line 3123 "parser.c"
+    break;
+
+  case 155: /* content_node: "<" "label" REFERENCE placement ">"  */
+#line 742 "parser.y"
+{
+	#line 4962 "format.w"
+	hset_label((yyvsp[-2].u),(yyvsp[-1].i));}
+#line 3131 "parser.c"
+    break;
+
+  case 156: /* content_node: start "link" REFERENCE on_off ">"  */
+#line 747 "parser.y"
+{
+	#line 5220 "format.w"
+	hput_tags((yyvsp[-4].u),hput_link((yyvsp[-2].u),(yyvsp[-1].i)));}
+#line 3139 "parser.c"
+    break;
+
+  case 157: /* def_node: "<" "outline" REFERENCE integer position list ">"  */
+#line 751 "parser.y"
+                                                          {
+	#line 5350 "format.w"
+	
+	static int outline_no= -1;
+	(yyval.rf).k= outline_kind;(yyval.rf).n= (yyvsp[-4].u);
+	if((yyvsp[-1].l).s==0)QUIT("Outline with empty title in line %d",yylineno);
+	outline_no++;
+	hset_outline(outline_no,(yyvsp[-4].u),(yyvsp[-3].i),(yyvsp[-2].u));
+	}
+#line 3153 "parser.c"
+    break;
+
+  case 158: /* stream_link: ref  */
+#line 761 "parser.y"
+               {
+	#line 5765 "format.w"
+	REF_RNG(stream_kind,(yyvsp[0].u));}
+#line 3161 "parser.c"
+    break;
+
+  case 159: /* stream_link: "*"  */
+#line 763 "parser.y"
+                                                    {
+	#line 5765 "format.w"
+	HPUT8(255);}
+#line 3169 "parser.c"
+    break;
+
+  case 160: /* stream_split: stream_link stream_link UNSIGNED  */
+#line 766 "parser.y"
+                                             {
+	#line 5766 "format.w"
+	RNG("split ratio",(yyvsp[0].u),0,1000);HPUT16((yyvsp[0].u));}
+#line 3177 "parser.c"
+    break;
+
+  case 161: /* $@7: %empty  */
+#line 769 "parser.y"
+                                {
+	#line 5767 "format.w"
+	RNG("magnification factor",(yyvsp[0].u),0,1000);HPUT16((yyvsp[0].u));}
+#line 3185 "parser.c"
+    break;
+
+  case 163: /* stream_type: stream_info  */
+#line 773 "parser.y"
+                       {
+	#line 5769 "format.w"
+	(yyval.info)= 0;}
+#line 3193 "parser.c"
+    break;
+
+  case 164: /* stream_type: "first"  */
+#line 775 "parser.y"
+                      {
+	#line 5769 "format.w"
+	(yyval.info)= 1;}
+#line 3201 "parser.c"
+    break;
+
+  case 165: /* stream_type: "last"  */
+#line 777 "parser.y"
+                     {
+	#line 5769 "format.w"
+	(yyval.info)= 2;}
+#line 3209 "parser.c"
+    break;
+
+  case 166: /* stream_type: "top"  */
+#line 779 "parser.y"
+                    {
+	#line 5769 "format.w"
+	(yyval.info)= 3;}
+#line 3217 "parser.c"
+    break;
+
+  case 167: /* stream_def_node: start "stream (definition)" ref stream_type list xdimen_node glue_node list glue_node ">"  */
+#line 785 "parser.y"
+{
+	#line 5773 "format.w"
+	DEF((yyval.rf),stream_kind,(yyvsp[-7].u));hput_tags((yyvsp[-9].u),TAG(stream_kind,(yyvsp[-6].info)	|b100));}
+#line 3225 "parser.c"
+    break;
+
+  case 168: /* stream_ins_node: start "stream (definition)" ref ">"  */
+#line 790 "parser.y"
+{
+	#line 5776 "format.w"
+	RNG("Stream insertion",(yyvsp[-1].u),0,max_ref[stream_kind]);hput_tags((yyvsp[-3].u),TAG(stream_kind,b100));}
+#line 3233 "parser.c"
+    break;
+
+  case 171: /* stream: empty_param_list list  */
+#line 796 "parser.y"
+                            {
+	#line 5871 "format.w"
+	(yyval.info)= b010;}
+#line 3241 "parser.c"
+    break;
+
+  case 172: /* stream: empty_param_list non_empty_param_list list  */
+#line 799 "parser.y"
+                                                   {
+	#line 5872 "format.w"
+	(yyval.info)= b010;}
+#line 3249 "parser.c"
+    break;
+
+  case 173: /* stream: param_ref list  */
+#line 802 "parser.y"
+                       {
+	#line 5873 "format.w"
+	(yyval.info)= b000;}
+#line 3257 "parser.c"
+    break;
+
+  case 174: /* content_node: start "stream" stream_ref stream ">"  */
+#line 806 "parser.y"
+{
+	#line 5875 "format.w"
+	hput_tags((yyvsp[-4].u),TAG(stream_kind,(yyvsp[-1].info)));}
+#line 3265 "parser.c"
+    break;
+
+  case 175: /* page_priority: %empty  */
+#line 810 "parser.y"
+              {
+	#line 5978 "format.w"
+	HPUT8(1);}
+#line 3273 "parser.c"
+    break;
+
+  case 176: /* page_priority: UNSIGNED  */
+#line 813 "parser.y"
+                 {
+	#line 5979 "format.w"
+	RNG("page priority",(yyvsp[0].u),0,255);HPUT8((yyvsp[0].u));}
+#line 3281 "parser.c"
+    break;
+
+  case 179: /* $@8: %empty  */
+#line 819 "parser.y"
+           {
+	#line 5983 "format.w"
+	hput_string((yyvsp[0].s));}
+#line 3289 "parser.c"
+    break;
+
+  case 180: /* $@9: %empty  */
+#line 821 "parser.y"
+                                                          {
+	#line 5983 "format.w"
+	HPUT32((yyvsp[0].d));}
+#line 3297 "parser.c"
+    break;
+
+  case 182: /* content_node: "<" "range" REFERENCE "on" ">"  */
+#line 828 "parser.y"
+                                         {
+	#line 6095 "format.w"
+	REF(page_kind,(yyvsp[-2].u));hput_range((yyvsp[-2].u),true);}
+#line 3305 "parser.c"
+    break;
+
+  case 183: /* content_node: "<" "range" REFERENCE "off" ">"  */
+#line 831 "parser.y"
+                                      {
+	#line 6096 "format.w"
+	REF(page_kind,(yyvsp[-2].u));hput_range((yyvsp[-2].u),false);}
+#line 3313 "parser.c"
+    break;
+
+  case 185: /* $@10: %empty  */
+#line 837 "parser.y"
+                                          {
+	#line 6786 "format.w"
+	new_directory((yyvsp[0].u)+1);new_output_buffers();}
+#line 3321 "parser.c"
+    break;
+
+  case 189: /* entry: "<" "entry" UNSIGNED string ">"  */
+#line 842 "parser.y"
+{
+	#line 6789 "format.w"
+	RNG("Section number",(yyvsp[-2].u),3,max_section_no);hset_entry(&(dir[(yyvsp[-2].u)]),(yyvsp[-2].u),0,0,(yyvsp[-1].s));}
+#line 3329 "parser.c"
+    break;
+
+  case 190: /* $@11: %empty  */
+#line 846 "parser.y"
+                                    {
+	#line 7277 "format.w"
+	hput_definitions_start();}
+#line 3337 "parser.c"
+    break;
+
+  case 191: /* definition_section: "<" "definitions" $@11 max_definitions definition_list ">"  */
+#line 850 "parser.y"
+   {
+	#line 7279 "format.w"
+	hput_definitions_end();}
+#line 3345 "parser.c"
+    break;
+
+  case 194: /* max_definitions: "<" "max" max_list ">"  */
+#line 856 "parser.y"
+{
+	#line 7395 "format.w"
+		/*245:*/
+	if(max_ref[label_kind]>=0)
+	ALLOCATE(labels,max_ref[label_kind]+1,label_t);
+		/*:245*/	/*266:*/
+	if(max_outline>=0)
+	ALLOCATE(outlines,max_outline+1,outline_t);
+		/*:266*/	/*293:*/
+	ALLOCATE(page_on,max_ref[page_kind]+1,int);
+	ALLOCATE(range_pos,2*(max_ref[range_kind]+1),range_pos_t);
+		/*:293*/	/*357:*/
+	definition_bits[0][int_kind]= (1<<(MAX_INT_DEFAULT+1))-1;
+	definition_bits[0][dimen_kind]= (1<<(MAX_DIMEN_DEFAULT+1))-1;
+	definition_bits[0][xdimen_kind]= (1<<(MAX_XDIMEN_DEFAULT+1))-1;
+	definition_bits[0][glue_kind]= (1<<(MAX_GLUE_DEFAULT+1))-1;
+	definition_bits[0][baseline_kind]= (1<<(MAX_BASELINE_DEFAULT+1))-1;
+	definition_bits[0][page_kind]= (1<<(MAX_PAGE_DEFAULT+1))-1;
+	definition_bits[0][stream_kind]= (1<<(MAX_STREAM_DEFAULT+1))-1;
+	definition_bits[0][range_kind]= (1<<(MAX_RANGE_DEFAULT+1))-1;
+		/*:357*/	/*372:*/
+	ALLOCATE(hfont_name,max_ref[font_kind]+1,char*);
+		/*:372*/hput_max_definitions();}
+#line 3373 "parser.c"
+    break;
+
+  case 197: /* max_value: "font" UNSIGNED  */
+#line 882 "parser.y"
+                       {
+	#line 7399 "format.w"
+	hset_max(font_kind,(yyvsp[0].u));}
+#line 3381 "parser.c"
+    break;
+
+  case 198: /* max_value: "int" UNSIGNED  */
+#line 885 "parser.y"
+                         {
+	#line 7400 "format.w"
+	hset_max(int_kind,(yyvsp[0].u));}
+#line 3389 "parser.c"
+    break;
+
+  case 199: /* max_value: "dimen" UNSIGNED  */
+#line 888 "parser.y"
+                       {
+	#line 7401 "format.w"
+	hset_max(dimen_kind,(yyvsp[0].u));}
+#line 3397 "parser.c"
+    break;
+
+  case 200: /* max_value: "ligature" UNSIGNED  */
+#line 891 "parser.y"
+                          {
+	#line 7402 "format.w"
+	hset_max(ligature_kind,(yyvsp[0].u));}
+#line 3405 "parser.c"
+    break;
+
+  case 201: /* max_value: "disc" UNSIGNED  */
+#line 894 "parser.y"
+                      {
+	#line 7403 "format.w"
+	hset_max(disc_kind,(yyvsp[0].u));}
+#line 3413 "parser.c"
+    break;
+
+  case 202: /* max_value: "glue" UNSIGNED  */
+#line 897 "parser.y"
+                      {
+	#line 7404 "format.w"
+	hset_max(glue_kind,(yyvsp[0].u));}
+#line 3421 "parser.c"
+    break;
+
+  case 203: /* max_value: "language" UNSIGNED  */
+#line 900 "parser.y"
+                          {
+	#line 7405 "format.w"
+	hset_max(language_kind,(yyvsp[0].u));}
+#line 3429 "parser.c"
+    break;
+
+  case 204: /* max_value: "rule" UNSIGNED  */
+#line 903 "parser.y"
+                      {
+	#line 7406 "format.w"
+	hset_max(rule_kind,(yyvsp[0].u));}
+#line 3437 "parser.c"
+    break;
+
+  case 205: /* max_value: "image" UNSIGNED  */
+#line 906 "parser.y"
+                       {
+	#line 7407 "format.w"
+	hset_max(image_kind,(yyvsp[0].u));}
+#line 3445 "parser.c"
+    break;
+
+  case 206: /* max_value: "leaders" UNSIGNED  */
+#line 909 "parser.y"
+                         {
+	#line 7408 "format.w"
+	hset_max(leaders_kind,(yyvsp[0].u));}
+#line 3453 "parser.c"
+    break;
+
+  case 207: /* max_value: "baseline" UNSIGNED  */
+#line 912 "parser.y"
+                          {
+	#line 7409 "format.w"
+	hset_max(baseline_kind,(yyvsp[0].u));}
+#line 3461 "parser.c"
+    break;
+
+  case 208: /* max_value: "xdimen" UNSIGNED  */
+#line 915 "parser.y"
+                        {
+	#line 7410 "format.w"
+	hset_max(xdimen_kind,(yyvsp[0].u));}
+#line 3469 "parser.c"
+    break;
+
+  case 209: /* max_value: "param" UNSIGNED  */
+#line 918 "parser.y"
+                       {
+	#line 7411 "format.w"
+	hset_max(param_kind,(yyvsp[0].u));}
+#line 3477 "parser.c"
+    break;
+
+  case 210: /* max_value: "stream (definition)" UNSIGNED  */
+#line 921 "parser.y"
+                           {
+	#line 7412 "format.w"
+	hset_max(stream_kind,(yyvsp[0].u));}
+#line 3485 "parser.c"
+    break;
+
+  case 211: /* max_value: "page" UNSIGNED  */
+#line 924 "parser.y"
+                      {
+	#line 7413 "format.w"
+	hset_max(page_kind,(yyvsp[0].u));}
+#line 3493 "parser.c"
+    break;
+
+  case 212: /* max_value: "range" UNSIGNED  */
+#line 927 "parser.y"
+                       {
+	#line 7414 "format.w"
+	hset_max(range_kind,(yyvsp[0].u));}
+#line 3501 "parser.c"
+    break;
+
+  case 213: /* max_value: "label" UNSIGNED  */
+#line 930 "parser.y"
+                       {
+	#line 7415 "format.w"
+	hset_max(label_kind,(yyvsp[0].u));}
+#line 3509 "parser.c"
+    break;
+
+  case 214: /* def_node: start "font" ref font ">"  */
+#line 936 "parser.y"
+                       {
+	#line 7612 "format.w"
+	DEF((yyval.rf),font_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),(yyvsp[-1].info));}
+#line 3517 "parser.c"
+    break;
+
+  case 215: /* def_node: start "int" ref integer ">"  */
+#line 939 "parser.y"
+                                      {
+	#line 7613 "format.w"
+	DEF((yyval.rf),int_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),hput_int((yyvsp[-1].i)));}
+#line 3525 "parser.c"
+    break;
+
+  case 216: /* def_node: start "dimen" ref dimension ">"  */
+#line 942 "parser.y"
+                                      {
+	#line 7614 "format.w"
+	DEF((yyval.rf),dimen_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),hput_dimen((yyvsp[-1].d)));}
+#line 3533 "parser.c"
+    break;
+
+  case 217: /* def_node: start "language" ref string ">"  */
+#line 945 "parser.y"
+                                      {
+	#line 7615 "format.w"
+	DEF((yyval.rf),language_kind,(yyvsp[-2].u));hput_string((yyvsp[-1].s));hput_tags((yyvsp[-4].u),TAG(language_kind,0));}
+#line 3541 "parser.c"
+    break;
+
+  case 218: /* def_node: start "glue" ref glue ">"  */
+#line 948 "parser.y"
+                                {
+	#line 7616 "format.w"
+	DEF((yyval.rf),glue_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),hput_glue(&((yyvsp[-1].g))));}
+#line 3549 "parser.c"
+    break;
+
+  case 219: /* def_node: start "xdimen" ref xdimen ">"  */
+#line 951 "parser.y"
+                                    {
+	#line 7617 "format.w"
+	DEF((yyval.rf),xdimen_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),hput_xdimen(&((yyvsp[-1].xd))));}
+#line 3557 "parser.c"
+    break;
+
+  case 220: /* def_node: start "rule" ref rule ">"  */
+#line 954 "parser.y"
+                                {
+	#line 7618 "format.w"
+	DEF((yyval.rf),rule_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),hput_rule(&((yyvsp[-1].r))));}
+#line 3565 "parser.c"
+    break;
+
+  case 221: /* def_node: start "leaders" ref leaders ">"  */
+#line 957 "parser.y"
+                                      {
+	#line 7619 "format.w"
+	DEF((yyval.rf),leaders_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),TAG(leaders_kind,(yyvsp[-1].info)));}
+#line 3573 "parser.c"
+    break;
+
+  case 222: /* def_node: start "baseline" ref baseline ">"  */
+#line 960 "parser.y"
+                                        {
+	#line 7620 "format.w"
+	DEF((yyval.rf),baseline_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),TAG(baseline_kind,(yyvsp[-1].info)));}
+#line 3581 "parser.c"
+    break;
+
+  case 223: /* def_node: start "ligature" ref ligature ">"  */
+#line 963 "parser.y"
+                                        {
+	#line 7621 "format.w"
+	DEF((yyval.rf),ligature_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),hput_ligature(&((yyvsp[-1].lg))));}
+#line 3589 "parser.c"
+    break;
+
+  case 224: /* def_node: start "disc" ref disc ">"  */
+#line 966 "parser.y"
+                                {
+	#line 7622 "format.w"
+	DEF((yyval.rf),disc_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),hput_disc(&((yyvsp[-1].dc))));}
+#line 3597 "parser.c"
+    break;
+
+  case 225: /* def_node: start "image" ref image ">"  */
+#line 969 "parser.y"
+                                  {
+	#line 7623 "format.w"
+	DEF((yyval.rf),image_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),hput_image(&((yyvsp[-1].x))));}
+#line 3605 "parser.c"
+    break;
+
+  case 226: /* def_node: start "param" ref parameters ">"  */
+#line 972 "parser.y"
+                                       {
+	#line 7624 "format.w"
+	DEF((yyval.rf),param_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),hput_list((yyvsp[-4].u)+2,&((yyvsp[-1].l))));}
+#line 3613 "parser.c"
+    break;
+
+  case 227: /* def_node: start "page" ref page ">"  */
+#line 975 "parser.y"
+                                {
+	#line 7625 "format.w"
+	DEF((yyval.rf),page_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),TAG(page_kind,0));}
+#line 3621 "parser.c"
+    break;
+
+  case 228: /* def_node: start "int" ref ref ">"  */
+#line 980 "parser.y"
+                         {
+	#line 7644 "format.w"
+	DEF_REF((yyval.rf),int_kind,(yyvsp[-2].u),(yyvsp[-1].u));hput_tags((yyvsp[-4].u),TAG(int_kind,0));}
+#line 3629 "parser.c"
+    break;
+
+  case 229: /* def_node: start "dimen" ref ref ">"  */
+#line 983 "parser.y"
+                                {
+	#line 7645 "format.w"
+	DEF_REF((yyval.rf),dimen_kind,(yyvsp[-2].u),(yyvsp[-1].u));hput_tags((yyvsp[-4].u),TAG(dimen_kind,0));}
+#line 3637 "parser.c"
+    break;
+
+  case 230: /* def_node: start "glue" ref ref ">"  */
+#line 986 "parser.y"
+                               {
+	#line 7646 "format.w"
+	DEF_REF((yyval.rf),glue_kind,(yyvsp[-2].u),(yyvsp[-1].u));hput_tags((yyvsp[-4].u),TAG(glue_kind,0));}
+#line 3645 "parser.c"
+    break;
+
+  case 232: /* def_list: def_list def_node  */
+#line 991 "parser.y"
+                          {
+	#line 7760 "format.w"
+	check_param_def(&((yyvsp[0].rf)));}
+#line 3653 "parser.c"
+    break;
+
+  case 233: /* parameters: estimate def_list  */
+#line 994 "parser.y"
+                            {
+	#line 7761 "format.w"
+	(yyval.l).p= (yyvsp[0].u);(yyval.l).k= param_kind;(yyval.l).s= (hpos-hstart)-(yyvsp[0].u);}
+#line 3661 "parser.c"
+    break;
+
+  case 234: /* empty_param_list: position  */
+#line 998 "parser.y"
+                         {
+	#line 7782 "format.w"
+	HPUTX(2);hpos++;hput_tags((yyvsp[0].u),TAG(param_kind,1));}
+#line 3669 "parser.c"
+    break;
+
+  case 235: /* $@12: %empty  */
+#line 1001 "parser.y"
+                                {
+	#line 7783 "format.w"
+	hpos= hpos-2;}
+#line 3677 "parser.c"
+    break;
+
+  case 236: /* non_empty_param_list: start "param" $@12 parameters ">"  */
+#line 1004 "parser.y"
+{
+	#line 7784 "format.w"
+	hput_tags((yyvsp[-4].u)-2,hput_list((yyvsp[-4].u)-1,&((yyvsp[-1].l))));}
+#line 3685 "parser.c"
+    break;
+
+  case 238: /* font_head: string dimension UNSIGNED UNSIGNED  */
+#line 1012 "parser.y"
+{
+	#line 7926 "format.w"
+	uint8_t f= (yyvsp[-4].u);SET_DBIT(f,font_kind);hfont_name[f]= strdup((yyvsp[-3].s));(yyval.info)= hput_font_head(f,hfont_name[f],(yyvsp[-2].d),(yyvsp[-1].u),(yyvsp[0].u));}
+#line 3693 "parser.c"
+    break;
+
+  case 241: /* font_param: start "penalty" fref penalty ">"  */
+#line 1019 "parser.y"
+                              {
+	#line 7931 "format.w"
+	hput_tags((yyvsp[-4].u),hput_int((yyvsp[-1].i)));}
+#line 3701 "parser.c"
+    break;
+
+  case 242: /* font_param: start "kern" fref kern ">"  */
+#line 1022 "parser.y"
+                                 {
+	#line 7932 "format.w"
+	hput_tags((yyvsp[-4].u),hput_kern(&((yyvsp[-1].kt))));}
+#line 3709 "parser.c"
+    break;
+
+  case 243: /* font_param: start "ligature" fref ligature ">"  */
+#line 1025 "parser.y"
+                                         {
+	#line 7933 "format.w"
+	hput_tags((yyvsp[-4].u),hput_ligature(&((yyvsp[-1].lg))));}
+#line 3717 "parser.c"
+    break;
+
+  case 244: /* font_param: start "disc" fref disc ">"  */
+#line 1028 "parser.y"
+                                 {
+	#line 7934 "format.w"
+	hput_tags((yyvsp[-4].u),hput_disc(&((yyvsp[-1].dc))));}
+#line 3725 "parser.c"
+    break;
+
+  case 245: /* font_param: start "glue" fref glue ">"  */
+#line 1031 "parser.y"
+                                 {
+	#line 7935 "format.w"
+	hput_tags((yyvsp[-4].u),hput_glue(&((yyvsp[-1].g))));}
+#line 3733 "parser.c"
+    break;
+
+  case 246: /* font_param: start "language" fref string ">"  */
+#line 1034 "parser.y"
+                                       {
+	#line 7936 "format.w"
+	hput_string((yyvsp[-1].s));hput_tags((yyvsp[-4].u),TAG(language_kind,0));}
+#line 3741 "parser.c"
+    break;
+
+  case 247: /* font_param: start "rule" fref rule ">"  */
+#line 1037 "parser.y"
+                                 {
+	#line 7937 "format.w"
+	hput_tags((yyvsp[-4].u),hput_rule(&((yyvsp[-1].r))));}
+#line 3749 "parser.c"
+    break;
+
+  case 248: /* font_param: start "image" fref image ">"  */
+#line 1040 "parser.y"
+                                   {
+	#line 7938 "format.w"
+	hput_tags((yyvsp[-4].u),hput_image(&((yyvsp[-1].x))));}
+#line 3757 "parser.c"
+    break;
+
+  case 249: /* fref: ref  */
+#line 1044 "parser.y"
+        {
+	#line 7940 "format.w"
+	RNG("Font parameter",(yyvsp[0].u),0,MAX_FONT_PARAMS);}
+#line 3765 "parser.c"
+    break;
+
+  case 250: /* xdimen_ref: ref  */
+#line 1048 "parser.y"
+              {
+	#line 8013 "format.w"
+	REF(xdimen_kind,(yyvsp[0].u));}
+#line 3773 "parser.c"
+    break;
+
+  case 251: /* param_ref: ref  */
+#line 1051 "parser.y"
+             {
+	#line 8014 "format.w"
+	REF(param_kind,(yyvsp[0].u));}
+#line 3781 "parser.c"
+    break;
+
+  case 252: /* stream_ref: ref  */
+#line 1054 "parser.y"
+              {
+	#line 8015 "format.w"
+	REF_RNG(stream_kind,(yyvsp[0].u));}
+#line 3789 "parser.c"
+    break;
+
+  case 253: /* content_node: start "penalty" ref ">"  */
+#line 1060 "parser.y"
+                     {
+	#line 8019 "format.w"
+	REF(penalty_kind,(yyvsp[-1].u));hput_tags((yyvsp[-3].u),TAG(penalty_kind,0));}
+#line 3797 "parser.c"
+    break;
+
+  case 254: /* content_node: start "kern" explicit ref ">"  */
+#line 1064 "parser.y"
+{
+	#line 8021 "format.w"
+	REF(dimen_kind,(yyvsp[-1].u));hput_tags((yyvsp[-4].u),TAG(kern_kind,((yyvsp[-2].b))?b100:b000));}
+#line 3805 "parser.c"
+    break;
+
+  case 255: /* content_node: start "kern" explicit "xdimen" ref ">"  */
+#line 1068 "parser.y"
+{
+	#line 8023 "format.w"
+	REF(xdimen_kind,(yyvsp[-1].u));hput_tags((yyvsp[-5].u),TAG(kern_kind,((yyvsp[-3].b))?b101:b001));}
+#line 3813 "parser.c"
+    break;
+
+  case 256: /* content_node: start "glue" ref ">"  */
+#line 1071 "parser.y"
+                           {
+	#line 8024 "format.w"
+	REF(glue_kind,(yyvsp[-1].u));hput_tags((yyvsp[-3].u),TAG(glue_kind,0));}
+#line 3821 "parser.c"
+    break;
+
+  case 257: /* content_node: start "ligature" ref ">"  */
+#line 1074 "parser.y"
+                               {
+	#line 8025 "format.w"
+	REF(ligature_kind,(yyvsp[-1].u));hput_tags((yyvsp[-3].u),TAG(ligature_kind,0));}
+#line 3829 "parser.c"
+    break;
+
+  case 258: /* content_node: start "disc" ref ">"  */
+#line 1077 "parser.y"
+                           {
+	#line 8026 "format.w"
+	REF(disc_kind,(yyvsp[-1].u));hput_tags((yyvsp[-3].u),TAG(disc_kind,0));}
+#line 3837 "parser.c"
+    break;
+
+  case 259: /* content_node: start "rule" ref ">"  */
+#line 1080 "parser.y"
+                           {
+	#line 8027 "format.w"
+	REF(rule_kind,(yyvsp[-1].u));hput_tags((yyvsp[-3].u),TAG(rule_kind,0));}
+#line 3845 "parser.c"
+    break;
+
+  case 260: /* content_node: start "image" ref ">"  */
+#line 1083 "parser.y"
+                            {
+	#line 8028 "format.w"
+	REF(image_kind,(yyvsp[-1].u));hput_tags((yyvsp[-3].u),TAG(image_kind,0));}
+#line 3853 "parser.c"
+    break;
+
+  case 261: /* content_node: start "leaders" ref ">"  */
+#line 1086 "parser.y"
+                              {
+	#line 8029 "format.w"
+	REF(leaders_kind,(yyvsp[-1].u));hput_tags((yyvsp[-3].u),TAG(leaders_kind,0));}
+#line 3861 "parser.c"
+    break;
+
+  case 262: /* content_node: start "baseline" ref ">"  */
+#line 1089 "parser.y"
+                               {
+	#line 8030 "format.w"
+	REF(baseline_kind,(yyvsp[-1].u));hput_tags((yyvsp[-3].u),TAG(baseline_kind,0));}
+#line 3869 "parser.c"
+    break;
+
+  case 263: /* content_node: start "language" REFERENCE ">"  */
+#line 1092 "parser.y"
+                                     {
+	#line 8031 "format.w"
+	REF(language_kind,(yyvsp[-1].u));hput_tags((yyvsp[-3].u),hput_language((yyvsp[-1].u)));}
+#line 3877 "parser.c"
+    break;
+
+  case 264: /* glue_node: start "glue" ref ">"  */
+#line 1096 "parser.y"
+                            {
+	#line 8033 "format.w"
+	REF(glue_kind,(yyvsp[-1].u));
+	if((yyvsp[-1].u)==zero_skip_no){hpos= hpos-2;(yyval.b)= false;}
+	else{hput_tags((yyvsp[-3].u),TAG(glue_kind,0));(yyval.b)= true;}}
+#line 3887 "parser.c"
+    break;
+
+  case 265: /* $@13: %empty  */
+#line 1103 "parser.y"
+                             {
+	#line 8464 "format.w"
+	hput_content_start();}
+#line 3895 "parser.c"
+    break;
+
+  case 266: /* content_section: "<" "content" $@13 content_list ">"  */
+#line 1106 "parser.y"
+{
+	#line 8465 "format.w"
+	hput_content_end();hput_range_defs();hput_label_defs();}
+#line 3903 "parser.c"
+    break;
+
+
+#line 3907 "parser.c"
+
+      default: break;
+    }
+  /* User semantic actions sometimes alter yychar, and that requires
+     that yytoken be updated with the new translation.  We take the
+     approach of translating immediately before every use of yytoken.
+     One alternative is translating here after every semantic action,
+     but that translation would be missed if the semantic action invokes
+     YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+     if it invokes YYBACKUP.  In the case of YYABORT or YYACCEPT, an
+     incorrect destructor might then be invoked immediately.  In the
+     case of YYERROR or YYBACKUP, subsequent parser actions might lead
+     to an incorrect destructor call or verbose syntax error message
+     before the lookahead is translated.  */
+  YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+
+  *++yyvsp = yyval;
+
+  /* Now 'shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+  {
+    const int yylhs = yyr1[yyn] - YYNTOKENS;
+    const int yyi = yypgoto[yylhs] + *yyssp;
+    yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp
+               ? yytable[yyi]
+               : yydefgoto[yylhs]);
+  }
+
+  goto yynewstate;
+
+
+/*--------------------------------------.
+| yyerrlab -- here on detecting error.  |
+`--------------------------------------*/
+yyerrlab:
+  /* Make sure we have latest lookahead translation.  See comments at
+     user semantic actions for why this is necessary.  */
+  yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar);
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+      {
+        yypcontext_t yyctx
+          = {yyssp, yytoken};
+        char const *yymsgp = YY_("syntax error");
+        int yysyntax_error_status;
+        yysyntax_error_status = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
+        if (yysyntax_error_status == 0)
+          yymsgp = yymsg;
+        else if (yysyntax_error_status == -1)
+          {
+            if (yymsg != yymsgbuf)
+              YYSTACK_FREE (yymsg);
+            yymsg = YY_CAST (char *,
+                             YYSTACK_ALLOC (YY_CAST (YYSIZE_T, yymsg_alloc)));
+            if (yymsg)
+              {
+                yysyntax_error_status
+                  = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
+                yymsgp = yymsg;
+              }
+            else
+              {
+                yymsg = yymsgbuf;
+                yymsg_alloc = sizeof yymsgbuf;
+                yysyntax_error_status = YYENOMEM;
+              }
+          }
+        yyerror (yymsgp);
+        if (yysyntax_error_status == YYENOMEM)
+          YYNOMEM;
+      }
+    }
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse lookahead token after an
+         error, discard it.  */
+
+      if (yychar <= YYEOF)
+        {
+          /* Return failure if at end of input.  */
+          if (yychar == YYEOF)
+            YYABORT;
+        }
+      else
+        {
+          yydestruct ("Error: discarding",
+                      yytoken, &yylval);
+          yychar = YYEMPTY;
+        }
+    }
+
+  /* Else will try to reuse lookahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+  /* Pacify compilers when the user code never invokes YYERROR and the
+     label yyerrorlab therefore never appears in user code.  */
+  if (0)
+    YYERROR;
+  ++yynerrs;
+
+  /* Do not reclaim the symbols of the rule whose action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;      /* Each real token shifted decrements this.  */
+
+  /* Pop stack until we find a state that shifts the error token.  */
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (!yypact_value_is_default (yyn))
+        {
+          yyn += YYSYMBOL_YYerror;
+          if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror)
+            {
+              yyn = yytable[yyn];
+              if (0 < yyn)
+                break;
+            }
+        }
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+        YYABORT;
+
+
+      yydestruct ("Error: popping",
+                  YY_ACCESSING_SYMBOL (yystate), yyvsp);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+  *++yyvsp = yylval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturnlab;
+
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturnlab;
+
+
+/*-----------------------------------------------------------.
+| yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here.  |
+`-----------------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (YY_("memory exhausted"));
+  yyresult = 2;
+  goto yyreturnlab;
+
+
+/*----------------------------------------------------------.
+| yyreturnlab -- parsing is finished, clean up and return.  |
+`----------------------------------------------------------*/
+yyreturnlab:
+  if (yychar != YYEMPTY)
+    {
+      /* Make sure we have latest lookahead translation.  See comments at
+         user semantic actions for why this is necessary.  */
+      yytoken = YYTRANSLATE (yychar);
+      yydestruct ("Cleanup: discarding lookahead",
+                  yytoken, &yylval);
+    }
+  /* Do not reclaim the symbols of the rule whose action triggered
+     this YYABORT or YYACCEPT.  */
+  YYPOPSTACK (yylen);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+                  YY_ACCESSING_SYMBOL (+*yyssp), yyvsp);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+  return yyresult;
+}
+
+#line 1110 "parser.y"
+
+	/*:510*/


Property changes on: trunk/Build/source/texk/web2c/hitexdir/hiparser.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Build/source/texk/web2c/hitexdir/hiparser.h
===================================================================
--- trunk/Build/source/texk/web2c/hitexdir/hiparser.h	                        (rev 0)
+++ trunk/Build/source/texk/web2c/hitexdir/hiparser.h	2021-11-12 11:09:17 UTC (rev 61033)
@@ -0,0 +1,173 @@
+/* A Bison parser, made by GNU Bison 3.8.2.  */
+
+/* Bison interface for Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation,
+   Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+   especially those whose name start with YY_ or yy_.  They are
+   private implementation details that can be changed or removed.  */
+
+#ifndef YY_YY_PARSER_H_INCLUDED
+# define YY_YY_PARSER_H_INCLUDED
+/* Debug traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+
+/* Token kinds.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+  enum yytokentype
+  {
+    YYEMPTY = -2,
+    YYEOF = 0,                     /* "end of file"  */
+    YYerror = 256,                 /* error  */
+    YYUNDEF = 257,                 /* "invalid token"  */
+    START = 258,                   /* "<"  */
+    END = 259,                     /* ">"  */
+    GLYPH = 260,                   /* "glyph"  */
+    UNSIGNED = 261,                /* UNSIGNED  */
+    REFERENCE = 262,               /* REFERENCE  */
+    SIGNED = 263,                  /* SIGNED  */
+    STRING = 264,                  /* STRING  */
+    CHARCODE = 265,                /* CHARCODE  */
+    FPNUM = 266,                   /* FPNUM  */
+    DIMEN = 267,                   /* "dimen"  */
+    PT = 268,                      /* "pt"  */
+    MM = 269,                      /* "mm"  */
+    INCH = 270,                    /* "in"  */
+    XDIMEN = 271,                  /* "xdimen"  */
+    H = 272,                       /* "h"  */
+    V = 273,                       /* "v"  */
+    FIL = 274,                     /* "fil"  */
+    FILL = 275,                    /* "fill"  */
+    FILLL = 276,                   /* "filll"  */
+    PENALTY = 277,                 /* "penalty"  */
+    INTEGER = 278,                 /* "int"  */
+    LANGUAGE = 279,                /* "language"  */
+    RULE = 280,                    /* "rule"  */
+    RUNNING = 281,                 /* "|"  */
+    KERN = 282,                    /* "kern"  */
+    EXPLICIT = 283,                /* "!"  */
+    GLUE = 284,                    /* "glue"  */
+    PLUS = 285,                    /* "plus"  */
+    MINUS = 286,                   /* "minus"  */
+    TXT_START = 287,               /* TXT_START  */
+    TXT_END = 288,                 /* TXT_END  */
+    TXT_IGNORE = 289,              /* TXT_IGNORE  */
+    TXT_FONT_GLUE = 290,           /* TXT_FONT_GLUE  */
+    TXT_FONT_HYPHEN = 291,         /* TXT_FONT_HYPHEN  */
+    TXT_FONT = 292,                /* TXT_FONT  */
+    TXT_LOCAL = 293,               /* TXT_LOCAL  */
+    TXT_GLOBAL = 294,              /* TXT_GLOBAL  */
+    TXT_CC = 295,                  /* TXT_CC  */
+    HBOX = 296,                    /* "hbox"  */
+    VBOX = 297,                    /* "vbox"  */
+    SHIFTED = 298,                 /* "shifted"  */
+    HPACK = 299,                   /* "hpack"  */
+    HSET = 300,                    /* "hset"  */
+    VPACK = 301,                   /* "vpack"  */
+    VSET = 302,                    /* "vset"  */
+    DEPTH = 303,                   /* "depth"  */
+    ADD = 304,                     /* "add"  */
+    TO = 305,                      /* "to"  */
+    LEADERS = 306,                 /* "leaders"  */
+    ALIGN = 307,                   /* "align"  */
+    CENTER = 308,                  /* "center"  */
+    EXPAND = 309,                  /* "expand"  */
+    BASELINE = 310,                /* "baseline"  */
+    LIGATURE = 311,                /* "ligature"  */
+    DISC = 312,                    /* "disc"  */
+    PAR = 313,                     /* "par"  */
+    MATH = 314,                    /* "math"  */
+    ON = 315,                      /* "on"  */
+    OFF = 316,                     /* "off"  */
+    ADJUST = 317,                  /* "adjust"  */
+    TABLE = 318,                   /* "table"  */
+    ITEM = 319,                    /* "item"  */
+    IMAGE = 320,                   /* "image"  */
+    LABEL = 321,                   /* "label"  */
+    BOT = 322,                     /* "bot"  */
+    MID = 323,                     /* "mid"  */
+    LINK = 324,                    /* "link"  */
+    OUTLINE = 325,                 /* "outline"  */
+    STREAM = 326,                  /* "stream"  */
+    STREAMDEF = 327,               /* "stream (definition)"  */
+    FIRST = 328,                   /* "first"  */
+    LAST = 329,                    /* "last"  */
+    TOP = 330,                     /* "top"  */
+    NOREFERENCE = 331,             /* "*"  */
+    PAGE = 332,                    /* "page"  */
+    RANGE = 333,                   /* "range"  */
+    DIRECTORY = 334,               /* "directory"  */
+    SECTION = 335,                 /* "entry"  */
+    DEFINITIONS = 336,             /* "definitions"  */
+    MAX = 337,                     /* "max"  */
+    PARAM = 338,                   /* "param"  */
+    FONT = 339,                    /* "font"  */
+    CONTENT = 340                  /* "content"  */
+  };
+  typedef enum yytokentype yytoken_kind_t;
+#endif
+
+/* Value type.  */
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+union YYSTYPE
+{
+#line 79 "parser.y"
+
+	#line 10237 "format.w"
+	uint32_t u;  int32_t i;  char *s;  float64_t f;  glyph_t c;
+	dimen_t d;stretch_t st;xdimen_t xd;kern_t kt;
+	rule_t r;glue_t g;image_t x;
+	list_t l;box_t h;disc_t dc;lig_t lg;
+	ref_t rf;info_t info;order_t o;bool b;
+	
+
+#line 159 "hiparser.h"
+
+};
+typedef union YYSTYPE YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+extern YYSTYPE yylval;
+
+
+int yyparse (void);
+
+
+#endif /* !YY_YY_PARSER_H_INCLUDED  */


Property changes on: trunk/Build/source/texk/web2c/hitexdir/hiparser.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Build/source/texk/web2c/hitexdir/hiparser.y
===================================================================
--- trunk/Build/source/texk/web2c/hitexdir/hiparser.y	                        (rev 0)
+++ trunk/Build/source/texk/web2c/hitexdir/hiparser.y	2021-11-12 11:09:17 UTC (rev 61033)
@@ -0,0 +1,1111 @@
+	/*510:*/
+%{
+	#line 10212 "format.w"
+	
+#include "hibasetypes.h"
+#include <string.h>
+#include <math.h>
+#include "hierror.h"
+#include "hiformat.h"
+#include "hiput.h"
+extern char**hfont_name;
+
+	/*356:*/
+uint32_t definition_bits[0x100/32][32]= {
+	#line 7578 "format.w"
+	{0}};
+
+#define SET_DBIT(N,K) ((N)>0xFF?1:(definition_bits[N/32][K]	|= (1<<((N)&(32-1)))))
+#define GET_DBIT(N,K) ((N)>0xFF?1:((definition_bits[N/32][K]>>((N)&(32-1)))&1))
+#define DEF(D,K,N) (D).k= K; (D).n= (N);SET_DBIT((D).n,(D).k);\
+ DBG(DBGDEF,"Defining %s %d\n",definition_name[(D).k],(D).n);\
+ RNG("Definition",(D).n,max_fixed[(D).k]+1,max_ref[(D).k]);
+#define REF(K,N) REF_RNG(K,N);if(!GET_DBIT(N,K)) \
+ QUIT("Reference %d to %s before definition",(N),definition_name[K])
+	/*:356*/	/*360:*/
+#define DEF_REF(D,K,M,N)  DEF(D,K,M);\
+if ((M)>max_default[K]) QUIT("Defining non default reference %d for %s",M,definition_name[K]); \
+if ((N)>max_fixed[K]) QUIT("Defining reference %d for %s by non fixed reference %d",M,definition_name[K],N);
+	/*:360*/
+
+extern void hset_entry(entry_t*e,uint16_t i,uint32_t size,
+uint32_t xsize,char*file_name);
+
+	/*423:*/
+#ifdef DEBUG
+#define  YYDEBUG 1
+extern int yydebug;
+#else
+#define YYDEBUG 0
+#endif
+	/*:423*/
+extern int yylex(void);
+
+	/*352:*/
+void hset_max(kind_t k,int n)
+{
+	#line 7421 "format.w"
+	DBG(DBGDEF,"Setting max %s to %d\n",definition_name[k],n);
+	RNG("Maximum",n,max_fixed[k]+1,MAX_REF(k));
+	if(n>max_ref[k])
+	max_ref[k]= n;
+	}
+	/*:352*/	/*363:*/
+void check_param_def(ref_t*df)
+{
+	#line 7727 "format.w"
+	if(df->k!=int_kind&&df->k!=dimen_kind&&df->k!=glue_kind)
+	QUIT("Kind %s not allowed in parameter list",definition_name[df->k]);
+	if(df->n<=max_fixed[df->k]||max_default[df->k]<df->n)
+	QUIT("Parameter %d for %s not allowed in parameter list",df->n,definition_name[df->k]);
+	}
+	/*:363*/	/*422:*/
+extern int yylineno;
+int yyerror(const char*msg)
+{
+	#line 8799 "format.w"
+	QUIT(" in line %d %s",yylineno,msg);
+	return 0;
+	}
+	/*:422*/
+
+
+%}
+
+
+
+
+
+%union {
+	#line 10237 "format.w"
+	uint32_t u;  int32_t i;  char *s;  float64_t f;  glyph_t c;
+	dimen_t d;stretch_t st;xdimen_t xd;kern_t kt;
+	rule_t r;glue_t g;image_t x;
+	list_t l;box_t h;disc_t dc;lig_t lg;
+	ref_t rf;info_t info;order_t o;bool b;
+	}
+
+
+
+%error_verbose
+%start hint
+
+	/*2:*/
+%token START    "<"
+%token END      ">"
+%token GLYPH     "glyph"
+%token <u> UNSIGNED
+%token <u> REFERENCE
+	/*:2*/	/*4:*/
+%type <u> start
+%type <c> glyph
+	/*:4*/	/*26:*/
+%token <i> SIGNED
+%type <i> integer
+	/*:26*/	/*33:*/
+%token <s> STRING
+	/*:33*/	/*47:*/
+%token <u> CHARCODE
+	/*:47*/	/*49:*/
+%type <s> string
+	/*:49*/	/*54:*/
+%token <f> FPNUM
+%type <f> number
+	/*:54*/	/*79:*/
+%token DIMEN "dimen"
+%token PT "pt"
+%token MM "mm"
+%token INCH "in"
+%type <d> dimension
+	/*:79*/	/*87:*/
+%token XDIMEN "xdimen"
+%token H "h"
+%token V "v"
+%type <xd> xdimen
+	/*:87*/	/*98:*/
+%token FIL "fil"
+%token FILL "fill"
+%token FILLL "filll"
+%type <st> stretch
+%type <o> order
+	/*:98*/	/*102:*/
+%token PENALTY "penalty"
+%token INTEGER     "int"
+%type <i> penalty
+	/*:102*/	/*108:*/
+%token LANGUAGE "language"
+	/*:108*/	/*114:*/
+%token RULE "rule"
+%token RUNNING "|"
+%type <d> rule_dimension
+%type <r> rule
+	/*:114*/	/*123:*/
+%token KERN "kern"
+%token EXPLICIT "!"
+%type <b> explicit
+%type <kt> kern
+	/*:123*/	/*132:*/
+%token GLUE "glue"
+%token PLUS  "plus"
+%token MINUS   "minus"
+%type <g> glue
+%type <b> glue_node
+%type <st> plus minus
+	/*:132*/	/*141:*/
+%type <l>  list
+%type <u> position content_list
+	/*:141*/	/*150:*/
+%token TXT_START TXT_END TXT_IGNORE
+%token TXT_FONT_GLUE TXT_FONT_HYPHEN
+%token <u> TXT_FONT TXT_LOCAL
+%token <rf> TXT_GLOBAL
+%token <u> TXT_CC
+%type <u> text
+	/*:150*/	/*161:*/
+%token HBOX     "hbox"
+%token VBOX     "vbox"
+%token SHIFTED  "shifted"
+%type <info> box box_dimen box_shift box_glue_set
+
+	/*:161*/	/*169:*/
+%token HPACK "hpack"
+%token HSET  "hset"
+%token VPACK "vpack"
+%token VSET  "vset"
+%token DEPTH "depth"
+%token ADD "add"
+%token TO "to"
+%type <info> xbox box_goal hpack vpack
+	/*:169*/	/*174:*/
+%token LEADERS "leaders"
+%token ALIGN "align"
+%token CENTER "center"
+%token EXPAND "expand"
+%type <info> leaders
+%type <info> ltype
+	/*:174*/	/*181:*/
+%token BASELINE "baseline"
+%type <info> baseline
+	/*:181*/	/*188:*/
+%token LIGATURE     "ligature"
+%type <u>  lig_cc
+%type <lg> ligature
+%type <u> ref
+	/*:188*/	/*196:*/
+%token DISC     "disc"
+%type <dc> disc
+%type <u> replace_count
+	/*:196*/	/*204:*/
+%token PAR "par"
+%type <info> par
+	/*:204*/	/*209:*/
+%token MATH "math"
+%type <info> math
+	/*:209*/	/*214:*/
+%token ON "on"
+%token OFF "off"
+%type <i> on_off
+	/*:214*/	/*218:*/
+%token ADJUST "adjust"
+	/*:218*/	/*222:*/
+%token TABLE "table"
+%token ITEM "item"
+%type <info> table span_count
+	/*:222*/	/*229:*/
+%token IMAGE "image"
+%type <x> image image_dimen
+	/*:229*/	/*246:*/
+%token LABEL "label"
+%token BOT "bot"
+%token MID "mid"
+%type <i> placement
+	/*:246*/	/*260:*/
+%token LINK "link"
+	/*:260*/	/*270:*/
+%token OUTLINE "outline"
+	/*:270*/	/*277:*/
+%token STREAM "stream"
+%token STREAMDEF "stream (definition)"
+%token FIRST "first"
+%token LAST "last"
+%token TOP "top"
+%token NOREFERENCE "*"
+%type <info> stream_type
+%type <u> stream_ref
+%type <rf> stream_def_node
+	/*:277*/	/*283:*/
+%type <info> stream
+	/*:283*/	/*287:*/
+%token PAGE "page"
+	/*:287*/	/*295:*/
+%token RANGE "range"
+	/*:295*/	/*322:*/
+%token DIRECTORY "directory"
+%token SECTION "entry"
+	/*:322*/	/*341:*/
+%token DEFINITIONS "definitions"
+	/*:341*/	/*349:*/
+%token MAX "max"
+	/*:349*/	/*358:*/
+
+%type <rf> def_node
+	/*:358*/	/*364:*/
+%token PARAM "param"
+%type <u> def_list
+%type <l> parameters
+	/*:364*/	/*373:*/
+%token FONT     "font"
+%type <info> font font_head
+	/*:373*/	/*401:*/
+%token CONTENT "content"
+	/*:401*/
+%%
+	/*5:*/
+glyph:UNSIGNED REFERENCE{
+	#line 418 "format.w"
+	$$.c= $1;REF(font_kind,$2);$$.f= $2;};
+content_node:start GLYPH glyph END{
+	#line 419 "format.w"
+	hput_tags($1,hput_glyph(&($3)));};
+start:START{
+	#line 420 "format.w"
+	HPUTNODE;$$= (uint32_t)(hpos++-hstart);}
+	/*:5*/	/*29:*/
+integer:SIGNED	|UNSIGNED{
+	#line 941 "format.w"
+	RNG("number",$1,0,0x7FFFFFFF);};
+	/*:29*/	/*38:*/
+glyph:CHARCODE REFERENCE{
+	#line 1082 "format.w"
+	$$.c= $1;REF(font_kind,$2);$$.f= $2;};
+	/*:38*/	/*50:*/
+string:STRING	|CHARCODE{
+	#line 1187 "format.w"
+	static char s[2];
+	RNG("String element",$1,0x20,0x7E);
+	s[0]= $1;s[1]= 0;$$= s;};
+	/*:50*/	/*58:*/
+number:UNSIGNED{
+	#line 1339 "format.w"
+	$$= (float64_t)$1;}	|SIGNED{
+	#line 1339 "format.w"
+	$$= (float64_t)$1;}	|FPNUM;
+	/*:58*/	/*82:*/
+dimension:number PT{
+	#line 1682 "format.w"
+	$$= ROUND($1*ONE);RNG("Dimension",$$,-MAX_DIMEN,MAX_DIMEN);}
+	|number INCH{
+	#line 1683 "format.w"
+	$$= ROUND($1*ONE*72.27);RNG("Dimension",$$,-MAX_DIMEN,MAX_DIMEN);}
+	|number MM{
+	#line 1684 "format.w"
+	$$= ROUND($1*ONE*(72.27/25.4));RNG("Dimension",$$,-MAX_DIMEN,MAX_DIMEN);};
+	/*:82*/	/*89:*/
+xdimen:dimension number H number V{
+	#line 1762 "format.w"
+	$$.w= $1;$$.h= $2;$$.v= $4;}
+	|dimension number H{
+	#line 1763 "format.w"
+	$$.w= $1;$$.h= $2;$$.v= 0.0;}
+	|dimension number V{
+	#line 1764 "format.w"
+	$$.w= $1;$$.h= 0.0;$$.v= $2;}
+	|dimension{
+	#line 1765 "format.w"
+	$$.w= $1;$$.h= 0.0;$$.v= 0.0;};
+
+
+
+xdimen_node:start XDIMEN xdimen END{
+	#line 1769 "format.w"
+	hput_tags($1,hput_xdimen(&($3)));};
+	/*:89*/	/*100:*/
+
+order:PT{
+	#line 1947 "format.w"
+	$$= normal_o;}	|FIL{
+	#line 1947 "format.w"
+	$$= fil_o;}	|FILL{
+	#line 1947 "format.w"
+	$$= fill_o;}	|FILLL{
+	#line 1947 "format.w"
+	$$= filll_o;};
+
+stretch:number order{
+	#line 1949 "format.w"
+	$$.f= $1;$$.o= $2;};
+	/*:100*/	/*104:*/
+penalty:integer{
+	#line 2003 "format.w"
+	RNG("Penalty",$1,-20000,+20000);$$= $1;};
+content_node:start PENALTY penalty END{
+	#line 2004 "format.w"
+	hput_tags($1,hput_int($3));};
+	/*:104*/	/*116:*/
+rule_dimension:dimension	|RUNNING{
+	#line 2179 "format.w"
+	$$= RUNNING_DIMEN;};
+rule:rule_dimension rule_dimension rule_dimension
+{
+	#line 2181 "format.w"
+	$$.h= $1;$$.d= $2;$$.w= $3;
+	if($3==RUNNING_DIMEN&&($1==RUNNING_DIMEN||$2==RUNNING_DIMEN))
+	QUIT("Incompatible running dimensions 0x%x 0x%x 0x%x",$1,$2,$3);};
+rule_node:start RULE rule END{
+	#line 2184 "format.w"
+	hput_tags($1,hput_rule(&($3)));};
+content_node:rule_node;
+	/*:116*/	/*125:*/
+explicit:{
+	#line 2292 "format.w"
+	$$= false;}	|EXPLICIT{
+	#line 2292 "format.w"
+	$$= true;};
+kern:explicit xdimen{
+	#line 2293 "format.w"
+	$$.x= $1;$$.d= $2;};
+content_node:start KERN kern END{
+	#line 2294 "format.w"
+	hput_tags($1,hput_kern(&($3)));}
+	/*:125*/	/*134:*/
+plus:{
+	#line 2504 "format.w"
+	$$.f= 0.0;$$.o= 0;}	|PLUS stretch{
+	#line 2504 "format.w"
+	$$= $2;};
+minus:{
+	#line 2505 "format.w"
+	$$.f= 0.0;$$.o= 0;}	|MINUS stretch{
+	#line 2505 "format.w"
+	$$= $2;};
+glue:xdimen plus minus{
+	#line 2506 "format.w"
+	$$.w= $1;$$.p= $2;$$.m= $3;};
+content_node:start GLUE glue END{
+	#line 2507 "format.w"
+	if(ZERO_GLUE($3)){HPUT8(zero_skip_no);
+	hput_tags($1,TAG(glue_kind,0));}else hput_tags($1,hput_glue(&($3)));};
+glue_node:start GLUE glue END
+{
+	#line 2510 "format.w"
+	if(ZERO_GLUE($3)){hpos--;$$= false;}
+	else{hput_tags($1,hput_glue(&($3)));$$= true;}};
+	/*:134*/	/*142:*/
+position:{
+	#line 2786 "format.w"
+	$$= hpos-hstart;};
+content_list:position
+	|content_list content_node;
+estimate:{
+	#line 2789 "format.w"
+	hpos+= 2;}
+	|UNSIGNED{
+	#line 2790 "format.w"
+	hpos+= hsize_bytes($1)+1;};
+list:start estimate content_list END
+{
+	#line 2792 "format.w"
+	$$.k= list_kind;$$.p= $3;$$.s= (hpos-hstart)-$3;
+	hput_tags($1,hput_list($1+1,&($$)));};
+	/*:142*/	/*153:*/
+list:TXT_START position
+{
+	#line 3199 "format.w"
+	hpos+= 4;}
+text TXT_END
+{
+	#line 3201 "format.w"
+	$$.k= text_kind;$$.p= $4;$$.s= (hpos-hstart)-$4;
+	hput_tags($2,hput_list($2+1,&($$)));};
+text:position	|text txt;
+
+txt:TXT_CC{
+	#line 3205 "format.w"
+	hput_txt_cc($1);}
+	|TXT_FONT{
+	#line 3206 "format.w"
+	REF(font_kind,$1);hput_txt_font($1);}
+	|TXT_GLOBAL{
+	#line 3207 "format.w"
+	REF($1.k,$1.n);hput_txt_global(&($1));}
+	|TXT_LOCAL{
+	#line 3208 "format.w"
+	RNG("Font parameter",$1,0,11);hput_txt_local($1);}
+	|TXT_FONT_GLUE{
+	#line 3209 "format.w"
+	HPUTX(1);HPUT8(txt_glue);}
+	|TXT_FONT_HYPHEN{
+	#line 3210 "format.w"
+	HPUTX(1);HPUT8(txt_hyphen);}
+	|TXT_IGNORE{
+	#line 3211 "format.w"
+	HPUTX(1);HPUT8(txt_ignore);}
+	|{
+	#line 3212 "format.w"
+	HPUTX(1);HPUT8(txt_node);}content_node;
+	/*:153*/	/*163:*/
+
+box_dimen:dimension dimension dimension
+{
+	#line 3470 "format.w"
+	$$= hput_box_dimen($1,$2,$3);};
+box_shift:{
+	#line 3471 "format.w"
+	$$= b000;}
+	|SHIFTED dimension{
+	#line 3472 "format.w"
+	$$= hput_box_shift($2);};
+
+box_glue_set:{
+	#line 3474 "format.w"
+	$$= b000;}
+	|PLUS stretch{
+	#line 3475 "format.w"
+	$$= hput_box_glue_set(+1,$2.f,$2.o);}
+	|MINUS stretch{
+	#line 3476 "format.w"
+	$$= hput_box_glue_set(-1,$2.f,$2.o);};
+
+
+box:box_dimen box_shift box_glue_set list{
+	#line 3479 "format.w"
+	$$= $1	|$2	|$3;};
+
+hbox_node:start HBOX box END{
+	#line 3481 "format.w"
+	hput_tags($1,TAG(hbox_kind,$3));};
+vbox_node:start VBOX box END{
+	#line 3482 "format.w"
+	hput_tags($1,TAG(vbox_kind,$3));};
+content_node:hbox_node	|vbox_node;
+	/*:163*/	/*171:*/
+box_flex:plus minus{
+	#line 3663 "format.w"
+	hput_stretch(&($1));hput_stretch(&($2));};
+xbox:box_dimen box_shift box_flex xdimen_ref list{
+	#line 3664 "format.w"
+	$$= $1	|$2;}
+	|box_dimen box_shift box_flex xdimen_node list{
+	#line 3665 "format.w"
+	$$= $1	|$2	|b100;};
+
+box_goal:TO xdimen_ref{
+	#line 3667 "format.w"
+	$$= b000;}
+	|ADD xdimen_ref{
+	#line 3668 "format.w"
+	$$= b001;}
+	|TO xdimen_node{
+	#line 3669 "format.w"
+	$$= b100;}
+	|ADD xdimen_node{
+	#line 3670 "format.w"
+	$$= b101;};
+
+hpack:box_shift box_goal list{
+	#line 3672 "format.w"
+	$$= $2;};
+vpack:box_shift MAX DEPTH dimension{
+	#line 3673 "format.w"
+	HPUT32($4);}box_goal list{
+	#line 3673 "format.w"
+	$$= $1	|$6;};
+
+vxbox_node:start VSET xbox END{
+	#line 3675 "format.w"
+	hput_tags($1,TAG(vset_kind,$3));}
+	|start VPACK vpack END{
+	#line 3676 "format.w"
+	hput_tags($1,TAG(vpack_kind,$3));};
+
+
+hxbox_node:start HSET xbox END{
+	#line 3679 "format.w"
+	hput_tags($1,TAG(hset_kind,$3));}
+	|start HPACK hpack END{
+	#line 3680 "format.w"
+	hput_tags($1,TAG(hpack_kind,$3));};
+
+content_node:vxbox_node	|hxbox_node;
+	/*:171*/	/*176:*/
+ltype:{
+	#line 3790 "format.w"
+	$$= 1;}	|ALIGN{
+	#line 3790 "format.w"
+	$$= 1;}	|CENTER{
+	#line 3790 "format.w"
+	$$= 2;}	|EXPAND{
+	#line 3790 "format.w"
+	$$= 3;};
+leaders:glue_node ltype rule_node{
+	#line 3791 "format.w"
+	if($1)$$= $2	|b100;else $$= $2;}
+	|glue_node ltype hbox_node{
+	#line 3792 "format.w"
+	if($1)$$= $2	|b100;else $$= $2;}
+	|glue_node ltype vbox_node{
+	#line 3793 "format.w"
+	if($1)$$= $2	|b100;else $$= $2;};
+content_node:start LEADERS leaders END{
+	#line 3794 "format.w"
+	hput_tags($1,TAG(leaders_kind,$3));}
+	/*:176*/	/*183:*/
+baseline:dimension{
+	#line 3900 "format.w"
+	if($1!=0)HPUT32($1);}
+glue_node glue_node{
+	#line 3901 "format.w"
+	$$= b000;if($1!=0)$$	|= b001;
+	if($3)$$	|= b100;
+	if($4)$$	|= b010;
+	};
+content_node:start BASELINE baseline END
+{
+	#line 3906 "format.w"
+	if($3==b000)HPUT8(0);hput_tags($1,TAG(baseline_kind,$3));};
+	/*:183*/	/*190:*/
+cc_list:	|cc_list TXT_CC{
+	#line 3989 "format.w"
+	hput_utf8($2);};
+lig_cc:UNSIGNED{
+	#line 3990 "format.w"
+	RNG("UTF-8 code",$1,0,0x1FFFFF);$$= hpos-hstart;hput_utf8($1);};
+lig_cc:CHARCODE{
+	#line 3991 "format.w"
+	$$= hpos-hstart;hput_utf8($1);};
+ref:REFERENCE{
+	#line 3992 "format.w"
+	HPUT8($1);$$= $1;};
+ligature:ref{
+	#line 3993 "format.w"
+	REF(font_kind,$1);}lig_cc TXT_START cc_list TXT_END
+{
+	#line 3994 "format.w"
+	$$.f= $1;$$.l.p= $3;$$.l.s= (hpos-hstart)-$3;
+	RNG("Ligature size",$$.l.s,0,255);};
+content_node:start LIGATURE ligature END{
+	#line 3996 "format.w"
+	hput_tags($1,hput_ligature(&($3)));};
+	/*:190*/	/*198:*/
+replace_count:explicit{
+	#line 4106 "format.w"
+	if($1){$$= 0x80;HPUT8(0x80);}else $$= 0x00;}
+	|explicit UNSIGNED{
+	#line 4107 "format.w"
+	RNG("Replace count",$2,0,31);
+	$$= ($2)	|(($1)?0x80:0x00);if($$!=0)HPUT8($$);};
+disc:replace_count list list{
+	#line 4109 "format.w"
+	$$.r= $1;$$.p= $2;$$.q= $3;
+	if($3.s==0){hpos= hpos-2;if($2.s==0)hpos= hpos-2;}}
+	|replace_count list{
+	#line 4111 "format.w"
+	$$.r= $1;$$.p= $2;if($2.s==0)hpos= hpos-2;$$.q.s= 0;}
+	|replace_count{
+	#line 4112 "format.w"
+	$$.r= $1;$$.p.s= 0;$$.q.s= 0;};
+
+
+disc_node:start DISC disc END
+{
+	#line 4116 "format.w"
+	hput_tags($1,hput_disc(&($3)));};
+
+content_node:disc_node;
+	/*:198*/	/*206:*/
+par_dimen:xdimen{
+	#line 4268 "format.w"
+	hput_xdimen_node(&($1));};
+par:xdimen_ref param_ref list{
+	#line 4269 "format.w"
+	$$= b000;}
+	|xdimen_ref empty_param_list non_empty_param_list list{
+	#line 4270 "format.w"
+	$$= b010;}
+	|xdimen_ref empty_param_list list{
+	#line 4271 "format.w"
+	$$= b010;}
+	|xdimen param_ref{
+	#line 4272 "format.w"
+	hput_xdimen_node(&($1));}list{
+	#line 4272 "format.w"
+	$$= b100;}
+	|par_dimen empty_param_list non_empty_param_list list{
+	#line 4273 "format.w"
+	$$= b110;}
+	|par_dimen empty_param_list list{
+	#line 4274 "format.w"
+	$$= b110;};
+
+content_node:start PAR par END{
+	#line 4276 "format.w"
+	hput_tags($1,TAG(par_kind,$3));};
+	/*:206*/	/*211:*/
+math:param_ref list{
+	#line 4342 "format.w"
+	$$= b000;}
+	|param_ref list hbox_node{
+	#line 4343 "format.w"
+	$$= b001;}
+	|param_ref hbox_node list{
+	#line 4344 "format.w"
+	$$= b010;}
+	|empty_param_list list{
+	#line 4345 "format.w"
+	$$= b100;}
+	|empty_param_list list hbox_node{
+	#line 4346 "format.w"
+	$$= b101;}
+	|empty_param_list hbox_node list{
+	#line 4347 "format.w"
+	$$= b110;}
+	|empty_param_list non_empty_param_list list{
+	#line 4348 "format.w"
+	$$= b100;}
+	|empty_param_list non_empty_param_list list hbox_node{
+	#line 4349 "format.w"
+	$$= b101;}
+	|empty_param_list non_empty_param_list hbox_node list{
+	#line 4350 "format.w"
+	$$= b110;};
+
+content_node:start MATH math END{
+	#line 4352 "format.w"
+	hput_tags($1,TAG(math_kind,$3));};
+	/*:211*/	/*216:*/
+on_off:ON{
+	#line 4402 "format.w"
+	$$= 1;}	|OFF{
+	#line 4402 "format.w"
+	$$= 0;};
+math:on_off{
+	#line 4403 "format.w"
+	$$= b011	|($1<<2);};
+	/*:216*/	/*220:*/
+content_node:start ADJUST list END{
+	#line 4434 "format.w"
+	hput_tags($1,TAG(adjust_kind,1));};
+	/*:220*/	/*224:*/
+span_count:UNSIGNED{
+	#line 4533 "format.w"
+	$$= hput_span_count($1);};
+content_node:start ITEM content_node END{
+	#line 4534 "format.w"
+	hput_tags($1,TAG(item_kind,1));};
+content_node:start ITEM span_count content_node END{
+	#line 4535 "format.w"
+	hput_tags($1,TAG(item_kind,$3));};
+content_node:start ITEM list END{
+	#line 4536 "format.w"
+	hput_tags($1,TAG(item_kind,b000));};
+
+table:H box_goal list list{
+	#line 4538 "format.w"
+	$$= $2;};
+table:V box_goal list list{
+	#line 4539 "format.w"
+	$$= $2	|b010;};
+
+content_node:start TABLE table END{
+	#line 4541 "format.w"
+	hput_tags($1,TAG(table_kind,$3));};
+	/*:224*/	/*231:*/
+image_dimen:dimension dimension{
+	#line 4629 "format.w"
+	$$.w= $1;$$.h= $2;}	|{
+	#line 4629 "format.w"
+	$$.w= $$.h= 0;};
+image:UNSIGNED image_dimen plus minus{
+	#line 4630 "format.w"
+	$$.w= $2.w;$$.h= $2.h;$$.p= $3;$$.m= $4;RNG("Section number",$1,3,max_section_no);$$.n= $1;};
+content_node:start IMAGE image END{
+	#line 4631 "format.w"
+	hput_tags($1,hput_image(&($3)));}
+	/*:231*/	/*241:*/
+max_value:OUTLINE UNSIGNED{
+	#line 4868 "format.w"
+	max_outline= $2;
+	RNG("max outline",max_outline,0,0xFFFF);
+	DBG(DBGDEF	|DBGLABEL,"Setting max outline to %d\n",max_outline);
+	};
+	/*:241*/	/*248:*/
+placement:TOP{
+	#line 4960 "format.w"
+	$$= LABEL_TOP;}	|BOT{
+	#line 4960 "format.w"
+	$$= LABEL_BOT;}	|MID{
+	#line 4960 "format.w"
+	$$= LABEL_MID;}	|{
+	#line 4960 "format.w"
+	$$= LABEL_MID;};
+content_node:START LABEL REFERENCE placement END
+{
+	#line 4962 "format.w"
+	hset_label($3,$4);}
+	/*:248*/	/*262:*/
+content_node:start LINK REFERENCE on_off END
+{
+	#line 5220 "format.w"
+	hput_tags($1,hput_link($3,$4));};
+	/*:262*/	/*272:*/
+def_node:START OUTLINE REFERENCE integer position list END{
+	#line 5350 "format.w"
+	
+	static int outline_no= -1;
+	$$.k= outline_kind;$$.n= $3;
+	if($6.s==0)QUIT("Outline with empty title in line %d",yylineno);
+	outline_no++;
+	hset_outline(outline_no,$3,$4,$5);
+	};
+	/*:272*/	/*279:*/
+stream_link:ref{
+	#line 5765 "format.w"
+	REF_RNG(stream_kind,$1);}	|NOREFERENCE{
+	#line 5765 "format.w"
+	HPUT8(255);};
+stream_split:stream_link stream_link UNSIGNED{
+	#line 5766 "format.w"
+	RNG("split ratio",$3,0,1000);HPUT16($3);};
+stream_info:xdimen_node UNSIGNED{
+	#line 5767 "format.w"
+	RNG("magnification factor",$2,0,1000);HPUT16($2);}stream_split;
+
+stream_type:stream_info{
+	#line 5769 "format.w"
+	$$= 0;}	|FIRST{
+	#line 5769 "format.w"
+	$$= 1;}	|LAST{
+	#line 5769 "format.w"
+	$$= 2;}	|TOP{
+	#line 5769 "format.w"
+	$$= 3;};
+
+stream_def_node:start STREAMDEF ref stream_type
+list xdimen_node glue_node list glue_node END
+{
+	#line 5773 "format.w"
+	DEF($$,stream_kind,$3);hput_tags($1,TAG(stream_kind,$4	|b100));};
+
+stream_ins_node:start STREAMDEF ref END
+{
+	#line 5776 "format.w"
+	RNG("Stream insertion",$3,0,max_ref[stream_kind]);hput_tags($1,TAG(stream_kind,b100));};
+
+content_node:stream_def_node	|stream_ins_node;
+	/*:279*/	/*284:*/
+stream:empty_param_list list{
+	#line 5871 "format.w"
+	$$= b010;}
+	|empty_param_list non_empty_param_list list{
+	#line 5872 "format.w"
+	$$= b010;}
+	|param_ref list{
+	#line 5873 "format.w"
+	$$= b000;};
+content_node:start STREAM stream_ref stream END
+{
+	#line 5875 "format.w"
+	hput_tags($1,TAG(stream_kind,$4));};
+	/*:284*/	/*289:*/
+page_priority:{
+	#line 5978 "format.w"
+	HPUT8(1);}
+	|UNSIGNED{
+	#line 5979 "format.w"
+	RNG("page priority",$1,0,255);HPUT8($1);};
+
+stream_def_list:	|stream_def_list stream_def_node;
+
+page:string{
+	#line 5983 "format.w"
+	hput_string($1);}page_priority glue_node dimension{
+	#line 5983 "format.w"
+	HPUT32($5);}
+xdimen_node xdimen_node
+list stream_def_list;
+	/*:289*/	/*297:*/
+
+content_node:START RANGE REFERENCE ON END{
+	#line 6095 "format.w"
+	REF(page_kind,$3);hput_range($3,true);}
+	|START RANGE REFERENCE OFF END{
+	#line 6096 "format.w"
+	REF(page_kind,$3);hput_range($3,false);};
+	/*:297*/	/*308:*/
+hint:directory_section definition_section content_section;
+	/*:308*/	/*324:*/
+directory_section:START DIRECTORY UNSIGNED{
+	#line 6786 "format.w"
+	new_directory($3+1);new_output_buffers();}entry_list END;
+entry_list:	|entry_list entry;
+entry:START SECTION UNSIGNED string END
+{
+	#line 6789 "format.w"
+	RNG("Section number",$3,3,max_section_no);hset_entry(&(dir[$3]),$3,0,0,$4);};
+	/*:324*/	/*343:*/
+definition_section:START DEFINITIONS{
+	#line 7277 "format.w"
+	hput_definitions_start();}
+max_definitions definition_list
+END{
+	#line 7279 "format.w"
+	hput_definitions_end();};
+definition_list:	|definition_list def_node;
+	/*:343*/	/*351:*/
+max_definitions:START MAX max_list END
+{
+	#line 7395 "format.w"
+		/*245:*/
+	if(max_ref[label_kind]>=0)
+	ALLOCATE(labels,max_ref[label_kind]+1,label_t);
+		/*:245*/	/*266:*/
+	if(max_outline>=0)
+	ALLOCATE(outlines,max_outline+1,outline_t);
+		/*:266*/	/*293:*/
+	ALLOCATE(page_on,max_ref[page_kind]+1,int);
+	ALLOCATE(range_pos,2*(max_ref[range_kind]+1),range_pos_t);
+		/*:293*/	/*357:*/
+	definition_bits[0][int_kind]= (1<<(MAX_INT_DEFAULT+1))-1;
+	definition_bits[0][dimen_kind]= (1<<(MAX_DIMEN_DEFAULT+1))-1;
+	definition_bits[0][xdimen_kind]= (1<<(MAX_XDIMEN_DEFAULT+1))-1;
+	definition_bits[0][glue_kind]= (1<<(MAX_GLUE_DEFAULT+1))-1;
+	definition_bits[0][baseline_kind]= (1<<(MAX_BASELINE_DEFAULT+1))-1;
+	definition_bits[0][page_kind]= (1<<(MAX_PAGE_DEFAULT+1))-1;
+	definition_bits[0][stream_kind]= (1<<(MAX_STREAM_DEFAULT+1))-1;
+	definition_bits[0][range_kind]= (1<<(MAX_RANGE_DEFAULT+1))-1;
+		/*:357*/	/*372:*/
+	ALLOCATE(hfont_name,max_ref[font_kind]+1,char*);
+		/*:372*/hput_max_definitions();};
+
+max_list:	|max_list START max_value END;
+
+max_value:FONT UNSIGNED{
+	#line 7399 "format.w"
+	hset_max(font_kind,$2);}
+	|INTEGER UNSIGNED{
+	#line 7400 "format.w"
+	hset_max(int_kind,$2);}
+	|DIMEN UNSIGNED{
+	#line 7401 "format.w"
+	hset_max(dimen_kind,$2);}
+	|LIGATURE UNSIGNED{
+	#line 7402 "format.w"
+	hset_max(ligature_kind,$2);}
+	|DISC UNSIGNED{
+	#line 7403 "format.w"
+	hset_max(disc_kind,$2);}
+	|GLUE UNSIGNED{
+	#line 7404 "format.w"
+	hset_max(glue_kind,$2);}
+	|LANGUAGE UNSIGNED{
+	#line 7405 "format.w"
+	hset_max(language_kind,$2);}
+	|RULE UNSIGNED{
+	#line 7406 "format.w"
+	hset_max(rule_kind,$2);}
+	|IMAGE UNSIGNED{
+	#line 7407 "format.w"
+	hset_max(image_kind,$2);}
+	|LEADERS UNSIGNED{
+	#line 7408 "format.w"
+	hset_max(leaders_kind,$2);}
+	|BASELINE UNSIGNED{
+	#line 7409 "format.w"
+	hset_max(baseline_kind,$2);}
+	|XDIMEN UNSIGNED{
+	#line 7410 "format.w"
+	hset_max(xdimen_kind,$2);}
+	|PARAM UNSIGNED{
+	#line 7411 "format.w"
+	hset_max(param_kind,$2);}
+	|STREAMDEF UNSIGNED{
+	#line 7412 "format.w"
+	hset_max(stream_kind,$2);}
+	|PAGE UNSIGNED{
+	#line 7413 "format.w"
+	hset_max(page_kind,$2);}
+	|RANGE UNSIGNED{
+	#line 7414 "format.w"
+	hset_max(range_kind,$2);}
+	|LABEL UNSIGNED{
+	#line 7415 "format.w"
+	hset_max(label_kind,$2);};
+
+	/*:351*/	/*359:*/
+def_node:
+start FONT ref font END{
+	#line 7612 "format.w"
+	DEF($$,font_kind,$3);hput_tags($1,$4);}
+	|start INTEGER ref integer END{
+	#line 7613 "format.w"
+	DEF($$,int_kind,$3);hput_tags($1,hput_int($4));}
+	|start DIMEN ref dimension END{
+	#line 7614 "format.w"
+	DEF($$,dimen_kind,$3);hput_tags($1,hput_dimen($4));}
+	|start LANGUAGE ref string END{
+	#line 7615 "format.w"
+	DEF($$,language_kind,$3);hput_string($4);hput_tags($1,TAG(language_kind,0));}
+	|start GLUE ref glue END{
+	#line 7616 "format.w"
+	DEF($$,glue_kind,$3);hput_tags($1,hput_glue(&($4)));}
+	|start XDIMEN ref xdimen END{
+	#line 7617 "format.w"
+	DEF($$,xdimen_kind,$3);hput_tags($1,hput_xdimen(&($4)));}
+	|start RULE ref rule END{
+	#line 7618 "format.w"
+	DEF($$,rule_kind,$3);hput_tags($1,hput_rule(&($4)));}
+	|start LEADERS ref leaders END{
+	#line 7619 "format.w"
+	DEF($$,leaders_kind,$3);hput_tags($1,TAG(leaders_kind,$4));}
+	|start BASELINE ref baseline END{
+	#line 7620 "format.w"
+	DEF($$,baseline_kind,$3);hput_tags($1,TAG(baseline_kind,$4));}
+	|start LIGATURE ref ligature END{
+	#line 7621 "format.w"
+	DEF($$,ligature_kind,$3);hput_tags($1,hput_ligature(&($4)));}
+	|start DISC ref disc END{
+	#line 7622 "format.w"
+	DEF($$,disc_kind,$3);hput_tags($1,hput_disc(&($4)));}
+	|start IMAGE ref image END{
+	#line 7623 "format.w"
+	DEF($$,image_kind,$3);hput_tags($1,hput_image(&($4)));}
+	|start PARAM ref parameters END{
+	#line 7624 "format.w"
+	DEF($$,param_kind,$3);hput_tags($1,hput_list($1+2,&($4)));}
+	|start PAGE ref page END{
+	#line 7625 "format.w"
+	DEF($$,page_kind,$3);hput_tags($1,TAG(page_kind,0));};
+	/*:359*/	/*361:*/
+def_node:
+start INTEGER ref ref END{
+	#line 7644 "format.w"
+	DEF_REF($$,int_kind,$3,$4);hput_tags($1,TAG(int_kind,0));}
+	|start DIMEN ref ref END{
+	#line 7645 "format.w"
+	DEF_REF($$,dimen_kind,$3,$4);hput_tags($1,TAG(dimen_kind,0));}
+	|start GLUE ref ref END{
+	#line 7646 "format.w"
+	DEF_REF($$,glue_kind,$3,$4);hput_tags($1,TAG(glue_kind,0));};
+	/*:361*/	/*366:*/
+def_list:position
+	|def_list def_node{
+	#line 7760 "format.w"
+	check_param_def(&($2));};
+parameters:estimate def_list{
+	#line 7761 "format.w"
+	$$.p= $2;$$.k= param_kind;$$.s= (hpos-hstart)-$2;};
+	/*:366*/	/*367:*/
+empty_param_list:position{
+	#line 7782 "format.w"
+	HPUTX(2);hpos++;hput_tags($1,TAG(param_kind,1));};
+non_empty_param_list:start PARAM{
+	#line 7783 "format.w"
+	hpos= hpos-2;}parameters END
+{
+	#line 7784 "format.w"
+	hput_tags($1-2,hput_list($1-1,&($4)));};
+	/*:367*/	/*375:*/
+
+font:font_head font_param_list;
+
+font_head:string dimension UNSIGNED UNSIGNED
+{
+	#line 7926 "format.w"
+	uint8_t f= $<u>0;SET_DBIT(f,font_kind);hfont_name[f]= strdup($1);$$= hput_font_head(f,hfont_name[f],$2,$3,$4);};
+
+font_param_list:glue_node disc_node	|font_param_list font_param;
+
+font_param:
+start PENALTY fref penalty END{
+	#line 7931 "format.w"
+	hput_tags($1,hput_int($4));}
+	|start KERN fref kern END{
+	#line 7932 "format.w"
+	hput_tags($1,hput_kern(&($4)));}
+	|start LIGATURE fref ligature END{
+	#line 7933 "format.w"
+	hput_tags($1,hput_ligature(&($4)));}
+	|start DISC fref disc END{
+	#line 7934 "format.w"
+	hput_tags($1,hput_disc(&($4)));}
+	|start GLUE fref glue END{
+	#line 7935 "format.w"
+	hput_tags($1,hput_glue(&($4)));}
+	|start LANGUAGE fref string END{
+	#line 7936 "format.w"
+	hput_string($4);hput_tags($1,TAG(language_kind,0));}
+	|start RULE fref rule END{
+	#line 7937 "format.w"
+	hput_tags($1,hput_rule(&($4)));}
+	|start IMAGE fref image END{
+	#line 7938 "format.w"
+	hput_tags($1,hput_image(&($4)));};
+
+fref:ref{
+	#line 7940 "format.w"
+	RNG("Font parameter",$1,0,MAX_FONT_PARAMS);};
+	/*:375*/	/*378:*/
+xdimen_ref:ref{
+	#line 8013 "format.w"
+	REF(xdimen_kind,$1);};
+param_ref:ref{
+	#line 8014 "format.w"
+	REF(param_kind,$1);};
+stream_ref:ref{
+	#line 8015 "format.w"
+	REF_RNG(stream_kind,$1);};
+
+
+content_node:
+start PENALTY ref END{
+	#line 8019 "format.w"
+	REF(penalty_kind,$3);hput_tags($1,TAG(penalty_kind,0));}
+	|start KERN explicit ref END
+{
+	#line 8021 "format.w"
+	REF(dimen_kind,$4);hput_tags($1,TAG(kern_kind,($3)?b100:b000));}
+	|start KERN explicit XDIMEN ref END
+{
+	#line 8023 "format.w"
+	REF(xdimen_kind,$5);hput_tags($1,TAG(kern_kind,($3)?b101:b001));}
+	|start GLUE ref END{
+	#line 8024 "format.w"
+	REF(glue_kind,$3);hput_tags($1,TAG(glue_kind,0));}
+	|start LIGATURE ref END{
+	#line 8025 "format.w"
+	REF(ligature_kind,$3);hput_tags($1,TAG(ligature_kind,0));}
+	|start DISC ref END{
+	#line 8026 "format.w"
+	REF(disc_kind,$3);hput_tags($1,TAG(disc_kind,0));}
+	|start RULE ref END{
+	#line 8027 "format.w"
+	REF(rule_kind,$3);hput_tags($1,TAG(rule_kind,0));}
+	|start IMAGE ref END{
+	#line 8028 "format.w"
+	REF(image_kind,$3);hput_tags($1,TAG(image_kind,0));}
+	|start LEADERS ref END{
+	#line 8029 "format.w"
+	REF(leaders_kind,$3);hput_tags($1,TAG(leaders_kind,0));}
+	|start BASELINE ref END{
+	#line 8030 "format.w"
+	REF(baseline_kind,$3);hput_tags($1,TAG(baseline_kind,0));}
+	|start LANGUAGE REFERENCE END{
+	#line 8031 "format.w"
+	REF(language_kind,$3);hput_tags($1,hput_language($3));};
+
+glue_node:start GLUE ref END{
+	#line 8033 "format.w"
+	REF(glue_kind,$3);
+	if($3==zero_skip_no){hpos= hpos-2;$$= false;}
+	else{hput_tags($1,TAG(glue_kind,0));$$= true;}};
+
+	/*:378*/	/*403:*/
+content_section:START CONTENT{
+	#line 8464 "format.w"
+	hput_content_start();}content_list END
+{
+	#line 8465 "format.w"
+	hput_content_end();hput_range_defs();hput_label_defs();};
+	/*:403*/
+%%
+	/*:510*/


Property changes on: trunk/Build/source/texk/web2c/hitexdir/hiparser.y
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Deleted: trunk/Build/source/texk/web2c/hitexdir/hishrink-lexer.c
===================================================================
--- trunk/Build/source/texk/web2c/hitexdir/hishrink-lexer.c	2021-11-12 00:49:04 UTC (rev 61032)
+++ trunk/Build/source/texk/web2c/hitexdir/hishrink-lexer.c	2021-11-12 11:09:17 UTC (rev 61033)
@@ -1,3206 +0,0 @@
-#line 2 "shrink.lex.c"
-
-#line 4 "shrink.lex.c"
-
-#define  YY_INT_ALIGNED short int
-
-/* A lexical scanner generated by flex */
-
-/* %not-for-header */
-
-/* %if-c-only */
-/* %if-not-reentrant */
-
-/* %endif */
-/* %endif */
-/* %ok-for-header */
-
-#define FLEX_SCANNER
-#define YY_FLEX_MAJOR_VERSION 2
-#define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 37
-#if YY_FLEX_SUBMINOR_VERSION > 0
-#define FLEX_BETA
-#endif
-
-/* %if-c++-only */
-/* %endif */
-
-/* %if-c-only */
-    
-/* %endif */
-
-/* %if-c-only */
-
-/* %endif */
-
-/* First, we deal with  platform-specific or compiler-specific issues. */
-
-/* begin standard C headers. */
-/* %if-c-only */
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-/* %endif */
-
-/* %if-tables-serialization */
-/* %endif */
-/* end standard C headers. */
-
-/* %if-c-or-c++ */
-/* flex integer type definitions */
-
-#ifndef FLEXINT_H
-#define FLEXINT_H
-
-/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
-
-#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
-
-/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
- * if you want the limit (max/min) macros for int types. 
- */
-#ifndef __STDC_LIMIT_MACROS
-#define __STDC_LIMIT_MACROS 1
-#endif
-
-#include <inttypes.h>
-typedef int8_t flex_int8_t;
-typedef uint8_t flex_uint8_t;
-typedef int16_t flex_int16_t;
-typedef uint16_t flex_uint16_t;
-typedef int32_t flex_int32_t;
-typedef uint32_t flex_uint32_t;
-#else
-typedef signed char flex_int8_t;
-typedef short int flex_int16_t;
-typedef int flex_int32_t;
-typedef unsigned char flex_uint8_t; 
-typedef unsigned short int flex_uint16_t;
-typedef unsigned int flex_uint32_t;
-
-/* Limits of integral types. */
-#ifndef INT8_MIN
-#define INT8_MIN               (-128)
-#endif
-#ifndef INT16_MIN
-#define INT16_MIN              (-32767-1)
-#endif
-#ifndef INT32_MIN
-#define INT32_MIN              (-2147483647-1)
-#endif
-#ifndef INT8_MAX
-#define INT8_MAX               (127)
-#endif
-#ifndef INT16_MAX
-#define INT16_MAX              (32767)
-#endif
-#ifndef INT32_MAX
-#define INT32_MAX              (2147483647)
-#endif
-#ifndef UINT8_MAX
-#define UINT8_MAX              (255U)
-#endif
-#ifndef UINT16_MAX
-#define UINT16_MAX             (65535U)
-#endif
-#ifndef UINT32_MAX
-#define UINT32_MAX             (4294967295U)
-#endif
-
-#endif /* ! C99 */
-
-#endif /* ! FLEXINT_H */
-
-/* %endif */
-
-/* %if-c++-only */
-/* %endif */
-
-#ifdef __cplusplus
-
-/* The "const" storage-class-modifier is valid. */
-#define YY_USE_CONST
-
-#else	/* ! __cplusplus */
-
-/* C99 requires __STDC__ to be defined as 1. */
-#if defined (__STDC__)
-
-#define YY_USE_CONST
-
-#endif	/* defined (__STDC__) */
-#endif	/* ! __cplusplus */
-
-#ifdef YY_USE_CONST
-#define yyconst const
-#else
-#define yyconst
-#endif
-
-/* %not-for-header */
-
-/* Returned upon end-of-file. */
-#define YY_NULL 0
-/* %ok-for-header */
-
-/* %not-for-header */
-
-/* Promotes a possibly negative, possibly signed char to an unsigned
- * integer for use as an array index.  If the signed char is negative,
- * we want to instead treat it as an 8-bit unsigned char, hence the
- * double cast.
- */
-#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
-/* %ok-for-header */
-
-/* %if-reentrant */
-/* %endif */
-
-/* %if-not-reentrant */
-
-/* %endif */
-
-/* Enter a start condition.  This macro really ought to take a parameter,
- * but we do it the disgusting crufty way forced on us by the ()-less
- * definition of BEGIN.
- */
-#define BEGIN (yy_start) = 1 + 2 *
-
-/* Translate the current start state into a value that can be later handed
- * to BEGIN to return to the state.  The YYSTATE alias is for lex
- * compatibility.
- */
-#define YY_START (((yy_start) - 1) / 2)
-#define YYSTATE YY_START
-
-/* Action number for EOF rule of a given start state. */
-#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
-
-/* Special action meaning "start processing a new file". */
-#define YY_NEW_FILE yyrestart(yyin  )
-
-#define YY_END_OF_BUFFER_CHAR 0
-
-/* Size of default input buffer. */
-#ifndef YY_BUF_SIZE
-#define YY_BUF_SIZE 16384
-#endif
-
-/* The state buf must be large enough to hold one state per character in the main buffer.
- */
-#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
-
-#ifndef YY_TYPEDEF_YY_BUFFER_STATE
-#define YY_TYPEDEF_YY_BUFFER_STATE
-typedef struct yy_buffer_state *YY_BUFFER_STATE;
-#endif
-
-#ifndef YY_TYPEDEF_YY_SIZE_T
-#define YY_TYPEDEF_YY_SIZE_T
-typedef size_t yy_size_t;
-#endif
-
-/* %if-not-reentrant */
-extern yy_size_t yyleng;
-/* %endif */
-
-/* %if-c-only */
-/* %if-not-reentrant */
-extern FILE *yyin, *yyout;
-/* %endif */
-/* %endif */
-
-#define EOB_ACT_CONTINUE_SCAN 0
-#define EOB_ACT_END_OF_FILE 1
-#define EOB_ACT_LAST_MATCH 2
-
-    /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires
-     *       access to the local variable yy_act. Since yyless() is a macro, it would break
-     *       existing scanners that call yyless() from OUTSIDE yylex. 
-     *       One obvious solution it to make yy_act a global. I tried that, and saw
-     *       a 5% performance hit in a non-yylineno scanner, because yy_act is
-     *       normally declared as a register variable-- so it is not worth it.
-     */
-    #define  YY_LESS_LINENO(n) \
-            do { \
-                int yyl;\
-                for ( yyl = n; yyl < yyleng; ++yyl )\
-                    if ( yytext[yyl] == '\n' )\
-                        --yylineno;\
-            }while(0)
-    
-/* Return all but the first "n" matched characters back to the input stream. */
-#define yyless(n) \
-	do \
-		{ \
-		/* Undo effects of setting up yytext. */ \
-        int yyless_macro_arg = (n); \
-        YY_LESS_LINENO(yyless_macro_arg);\
-		*yy_cp = (yy_hold_char); \
-		YY_RESTORE_YY_MORE_OFFSET \
-		(yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
-		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
-		} \
-	while ( 0 )
-
-#define unput(c) yyunput( c, (yytext_ptr)  )
-
-#ifndef YY_STRUCT_YY_BUFFER_STATE
-#define YY_STRUCT_YY_BUFFER_STATE
-struct yy_buffer_state
-	{
-/* %if-c-only */
-	FILE *yy_input_file;
-/* %endif */
-
-/* %if-c++-only */
-/* %endif */
-
-	char *yy_ch_buf;		/* input buffer */
-	char *yy_buf_pos;		/* current position in input buffer */
-
-	/* Size of input buffer in bytes, not including room for EOB
-	 * characters.
-	 */
-	yy_size_t yy_buf_size;
-
-	/* Number of characters read into yy_ch_buf, not including EOB
-	 * characters.
-	 */
-	yy_size_t yy_n_chars;
-
-	/* Whether we "own" the buffer - i.e., we know we created it,
-	 * and can realloc() it to grow it, and should free() it to
-	 * delete it.
-	 */
-	int yy_is_our_buffer;
-
-	/* Whether this is an "interactive" input source; if so, and
-	 * if we're using stdio for input, then we want to use getc()
-	 * instead of fread(), to make sure we stop fetching input after
-	 * each newline.
-	 */
-	int yy_is_interactive;
-
-	/* Whether we're considered to be at the beginning of a line.
-	 * If so, '^' rules will be active on the next match, otherwise
-	 * not.
-	 */
-	int yy_at_bol;
-
-    int yy_bs_lineno; /**< The line count. */
-    int yy_bs_column; /**< The column count. */
-    
-	/* Whether to try to fill the input buffer when we reach the
-	 * end of it.
-	 */
-	int yy_fill_buffer;
-
-	int yy_buffer_status;
-
-#define YY_BUFFER_NEW 0
-#define YY_BUFFER_NORMAL 1
-	/* When an EOF's been seen but there's still some text to process
-	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
-	 * shouldn't try reading from the input source any more.  We might
-	 * still have a bunch of tokens to match, though, because of
-	 * possible backing-up.
-	 *
-	 * When we actually see the EOF, we change the status to "new"
-	 * (via yyrestart()), so that the user can continue scanning by
-	 * just pointing yyin at a new input file.
-	 */
-#define YY_BUFFER_EOF_PENDING 2
-
-	};
-#endif /* !YY_STRUCT_YY_BUFFER_STATE */
-
-/* %if-c-only Standard (non-C++) definition */
-/* %not-for-header */
-
-/* %if-not-reentrant */
-
-/* Stack of input buffers. */
-static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
-static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
-static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
-/* %endif */
-/* %ok-for-header */
-
-/* %endif */
-
-/* We provide macros for accessing buffer states in case in the
- * future we want to put the buffer states in a more general
- * "scanner state".
- *
- * Returns the top of the stack, or NULL.
- */
-#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
-                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
-                          : NULL)
-
-/* Same as previous macro, but useful when we know that the buffer stack is not
- * NULL or when we need an lvalue. For internal use only.
- */
-#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
-
-/* %if-c-only Standard (non-C++) definition */
-
-/* %if-not-reentrant */
-/* %not-for-header */
-
-/* yy_hold_char holds the character lost when yytext is formed. */
-static char yy_hold_char;
-static yy_size_t yy_n_chars;		/* number of characters read into yy_ch_buf */
-yy_size_t yyleng;
-
-/* Points to current character in buffer. */
-static char *yy_c_buf_p = (char *) 0;
-static int yy_init = 0;		/* whether we need to initialize */
-static int yy_start = 0;	/* start state number */
-
-/* Flag which is used to allow yywrap()'s to do buffer switches
- * instead of setting up a fresh yyin.  A bit of a hack ...
- */
-static int yy_did_buffer_switch_on_eof;
-/* %ok-for-header */
-
-/* %endif */
-
-void yyrestart (FILE *input_file  );
-void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer  );
-YY_BUFFER_STATE yy_create_buffer (FILE *file,int size  );
-void yy_delete_buffer (YY_BUFFER_STATE b  );
-void yy_flush_buffer (YY_BUFFER_STATE b  );
-void yypush_buffer_state (YY_BUFFER_STATE new_buffer  );
-void yypop_buffer_state (void );
-
-static void yyensure_buffer_stack (void );
-static void yy_load_buffer_state (void );
-static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file  );
-
-#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
-
-YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size  );
-YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str  );
-YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len  );
-
-/* %endif */
-
-void *yyalloc (yy_size_t  );
-void *yyrealloc (void *,yy_size_t  );
-void yyfree (void *  );
-
-#define yy_new_buffer yy_create_buffer
-
-#define yy_set_interactive(is_interactive) \
-	{ \
-	if ( ! YY_CURRENT_BUFFER ){ \
-        yyensure_buffer_stack (); \
-		YY_CURRENT_BUFFER_LVALUE =    \
-            yy_create_buffer(yyin,YY_BUF_SIZE ); \
-	} \
-	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
-	}
-
-#define yy_set_bol(at_bol) \
-	{ \
-	if ( ! YY_CURRENT_BUFFER ){\
-        yyensure_buffer_stack (); \
-		YY_CURRENT_BUFFER_LVALUE =    \
-            yy_create_buffer(yyin,YY_BUF_SIZE ); \
-	} \
-	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
-	}
-
-#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
-
-/* %% [1.0] yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here */
-/* Begin user sect3 */
-
-#define FLEX_DEBUG
-
-typedef unsigned char YY_CHAR;
-
-FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
-
-typedef int yy_state_type;
-
-extern int yylineno;
-
-int yylineno = 1;
-
-extern char *yytext;
-#define yytext_ptr yytext
-
-/* %if-c-only Standard (non-C++) definition */
-
-static yy_state_type yy_get_previous_state (void );
-static yy_state_type yy_try_NUL_trans (yy_state_type current_state  );
-static int yy_get_next_buffer (void );
-static void yy_fatal_error (yyconst char msg[]  );
-
-/* %endif */
-
-/* Done after the current pattern has been matched and before the
- * corresponding action - sets up yytext.
- */
-#define YY_DO_BEFORE_ACTION \
-	(yytext_ptr) = yy_bp; \
-/* %% [2.0] code to fiddle yytext and yyleng for yymore() goes here \ */\
-	yyleng = (size_t) (yy_cp - yy_bp); \
-	(yy_hold_char) = *yy_cp; \
-	*yy_cp = '\0'; \
-/* %% [3.0] code to copy yytext_ptr to yytext[] goes here, if %array \ */\
-	(yy_c_buf_p) = yy_cp;
-
-/* %% [4.0] data tables for the DFA and the user's section 1 definitions go here */
-#define YY_NUM_RULES 126
-#define YY_END_OF_BUFFER 127
-/* This struct is not used in this scanner,
-   but its presence is necessary. */
-struct yy_trans_info
-	{
-	flex_int32_t yy_verify;
-	flex_int32_t yy_nxt;
-	};
-static yyconst flex_int16_t yy_accept[371] =
-    {   0,
-        0,    0,    0,    0,    0,    0,  127,  125,    6,    6,
-       43,   47,   10,  125,  114,  125,    4,    4,    1,    2,
-       41,  124,  124,  124,  124,  124,  124,  124,   31,  124,
-      124,  124,  124,  124,  124,  124,  124,  124,  124,   32,
-      124,   40,   14,   15,   13,   11,   74,   74,   58,   72,
-       48,   73,   49,   50,   74,  126,  126,  126,  126,    0,
-        0,    0,    0,    0,    0,    0,    7,    5,    5,    9,
-        9,    0,    0,    0,    4,  124,  124,  124,  124,  124,
-      124,  124,  124,  124,  124,  124,  124,  124,  124,  124,
-      124,  124,   29,  124,  124,  124,  124,  124,  124,  124,
-
-       28,  124,   97,  124,  124,  124,  124,   27,  124,  124,
-      124,  124,  124,  124,  124,   86,  124,  124,  124,  124,
-       12,    0,   58,   58,    0,   59,   55,   52,   56,   60,
-       53,   54,   57,    0,    0,    0,    0,    0,    0,    0,
-        0,    0,    0,   51,   71,   75,    0,    0,   20,   20,
-       16,    0,    0,    0,    5,    0,    9,   24,    8,   85,
-      124,  124,  124,  106,  124,  124,  124,  124,  124,  124,
-      124,  124,  124,   33,  124,  124,  124,  124,  124,  124,
-      124,  124,   37,  124,  124,  124,  124,  124,  124,  124,
-      124,  124,  120,  107,  124,   98,  124,  124,   95,  124,
-
-      124,  124,  102,  124,  124,  124,  124,  124,  113,  124,
-      124,  124,  124,   59,    0,    0,    0,    0,    0,    0,
-        0,    0,    0,    0,   76,    0,   18,   17,   21,    0,
-        0,    0,    0,    0,  124,  124,  124,  124,  124,  124,
-      124,  124,  124,  124,   94,  124,   34,  124,  122,   44,
-      124,   78,  124,   82,  124,  101,   42,  124,  124,  112,
-      124,  124,  108,   96,  124,  124,  115,  124,  124,   45,
-      124,   39,  124,  124,  124,  124,   79,  124,   84,  124,
-       70,   65,   61,   66,   69,   63,   64,   62,   68,   67,
-       77,   19,   22,    0,    0,   24,   25,  124,   89,  124,
-
-      124,  124,  124,  124,   87,   26,  124,  124,   35,  111,
-        3,   81,  104,  105,  124,  124,  124,   46,  124,  121,
-      124,  116,  124,  124,  124,  100,   83,  124,   23,    0,
-       99,  124,   90,  103,  124,  124,  124,   91,  124,  124,
-      124,  124,  124,  124,  124,  110,   30,    0,   25,  124,
-      123,  124,  124,  124,   88,  124,  109,   36,  118,   80,
-       92,  124,  124,   38,   93,  124,  117,  124,  119,    0
-    } ;
-
-static yyconst flex_int32_t yy_ec[256] =
-    {   0,
-        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
-        4,    4,    2,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    5,    6,    7,    8,    8,    8,    8,    9,   10,
-       11,   12,   13,    8,   14,   15,    8,   16,   17,   17,
-       17,   17,   17,   17,   17,   18,   18,    8,    8,   19,
-        8,   20,    8,   21,   22,   22,   23,   24,   22,   25,
-       26,    8,   27,    8,   28,   29,    8,    8,    8,   30,
-        8,   31,   32,    8,    8,    8,    8,    8,    8,    8,
-        8,   33,    8,    8,   34,    8,   35,   36,   37,   38,
-
-       39,   40,   41,   42,   43,   44,   45,   46,   47,   48,
-       49,   50,   51,   52,   53,   54,   55,   56,   57,   58,
-       59,   51,    8,   60,    8,    8,    1,   61,   61,   61,
-       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
-       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
-       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
-       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
-       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
-       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
-       61,   62,   62,   62,   62,   62,   62,   62,   62,   62,
-
-       62,   62,   62,   62,   62,   62,   62,   62,   62,   62,
-       62,   62,   62,   62,   62,   62,   62,   62,   62,   62,
-       62,   62,   62,   63,   63,   63,   63,   63,   63,   63,
-       63,   63,   63,   63,   63,   63,   63,   63,   63,   64,
-       64,   64,   64,   64,   64,   64,   64,   65,   65,   65,
-       65,   65,   65,   65,   65
-    } ;
-
-static yyconst flex_int32_t yy_meta[66] =
-    {   0,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    2,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    3,    3,    3,    3,    3,    3,
-        3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
-        3,    3,    3,    3,    3,    3,    3,    3,    3,    1,
-        4,    1,    1,    1,    4
-    } ;
-
-static yyconst flex_int16_t yy_base[376] =
-    {   0,
-        0,    0,   65,  130,  194,  258,  629,  630,  630,  630,
-      630,  630,   74,   68,   64,   68,   77,   72,  630,  630,
-      630,   53,   61,   58,   59,  570,   57,  581,   65,   57,
-        0,  587,   73,   74,  100,  106,  107,  104,  112,  113,
-      587,  630,  630,  630,  630,  615,  630,  117,  148,  162,
-      630,  630,  630,  630,  322,  630,  562,  561,  560,  611,
-      610,  609,  556,  555,  554,  165,  630,  630,  107,  154,
-      162,  157,  166,  193,  170,    0,  160,  571,  560,  558,
-      563,   24,   63,  153,  560,  173,  561,  148,  559,  572,
-      567,  570,  550,  564,  550,  184,  566,  180,  168,  106,
-
-        0,  560,    0,  545,  182,  550,  542,    0,  548,  538,
-      548,  556,  549,  539,  554,  539,  539,  552,  547,  542,
-      630,  228,  233,  237,  241,  243,  247,  630,  630,  630,
-      630,  630,  630,  250,  253,  257,  263,  266,  269,  272,
-      276,  279,  282,  630,  630,  630,  523,  522,  630,  573,
-      572,  571,  518,  517,  285,  288,  299,  291,  354,    0,
-      522,  535,  536,    0,  520,  518,  518,  528,  516,  530,
-      529,  530,  531,  519,  511,  509,  523,  511,  502,  522,
-      504,  516,    0,  509,  507,  515,  512,  498,  513,  515,
-      504,  506,    0,    0,  492,    0,  500,  506,  509,  508,
-
-      489,  500,    0,  501,  485,  498,  498,  490,    0,  477,
-      497,  479,  485,  249,  357,  364,  367,  370,  375,  378,
-      388,  396,  399,  402,  630,  470,  630,  521,  630,  520,
-      467,  421,  409,  431,  474,  478,  479,  485,  476,  483,
-      473,  478,  471,  479,    0,  450,  451,  439,    0,    0,
-      450,    0,  446,    0,  451,    0,    0,  439,  429,    0,
-      444,  421,    0,    0,  421,  430,    0,  422,  416,    0,
-      422,    0,  417,  398,  416,  411,    0,  397,    0,  402,
-      630,  630,  630,  630,  630,  630,  630,  630,  630,  630,
-      630,  630,  630,  431,  315,  630,  441,  380,    0,  390,
-
-      379,  382,  380,  381,    0,    0,  356,  371,    0,    0,
-        0,    0,    0,    0,  372,  350,  346,    0,  351,    0,
-      344,    0,  340,  317,  297,    0,    0,  292,  630,  454,
-        0,  289,    0,    0,  281,  280,  279,    0,  285,  265,
-      224,  225,  203,  205,  209,    0,    0,  464,  478,  202,
-        0,  186,  172,  163,    0,  151,    0,    0,    0,    0,
-        0,  140,  100,    0,    0,  109,    0,   61,    0,  630,
-      503,  507,  511,  514,   70
-    } ;
-
-static yyconst flex_int16_t yy_def[376] =
-    {   0,
-      370,    1,  371,  371,  372,  372,  370,  370,  370,  370,
-      370,  370,  373,  374,  370,  370,  370,  370,  370,  370,
-      370,  375,  375,  375,  375,  375,  375,  375,  375,  375,
-      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
-      375,  370,  370,  370,  370,  370,  370,  370,  370,  370,
-      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
-      370,  370,  370,  370,  370,  374,  370,  370,  370,  370,
-      370,  370,  370,  370,  370,  375,  375,  375,  375,  375,
-      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
-      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
-
-      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
-      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
-      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
-      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
-      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
-      370,  370,  370,  370,  370,  370,  370,  370,  370,  375,
-      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
-      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
-      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
-      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
-
-      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
-      375,  375,  375,  370,  370,  370,  370,  370,  370,  370,
-      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
-      370,  370,  370,  370,  375,  375,  375,  375,  375,  375,
-      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
-      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
-      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
-      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
-      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
-      370,  370,  370,  370,  370,  370,  370,  375,  375,  375,
-
-      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
-      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
-      375,  375,  375,  375,  375,  375,  375,  375,  370,  370,
-      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
-      375,  375,  375,  375,  375,  375,  375,  370,  370,  375,
-      375,  375,  375,  375,  375,  375,  375,  375,  375,  375,
-      375,  375,  375,  375,  375,  375,  375,  375,  375,    0,
-      370,  370,  370,  370,  370
-    } ;
-
-static yyconst flex_int16_t yy_nxt[696] =
-    {   0,
-        8,    9,   10,    9,    9,   11,   12,    8,   13,   14,
-        8,   15,   16,   16,    8,   17,   18,   18,   19,   20,
-        8,    8,    8,    8,    8,    8,    8,    8,    8,    8,
-        8,    8,    8,   21,   22,   23,   24,   25,   26,   27,
-       28,   29,   30,   31,   32,   33,   34,   31,   35,   36,
-       31,   37,   38,   39,   31,   40,   31,   41,   31,   42,
-        8,    8,    8,    8,    8,   43,   43,   44,   43,  166,
-       67,  167,   76,   46,   60,   60,   60,   60,   67,   68,
-       69,   69,   62,   70,   71,   71,   72,   75,   75,   75,
-       77,   72,   73,   73,   73,   79,   81,   83,   78,   86,
-
-       89,   84,  168,   92,   93,   87,   82,   96,   99,   80,
-       94,   97,  169,  369,   90,   98,  100,   91,  122,  123,
-      101,  122,  155,  155,  155,   43,   43,   43,   43,   43,
-       43,   43,   44,   43,   74,   63,   64,   65,   46,  102,
-      105,  109,  112,  194,  106,  113,  115,  103,  117,  124,
-      123,  107,  124,  195,  104,  110,  368,  114,  367,  108,
-      116,  111,  118,  122,  123,  119,  122,   67,   72,   73,
-       73,   73,  158,  158,  158,   67,   72,  157,  157,  157,
-       72,   73,   73,   73,   72,   75,   75,   75,  366,  365,
-       43,   43,   43,   43,   43,   48,   49,  160,   50,  170,
-
-       51,  364,  177,  161,  171,  172,  178,   52,  159,  159,
-      159,  156,   53,   54,  159,  159,  159,  159,  174,  186,
-      190,  192,  198,  363,  175,  193,   55,  191,  362,  122,
-      123,  187,  122,  199,  124,  123,  188,  124,  124,  123,
-      361,  124,  125,  126,  214,  125,  360,  214,  125,  126,
-      214,  125,  359,  214,   56,   57,   58,   59,   56,   48,
-       49,  358,   50,  357,   51,  215,  215,  215,  216,  216,
-      216,   52,  217,  217,  217,  356,   53,   54,  218,  218,
-      218,  219,  219,  219,  220,  220,  220,  221,  221,  221,
-       55,  222,  222,  222,  223,  223,  223,  224,  224,  224,
-
-      155,  155,  155,  232,  232,  232,  158,  158,  158,  232,
-      232,  232,  232,   72,  157,  157,  157,  355,   56,   57,
-       58,   59,   56,  125,  126,  354,  127,  353,  128,  233,
-      296,  296,  296,  352,  351,  129,  350,  130,  130,  347,
-      131,  132,  133,  346,  134,  135,  136,  137,  138,  139,
-      140,  141,  142,  143,  144,  345,  145,  145,  145,  145,
-      145,  145,  145,  145,  145,  145,  145,  145,  234,  159,
-      159,  159,  215,  215,  215,  159,  159,  159,  159,  216,
-      216,  216,  217,  217,  217,  218,  218,  218,  344,  281,
-      219,  219,  219,  220,  220,  220,  282,  343,  342,  283,
-
-      341,  340,  284,  221,  221,  221,  339,  285,  338,  337,
-      286,  222,  222,  222,  223,  223,  223,  224,  224,  224,
-      287,  295,  295,  336,  296,  296,  296,  335,  288,  334,
-      333,  289,  332,  331,  290,  234,  232,  232,  232,  329,
-      328,  327,  232,  232,  232,  232,  297,  297,  297,  326,
-      325,  324,  297,  297,  297,  297,  297,  297,  297,  323,
-      322,  321,  297,  297,  297,  297,  348,  348,  320,  349,
-      349,  349,  319,  318,  317,  349,  349,  349,  349,  349,
-      349,  349,  316,  315,  314,  349,  349,  349,  349,  313,
-      312,  311,  310,  349,  349,  349,  309,  308,  330,  349,
-
-      349,  349,  349,   45,   45,   45,   45,   47,   47,   47,
-       47,   61,   61,   61,   66,  307,   66,   66,  306,  305,
-      304,  303,  302,  301,  300,  299,  298,  294,  293,  292,
-      291,  280,  279,  278,  277,  276,  275,  274,  273,  272,
-      271,  270,  269,  268,  267,  266,  265,  264,  263,  262,
-      261,  260,  259,  258,  257,  256,  255,  254,  253,  252,
-      251,  250,  249,  248,  247,  246,  245,  244,  243,  242,
-      241,  240,  239,  238,  237,  236,  235,  231,  230,  229,
-      228,  227,  226,  225,  213,  212,  211,  210,  209,  208,
-      207,  206,  205,  204,  203,  202,  201,  200,  197,  196,
-
-      189,  185,  184,  183,  182,  181,  180,  179,  176,  173,
-      165,  164,  163,  162,  154,  153,  152,  151,  150,  149,
-      148,  147,  146,  121,  120,   95,   88,   85,  370,    7,
-      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
-      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
-      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
-      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
-      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
-      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
-      370,  370,  370,  370,  370
-
-    } ;
-
-static yyconst flex_int16_t yy_chk[696] =
-    {   0,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    3,    3,    3,    3,   82,
-       14,   82,  375,    3,   13,   13,   13,   13,   14,   15,
-       15,   15,   13,   16,   16,   16,   18,   18,   18,   18,
-       22,   17,   17,   17,   17,   23,   24,   25,   22,   27,
-
-       29,   25,   83,   30,   30,   27,   24,   33,   34,   23,
-       30,   33,   83,  368,   29,   33,   34,   29,   48,   48,
-       34,   48,   69,   69,   69,    3,    3,    3,    3,    3,
-        4,    4,    4,    4,   17,   13,   13,   13,    4,   35,
-       36,   37,   38,  100,   36,   38,   39,   35,   40,   49,
-       49,   36,   49,  100,   35,   37,  366,   38,  363,   36,
-       39,   37,   40,   50,   50,   40,   50,   66,   70,   70,
-       70,   70,   72,   72,   72,   66,   71,   71,   71,   71,
-       73,   73,   73,   73,   75,   75,   75,   75,  362,  356,
-        4,    4,    4,    4,    4,    5,    5,   77,    5,   84,
-
-        5,  354,   88,   77,   84,   84,   88,    5,   74,   74,
-       74,   70,    5,    5,   74,   74,   74,   74,   86,   96,
-       98,   99,  105,  353,   86,   99,    5,   98,  352,  122,
-      122,   96,  122,  105,  123,  123,   96,  123,  124,  124,
-      350,  124,  125,  125,  126,  125,  345,  126,  127,  127,
-      214,  127,  344,  214,    5,    5,    5,    5,    5,    6,
-        6,  343,    6,  342,    6,  134,  134,  134,  135,  135,
-      135,    6,  136,  136,  136,  341,    6,    6,  137,  137,
-      137,  138,  138,  138,  139,  139,  139,  140,  140,  140,
-        6,  141,  141,  141,  142,  142,  142,  143,  143,  143,
-
-      155,  155,  155,  156,  156,  156,  158,  158,  158,  156,
-      156,  156,  156,  157,  157,  157,  157,  340,    6,    6,
-        6,    6,    6,   55,   55,  339,   55,  337,   55,  158,
-      295,  295,  295,  336,  335,   55,  332,   55,   55,  328,
-       55,   55,   55,  325,   55,   55,   55,   55,   55,   55,
-       55,   55,   55,   55,   55,  324,   55,   55,   55,   55,
-       55,   55,   55,   55,   55,   55,   55,   55,  159,  159,
-      159,  159,  215,  215,  215,  159,  159,  159,  159,  216,
-      216,  216,  217,  217,  217,  218,  218,  218,  323,  215,
-      219,  219,  219,  220,  220,  220,  216,  321,  319,  217,
-
-      317,  316,  218,  221,  221,  221,  315,  219,  308,  307,
-      220,  222,  222,  222,  223,  223,  223,  224,  224,  224,
-      221,  233,  233,  304,  233,  233,  233,  303,  222,  302,
-      301,  223,  300,  298,  224,  232,  232,  232,  232,  294,
-      280,  278,  232,  232,  232,  232,  234,  234,  234,  276,
-      275,  274,  234,  234,  234,  234,  297,  297,  297,  273,
-      271,  269,  297,  297,  297,  297,  330,  330,  268,  330,
-      330,  330,  266,  265,  262,  330,  330,  330,  330,  348,
-      348,  348,  261,  259,  258,  348,  348,  348,  348,  255,
-      253,  251,  248,  349,  349,  349,  247,  246,  297,  349,
-
-      349,  349,  349,  371,  371,  371,  371,  372,  372,  372,
-      372,  373,  373,  373,  374,  244,  374,  374,  243,  242,
-      241,  240,  239,  238,  237,  236,  235,  231,  230,  228,
-      226,  213,  212,  211,  210,  208,  207,  206,  205,  204,
-      202,  201,  200,  199,  198,  197,  195,  192,  191,  190,
-      189,  188,  187,  186,  185,  184,  182,  181,  180,  179,
-      178,  177,  176,  175,  174,  173,  172,  171,  170,  169,
-      168,  167,  166,  165,  163,  162,  161,  154,  153,  152,
-      151,  150,  148,  147,  120,  119,  118,  117,  116,  115,
-      114,  113,  112,  111,  110,  109,  107,  106,  104,  102,
-
-       97,   95,   94,   93,   92,   91,   90,   89,   87,   85,
-       81,   80,   79,   78,   65,   64,   63,   62,   61,   60,
-       59,   58,   57,   46,   41,   32,   28,   26,    7,  370,
-      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
-      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
-      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
-      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
-      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
-      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
-      370,  370,  370,  370,  370
-
-    } ;
-
-/* Table of booleans, true if rule could match eol. */
-static yyconst flex_int32_t yy_rule_can_match_eol[127] =
-    {   0,
-0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 
-    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0,     };
-
-static yy_state_type yy_last_accepting_state;
-static char *yy_last_accepting_cpos;
-
-extern int yy_flex_debug;
-int yy_flex_debug = 1;
-
-static yyconst flex_int16_t yy_rule_linenum[126] =
-    {   0,
-      170,  171,  172,  173,  174,  175,  176,  178,  180,  182,
-      184,  185,  186,  187,  188,  193,  194,  195,  196,  197,
-      198,  199,  200,  202,  204,  206,  207,  208,  209,  211,
-      212,  213,  215,  216,  217,  219,  220,  222,  224,  225,
-      226,  228,  229,  231,  232,  233,  235,  238,  240,  241,
-      243,  244,  245,  246,  247,  248,  249,  251,  252,  254,
-      256,  257,  258,  259,  260,  261,  262,  263,  264,  267,
-      269,  270,  271,  273,  274,  275,  276,  279,  280,  281,
-      283,  284,  285,  286,  287,  288,  289,  291,  292,  293,
-      294,  296,  298,  300,  302,  304,  306,  307,  309,  311,
-
-      312,  313,  314,  316,  318,  319,  320,  322,  324,  326,
-      327,  328,  329,  330,  332,  334,  336,  337,  339,  341,
-      343,  345,  347,  349,  350
-    } ;
-
-/* The intent behind this definition is that it'll catch
- * any uses of REJECT which flex missed.
- */
-#define REJECT reject_used_but_not_detected
-#define yymore() yymore_used_but_not_detected
-#define YY_MORE_ADJ 0
-#define YY_RESTORE_YY_MORE_OFFSET
-char *yytext;
-#line 1 "shrink.l"
-/*509:*/
-#line 3 "shrink.l"
-	#line 10175 "format.w"
-	
-#include "basetypes.h"
-#include "error.h"
-#include "hformat.h"
-#include "hput.h"
-
-	/*423:*/
-#ifdef DEBUG
-#define  YYDEBUG 1
-extern int yydebug;
-#else
-#define YYDEBUG 0
-#endif
-	/*:423*/
-#include "hishrink-parser.h"
-
-	/*22:*/
-#define SCAN_UDEC(S) yylval.u= strtoul(S,NULL,10)
-	/*:22*/	/*25:*/
-#define SCAN_HEX(S) yylval.u= strtoul(S,NULL,16)
-	/*:25*/	/*28:*/
-#define SCAN_DEC(S) yylval.i= strtol(S,NULL,10)
-	/*:28*/	/*31:*/
-#define MAX_STR    (1<<10) 
-static char str_buffer[MAX_STR];
-static int str_length;
-#define STR_START      (str_length= 0)
-#define STR_PUT(C) (str_buffer[str_length++]= (C))
-#define STR_ADD(C) STR_PUT(C);RNG("String length",str_length,0,MAX_STR-1)
-#define STR_END        str_buffer[str_length]= 0
-#define SCAN_STR       yylval.s= str_buffer
-	/*:31*/	/*40:*/
-#define SCAN_UTF8_1(S)   yylval.u= ((S)[0]&0x7F)
-	/*:40*/	/*42:*/
-#define SCAN_UTF8_2(S)   yylval.u= (((S)[0]&0x1F)<<6)+((S)[1]&0x3F)
-	/*:42*/	/*44:*/
-#define SCAN_UTF8_3(S)   yylval.u= (((S)[0]&0x0F)<<12)+(((S)[1]&0x3F)<<6)+((S)[2]&0x3F)
-	/*:44*/	/*46:*/
-#define SCAN_UTF8_4(S)   yylval.u= (((S)[0]&0x03)<<18)+(((S)[1]&0x3F)<<12)+(((S)[2]&0x3F)<<6)+((S)[3]&0x3F)
-	/*:46*/	/*57:*/
-#define SCAN_DECFLOAT       yylval.f= atof(yytext)
-	/*:57*/	/*60:*/
-#define SCAN_HEXFLOAT       yylval.f= xtof(yytext)
-	/*:60*/	/*152:*/
-#define SCAN_REF(K) yylval.rf.k= K; yylval.rf.n= atoi(yytext+2)
-static int scan_level= 0;
-#define SCAN_START          yy_push_state(INITIAL);if (1==scan_level++) hpos0= hpos;
-#define SCAN_END            if (scan_level--) yy_pop_state(); else QUIT("Too many '>' in line %d",yylineno)
-#define SCAN_TXT_START      BEGIN(TXT)
-#define SCAN_TXT_END        BEGIN(INITIAL)
-	/*:152*/
-	/*61:*/
-
-float64_t xtof(char*x)
-{
-	#line 1369 "format.w"
-	int sign,digits,exp;
-	uint64_t mantissa= 0;
-	DBG(DBGFLOAT,"converting %s:\n",x);
-		/*62:*/
-	if(*x=='-'){sign= -1;x++;}
-	else if(*x=='+'){sign= +1;x++;}
-	else sign= +1;
-	DBG(DBGFLOAT,"\tsign=%d\n",sign);
-		/*:62*/
-	x= x+2;
-		/*63:*/
-	digits= 0;
-	while(*x=='0')x++;
-	while(*x!='.')
-	{mantissa= mantissa<<4;
-	if(*x<'A')mantissa= mantissa+*x-'0';
-	else mantissa= mantissa+*x-'A'+10;
-	x++;
-	digits++;
-	}
-	x++;
-	exp= 0;
-	while(*x!=0&&*x!='x')
-	{mantissa= mantissa<<4;
-	exp= exp-4;
-	if(*x<'A')mantissa= mantissa+*x-'0';
-	else mantissa= mantissa+*x-'A'+10;
-	x++;
-	digits++;
-	}
-	DBG(DBGFLOAT,"\tdigits=%d mantissa=0x%"PRIx64", exp=%d\n",digits,mantissa,exp);
-		/*:63*/
-		/*64:*/
-	if(mantissa==0)return 0.0;
-	{int s;
-	s= digits-DBL_M_BITS/4;
-	if(s>1)
-	mantissa= mantissa>>(4*(s-1));
-	else if(s<1)
-	mantissa= mantissa<<(4*(1-s));
-	exp= exp+4*(digits-1);
-	DBG(DBGFLOAT,"\tdigits=%d mantissa=0x%"PRIx64", exp=%d\n",digits,mantissa,exp);
-	while((mantissa>>DBL_M_BITS)>1){mantissa= mantissa>>1;exp++;}
-	DBG(DBGFLOAT,"\tdigits=%d mantissa=0x%"PRIx64", exp=%d\n",digits,mantissa,exp);
-	mantissa= mantissa&~((uint64_t)1<<DBL_M_BITS);
-	DBG(DBGFLOAT,"\tdigits=%d mantissa=0x%"PRIx64", exp=%d\n",digits,mantissa,exp);
-	}
-		/*:64*/
-		/*65:*/
-	if(*x=='x')
-	{int s;
-	x++;
-	if(*x=='-'){s= -1;x++;}
-	else if(*x=='+'){s= +1;x++;}
-	else s= +1;
-	DBG(DBGFLOAT,"\texpsign=%d\n",s);
-	DBG(DBGFLOAT,"\texp=%d\n",exp);
-	while(*x!=0)
-	{if(*x<'A')exp= exp+4*s*(*x-'0');
-	else exp= exp+4*s*(*x-'A'+10);
-	x++;
-	DBG(DBGFLOAT,"\texp=%d\n",exp);
-	}
-	}
-	RNG("Floating point exponent",exp,-DBL_EXCESS,DBL_EXCESS);
-		/*:65*/
-		/*66:*/
-	{union{float64_t d;uint64_t bits;}u;
-	if(sign<0)sign= 1;else sign= 0;
-	exp= exp+DBL_EXCESS;
-	u.bits= ((uint64_t)sign<<63)
-		|((uint64_t)exp<<DBL_M_BITS)	|mantissa;
-	DBG(DBGFLOAT," return %f\n",u.d);
-	return u.d;
-	}
-		/*:66*/
-	}
-	/*:61*/
-int yywrap(void){
-	#line 10186 "format.w"
-	return 1;}
-#ifdef _MSC_VER
-#pragma  warning( disable : 4267)
-#endif
-
-#define YY_NO_UNISTD_H 1
-#define YY_NO_INPUT 1
-/*23:*/
-/*:23*/	/*32:*/
-
-/*:32*/	/*39:*/
-/*:39*/	/*41:*/
-/*:41*/	/*43:*/
-/*:43*/	/*45:*/
-/*:45*/	/*149:*/
-
-/*:149*/
-#line 1009 "shrink.lex.c"
-
-#define INITIAL 0
-#define STR 1
-#define TXT 2
-
-#ifndef YY_NO_UNISTD_H
-/* Special case for "unistd.h", since it is non-ANSI. We include it way
- * down here because we want the user's section 1 to have been scanned first.
- * The user has a chance to override it with an option.
- */
-/* %if-c-only */
-#include <unistd.h>
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-#endif
-
-#ifndef YY_EXTRA_TYPE
-#define YY_EXTRA_TYPE void *
-#endif
-
-/* %if-c-only Reentrant structure and macros (non-C++). */
-/* %if-reentrant */
-/* %if-c-only */
-
-static int yy_init_globals (void );
-
-/* %endif */
-/* %if-reentrant */
-/* %endif */
-/* %endif End reentrant structures and macros. */
-
-/* Accessor methods to globals.
-   These are made visible to non-reentrant scanners for convenience. */
-
-int yylex_destroy (void );
-
-int yyget_debug (void );
-
-void yyset_debug (int debug_flag  );
-
-YY_EXTRA_TYPE yyget_extra (void );
-
-void yyset_extra (YY_EXTRA_TYPE user_defined  );
-
-FILE *yyget_in (void );
-
-void yyset_in  (FILE * in_str  );
-
-FILE *yyget_out (void );
-
-void yyset_out  (FILE * out_str  );
-
-yy_size_t yyget_leng (void );
-
-char *yyget_text (void );
-
-int yyget_lineno (void );
-
-void yyset_lineno (int line_number  );
-
-/* %if-bison-bridge */
-/* %endif */
-
-/* Macros after this point can all be overridden by user definitions in
- * section 1.
- */
-
-#ifndef YY_SKIP_YYWRAP
-#ifdef __cplusplus
-extern "C" int yywrap (void );
-#else
-extern int yywrap (void );
-#endif
-#endif
-
-/* %not-for-header */
-
-/* %ok-for-header */
-
-/* %endif */
-
-#ifndef yytext_ptr
-static void yy_flex_strncpy (char *,yyconst char *,int );
-#endif
-
-#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * );
-#endif
-
-#ifndef YY_NO_INPUT
-/* %if-c-only Standard (non-C++) definition */
-/* %not-for-header */
-
-#ifdef __cplusplus
-static int yyinput (void );
-#else
-static int input (void );
-#endif
-/* %ok-for-header */
-
-/* %endif */
-#endif
-
-/* %if-c-only */
-
-        static int yy_start_stack_ptr = 0;
-        static int yy_start_stack_depth = 0;
-        static int *yy_start_stack = NULL;
-    
-    static void yy_push_state (int new_state );
-    
-    static void yy_pop_state (void );
-    
-/* %endif */
-
-/* Amount of stuff to slurp up with each read. */
-#ifndef YY_READ_BUF_SIZE
-#define YY_READ_BUF_SIZE 8192
-#endif
-
-/* Copy whatever the last rule matched to the standard output. */
-#ifndef ECHO
-/* %if-c-only Standard (non-C++) definition */
-/* This used to be an fputs(), but since the string might contain NUL's,
- * we now use fwrite().
- */
-#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
-/* %endif */
-/* %if-c++-only C++ definition */
-/* %endif */
-#endif
-
-/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
- * is returned in "result".
- */
-#ifndef YY_INPUT
-#define YY_INPUT(buf,result,max_size) \
-/* %% [5.0] fread()/read() definition of YY_INPUT goes here unless we're doing C++ \ */\
-	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
-		{ \
-		int c = '*'; \
-		size_t n; \
-		for ( n = 0; n < max_size && \
-			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
-			buf[n] = (char) c; \
-		if ( c == '\n' ) \
-			buf[n++] = (char) c; \
-		if ( c == EOF && ferror( yyin ) ) \
-			YY_FATAL_ERROR( "input in flex scanner failed" ); \
-		result = n; \
-		} \
-	else \
-		{ \
-		errno=0; \
-		while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
-			{ \
-			if( errno != EINTR) \
-				{ \
-				YY_FATAL_ERROR( "input in flex scanner failed" ); \
-				break; \
-				} \
-			errno=0; \
-			clearerr(yyin); \
-			} \
-		}\
-\
-/* %if-c++-only C++ definition \ */\
-/* %endif */
-
-#endif
-
-/* No semi-colon after return; correct usage is to write "yyterminate();" -
- * we don't want an extra ';' after the "return" because that will cause
- * some compilers to complain about unreachable statements.
- */
-#ifndef yyterminate
-#define yyterminate() return YY_NULL
-#endif
-
-/* Number of entries by which start-condition stack grows. */
-#ifndef YY_START_STACK_INCR
-#define YY_START_STACK_INCR 25
-#endif
-
-/* Report a fatal error. */
-#ifndef YY_FATAL_ERROR
-/* %if-c-only */
-#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-#endif
-
-/* %if-tables-serialization structures and prototypes */
-/* %not-for-header */
-
-/* %ok-for-header */
-
-/* %not-for-header */
-
-/* %tables-yydmap generated elements */
-/* %endif */
-/* end tables serialization structures and prototypes */
-
-/* %ok-for-header */
-
-/* Default declaration of generated scanner - a define so the user can
- * easily add parameters.
- */
-#ifndef YY_DECL
-#define YY_DECL_IS_OURS 1
-/* %if-c-only Standard (non-C++) definition */
-
-extern int yylex (void);
-
-#define YY_DECL int yylex (void)
-/* %endif */
-/* %if-c++-only C++ definition */
-/* %endif */
-#endif /* !YY_DECL */
-
-/* Code executed at the beginning of each rule, after yytext and yyleng
- * have been set up.
- */
-#ifndef YY_USER_ACTION
-#define YY_USER_ACTION
-#endif
-
-/* Code executed at the end of each rule. */
-#ifndef YY_BREAK
-#define YY_BREAK break;
-#endif
-
-/* %% [6.0] YY_RULE_SETUP definition goes here */
-#define YY_RULE_SETUP \
-	YY_USER_ACTION
-
-/* %not-for-header */
-
-/** The main scanner function which does all the work.
- */
-YY_DECL
-{
-	register yy_state_type yy_current_state;
-	register char *yy_cp, *yy_bp;
-	register int yy_act;
-    
-/* %% [7.0] user's declarations go here */
-#line 167 "shrink.l"
-
-
-	/*3:*/
-#line 1263 "shrink.lex.c"
-
-	if ( !(yy_init) )
-		{
-		(yy_init) = 1;
-
-#ifdef YY_USER_INIT
-		YY_USER_INIT;
-#endif
-
-		if ( ! (yy_start) )
-			(yy_start) = 1;	/* first start state */
-
-		if ( ! yyin )
-/* %if-c-only */
-			yyin = stdin;
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-
-		if ( ! yyout )
-/* %if-c-only */
-			yyout = stdout;
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-
-		if ( ! YY_CURRENT_BUFFER ) {
-			yyensure_buffer_stack ();
-			YY_CURRENT_BUFFER_LVALUE =
-				yy_create_buffer(yyin,YY_BUF_SIZE );
-		}
-
-		yy_load_buffer_state( );
-		}
-
-	while ( 1 )		/* loops until end-of-file is reached */
-		{
-/* %% [8.0] yymore()-related code goes here */
-		yy_cp = (yy_c_buf_p);
-
-		/* Support of yytext. */
-		*yy_cp = (yy_hold_char);
-
-		/* yy_bp points to the position in yy_ch_buf of the start of
-		 * the current run.
-		 */
-		yy_bp = yy_cp;
-
-/* %% [9.0] code to set up and find next match goes here */
-		yy_current_state = (yy_start);
-yy_match:
-		do
-			{
-			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
-			if ( yy_accept[yy_current_state] )
-				{
-				(yy_last_accepting_state) = yy_current_state;
-				(yy_last_accepting_cpos) = yy_cp;
-				}
-			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
-				{
-				yy_current_state = (int) yy_def[yy_current_state];
-				if ( yy_current_state >= 371 )
-					yy_c = yy_meta[(unsigned int) yy_c];
-				}
-			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-			++yy_cp;
-			}
-		while ( yy_current_state != 370 );
-		yy_cp = (yy_last_accepting_cpos);
-		yy_current_state = (yy_last_accepting_state);
-
-yy_find_action:
-/* %% [10.0] code to find the action number goes here */
-		yy_act = yy_accept[yy_current_state];
-
-		YY_DO_BEFORE_ACTION;
-
-/* %% [11.0] code for yylineno update goes here */
-
-		if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
-			{
-			int yyl;
-			for ( yyl = 0; yyl < yyleng; ++yyl )
-				if ( yytext[yyl] == '\n' )
-					   
-    yylineno++;
-;
-			}
-
-do_action:	/* This label is used only to access EOF actions. */
-
-/* %% [12.0] debug code goes here */
-		if ( yy_flex_debug )
-			{
-			if ( yy_act == 0 )
-				fprintf( stderr, "--scanner backing up\n" );
-			else if ( yy_act < 126 )
-				fprintf( stderr, "--accepting rule at line %ld (\"%s\")\n",
-				         (long)yy_rule_linenum[yy_act], yytext );
-			else if ( yy_act == 126 )
-				fprintf( stderr, "--accepting default rule (\"%s\")\n",
-				         yytext );
-			else if ( yy_act == 127 )
-				fprintf( stderr, "--(end of buffer or a NUL)\n" );
-			else
-				fprintf( stderr, "--EOF (start condition %d)\n", YY_START );
-			}
-
-		switch ( yy_act )
-	{ /* beginning of action switch */
-/* %% [13.0] actions go here */
-			case 0: /* must back up */
-			/* undo the effects of YY_DO_BEFORE_ACTION */
-			*yy_cp = (yy_hold_char);
-			yy_cp = (yy_last_accepting_cpos);
-			yy_current_state = (yy_last_accepting_state);
-			goto yy_find_action;
-
-case 1:
-YY_RULE_SETUP
-#line 170 "shrink.l"
-SCAN_START;return START;
-	YY_BREAK
-case 2:
-YY_RULE_SETUP
-#line 171 "shrink.l"
-SCAN_END;return END;
-	YY_BREAK
-case 3:
-YY_RULE_SETUP
-#line 172 "shrink.l"
-return GLYPH;
-	YY_BREAK
-case 4:
-YY_RULE_SETUP
-#line 173 "shrink.l"
-SCAN_UDEC(yytext);return UNSIGNED;
-	YY_BREAK
-case 5:
-YY_RULE_SETUP
-#line 174 "shrink.l"
-SCAN_UDEC(yytext+1);return REFERENCE;
-	YY_BREAK
-case 6:
-/* rule 6 can match eol */
-YY_RULE_SETUP
-#line 175 "shrink.l"
-;
-	YY_BREAK
-case 7:
-/* rule 7 can match eol */
-YY_RULE_SETUP
-#line 176 "shrink.l"
-;
-	YY_BREAK
-/*:3*/	/*24:*/
-case 8:
-YY_RULE_SETUP
-#line 178 "shrink.l"
-SCAN_HEX(yytext+2);return UNSIGNED;
-	YY_BREAK
-/*:24*/	/*27:*/
-case 9:
-YY_RULE_SETUP
-#line 180 "shrink.l"
-SCAN_DEC(yytext);return SIGNED;
-	YY_BREAK
-/*:27*/	/*34:*/
-case 10:
-YY_RULE_SETUP
-#line 182 "shrink.l"
-STR_START;BEGIN(STR);
-	YY_BREAK
-
-case 11:
-YY_RULE_SETUP
-#line 184 "shrink.l"
-STR_END;SCAN_STR;BEGIN(INITIAL);return STRING;
-	YY_BREAK
-case 12:
-YY_RULE_SETUP
-#line 185 "shrink.l"
-STR_ADD('\'');
-	YY_BREAK
-case 13:
-YY_RULE_SETUP
-#line 186 "shrink.l"
-STR_ADD(yytext[0]);
-	YY_BREAK
-case 14:
-YY_RULE_SETUP
-#line 187 "shrink.l"
-RNG("String character",yytext[0],0x20,0x7E);
-	YY_BREAK
-case 15:
-/* rule 15 can match eol */
-YY_RULE_SETUP
-#line 188 "shrink.l"
-QUIT("Unterminated String in line %d",yylineno);
-	YY_BREAK
-
-/*:34*/	/*48:*/
-case 16:
-YY_RULE_SETUP
-#line 193 "shrink.l"
-STR_START;STR_PUT('\'');BEGIN(STR);
-	YY_BREAK
-case 17:
-YY_RULE_SETUP
-#line 194 "shrink.l"
-SCAN_UTF8_1(yytext+1);return CHARCODE;
-	YY_BREAK
-case 18:
-YY_RULE_SETUP
-#line 195 "shrink.l"
-STR_START;STR_PUT(yytext[1]);STR_PUT('\'');BEGIN(STR);
-	YY_BREAK
-case 19:
-YY_RULE_SETUP
-#line 196 "shrink.l"
-STR_START;STR_PUT('\'');STR_PUT('\'');BEGIN(STR);
-	YY_BREAK
-case 20:
-/* rule 20 can match eol */
-YY_RULE_SETUP
-#line 197 "shrink.l"
-SCAN_UTF8_1(yytext+1);return CHARCODE;
-	YY_BREAK
-case 21:
-YY_RULE_SETUP
-#line 198 "shrink.l"
-SCAN_UTF8_2(yytext+1);return CHARCODE;
-	YY_BREAK
-case 22:
-YY_RULE_SETUP
-#line 199 "shrink.l"
-SCAN_UTF8_3(yytext+1);return CHARCODE;
-	YY_BREAK
-case 23:
-YY_RULE_SETUP
-#line 200 "shrink.l"
-SCAN_UTF8_4(yytext+1);return CHARCODE;
-	YY_BREAK
-/*:48*/	/*55:*/
-case 24:
-YY_RULE_SETUP
-#line 202 "shrink.l"
-SCAN_DECFLOAT;return FPNUM;
-	YY_BREAK
-/*:55*/	/*59:*/
-case 25:
-YY_RULE_SETUP
-#line 204 "shrink.l"
-SCAN_HEXFLOAT;return FPNUM;
-	YY_BREAK
-/*:59*/	/*80:*/
-case 26:
-YY_RULE_SETUP
-#line 206 "shrink.l"
-return DIMEN;
-	YY_BREAK
-case 27:
-YY_RULE_SETUP
-#line 207 "shrink.l"
-return PT;
-	YY_BREAK
-case 28:
-YY_RULE_SETUP
-#line 208 "shrink.l"
-return MM;
-	YY_BREAK
-case 29:
-YY_RULE_SETUP
-#line 209 "shrink.l"
-return INCH;
-	YY_BREAK
-/*:80*/	/*88:*/
-case 30:
-YY_RULE_SETUP
-#line 211 "shrink.l"
-return XDIMEN;
-	YY_BREAK
-case 31:
-YY_RULE_SETUP
-#line 212 "shrink.l"
-return H;
-	YY_BREAK
-case 32:
-YY_RULE_SETUP
-#line 213 "shrink.l"
-return V;
-	YY_BREAK
-/*:88*/	/*99:*/
-case 33:
-YY_RULE_SETUP
-#line 215 "shrink.l"
-return FIL;
-	YY_BREAK
-case 34:
-YY_RULE_SETUP
-#line 216 "shrink.l"
-return FILL;
-	YY_BREAK
-case 35:
-YY_RULE_SETUP
-#line 217 "shrink.l"
-return FILLL;
-	YY_BREAK
-/*:99*/	/*103:*/
-case 36:
-YY_RULE_SETUP
-#line 219 "shrink.l"
-return PENALTY;
-	YY_BREAK
-case 37:
-YY_RULE_SETUP
-#line 220 "shrink.l"
-return INTEGER;
-	YY_BREAK
-/*:103*/	/*109:*/
-case 38:
-YY_RULE_SETUP
-#line 222 "shrink.l"
-return LANGUAGE;
-	YY_BREAK
-/*:109*/	/*115:*/
-case 39:
-YY_RULE_SETUP
-#line 224 "shrink.l"
-return RULE;
-	YY_BREAK
-case 40:
-YY_RULE_SETUP
-#line 225 "shrink.l"
-return RUNNING;
-	YY_BREAK
-case 41:
-YY_RULE_SETUP
-#line 226 "shrink.l"
-return RUNNING;
-	YY_BREAK
-/*:115*/	/*124:*/
-case 42:
-YY_RULE_SETUP
-#line 228 "shrink.l"
-return KERN;
-	YY_BREAK
-case 43:
-YY_RULE_SETUP
-#line 229 "shrink.l"
-return EXPLICIT;
-	YY_BREAK
-/*:124*/	/*133:*/
-case 44:
-YY_RULE_SETUP
-#line 231 "shrink.l"
-return GLUE;
-	YY_BREAK
-case 45:
-YY_RULE_SETUP
-#line 232 "shrink.l"
-return PLUS;
-	YY_BREAK
-case 46:
-YY_RULE_SETUP
-#line 233 "shrink.l"
-return MINUS;
-	YY_BREAK
-/*:133*/	/*151:*/
-case 47:
-YY_RULE_SETUP
-#line 235 "shrink.l"
-SCAN_TXT_START;return TXT_START;
-	YY_BREAK
-
-case 48:
-YY_RULE_SETUP
-#line 238 "shrink.l"
-SCAN_TXT_END;return TXT_END;
-	YY_BREAK
-case 49:
-YY_RULE_SETUP
-#line 240 "shrink.l"
-SCAN_START;return START;
-	YY_BREAK
-case 50:
-YY_RULE_SETUP
-#line 241 "shrink.l"
-QUIT("> not allowed in text mode");
-	YY_BREAK
-case 51:
-YY_RULE_SETUP
-#line 243 "shrink.l"
-yylval.u= '\\';return TXT_CC;
-	YY_BREAK
-case 52:
-YY_RULE_SETUP
-#line 244 "shrink.l"
-yylval.u= '"';return TXT_CC;
-	YY_BREAK
-case 53:
-YY_RULE_SETUP
-#line 245 "shrink.l"
-yylval.u= '<';return TXT_CC;
-	YY_BREAK
-case 54:
-YY_RULE_SETUP
-#line 246 "shrink.l"
-yylval.u= '>';return TXT_CC;
-	YY_BREAK
-case 55:
-YY_RULE_SETUP
-#line 247 "shrink.l"
-yylval.u= ' ';return TXT_CC;
-	YY_BREAK
-case 56:
-YY_RULE_SETUP
-#line 248 "shrink.l"
-yylval.u= '-';return TXT_CC;
-	YY_BREAK
-case 57:
-YY_RULE_SETUP
-#line 249 "shrink.l"
-return TXT_IGNORE;
-	YY_BREAK
-case 58:
-/* rule 58 can match eol */
-YY_RULE_SETUP
-#line 251 "shrink.l"
-return TXT_FONT_GLUE;
-	YY_BREAK
-case 59:
-/* rule 59 can match eol */
-YY_RULE_SETUP
-#line 252 "shrink.l"
-;
-	YY_BREAK
-case 60:
-YY_RULE_SETUP
-#line 254 "shrink.l"
-yylval.u= yytext[1]-'0';return TXT_FONT;
-	YY_BREAK
-case 61:
-YY_RULE_SETUP
-#line 256 "shrink.l"
-SCAN_REF(font_kind);return TXT_GLOBAL;
-	YY_BREAK
-case 62:
-YY_RULE_SETUP
-#line 257 "shrink.l"
-SCAN_REF(penalty_kind);return TXT_GLOBAL;
-	YY_BREAK
-case 63:
-YY_RULE_SETUP
-#line 258 "shrink.l"
-SCAN_REF(kern_kind);return TXT_GLOBAL;
-	YY_BREAK
-case 64:
-YY_RULE_SETUP
-#line 259 "shrink.l"
-SCAN_REF(ligature_kind);return TXT_GLOBAL;
-	YY_BREAK
-case 65:
-YY_RULE_SETUP
-#line 260 "shrink.l"
-SCAN_REF(disc_kind);return TXT_GLOBAL;
-	YY_BREAK
-case 66:
-YY_RULE_SETUP
-#line 261 "shrink.l"
-SCAN_REF(glue_kind);return TXT_GLOBAL;
-	YY_BREAK
-case 67:
-YY_RULE_SETUP
-#line 262 "shrink.l"
-SCAN_REF(language_kind);return TXT_GLOBAL;
-	YY_BREAK
-case 68:
-YY_RULE_SETUP
-#line 263 "shrink.l"
-SCAN_REF(rule_kind);return TXT_GLOBAL;
-	YY_BREAK
-case 69:
-YY_RULE_SETUP
-#line 264 "shrink.l"
-SCAN_REF(image_kind);return TXT_GLOBAL;
-	YY_BREAK
-case 70:
-YY_RULE_SETUP
-#line 267 "shrink.l"
-SCAN_UDEC(yytext+2);return TXT_CC;
-	YY_BREAK
-case 71:
-YY_RULE_SETUP
-#line 269 "shrink.l"
-yylval.u= yytext[1]-'a';return TXT_LOCAL;
-	YY_BREAK
-case 72:
-YY_RULE_SETUP
-#line 270 "shrink.l"
-return TXT_FONT_GLUE;
-	YY_BREAK
-case 73:
-YY_RULE_SETUP
-#line 271 "shrink.l"
-return TXT_FONT_HYPHEN;
-	YY_BREAK
-case 74:
-/* rule 74 can match eol */
-YY_RULE_SETUP
-#line 273 "shrink.l"
-SCAN_UTF8_1(yytext);return TXT_CC;
-	YY_BREAK
-case 75:
-YY_RULE_SETUP
-#line 274 "shrink.l"
-SCAN_UTF8_2(yytext);return TXT_CC;
-	YY_BREAK
-case 76:
-YY_RULE_SETUP
-#line 275 "shrink.l"
-SCAN_UTF8_3(yytext);return TXT_CC;
-	YY_BREAK
-case 77:
-YY_RULE_SETUP
-#line 276 "shrink.l"
-SCAN_UTF8_4(yytext);return TXT_CC;
-	YY_BREAK
-
-/*:151*/	/*162:*/
-case 78:
-YY_RULE_SETUP
-#line 279 "shrink.l"
-return HBOX;
-	YY_BREAK
-case 79:
-YY_RULE_SETUP
-#line 280 "shrink.l"
-return VBOX;
-	YY_BREAK
-case 80:
-YY_RULE_SETUP
-#line 281 "shrink.l"
-return SHIFTED;
-	YY_BREAK
-/*:162*/	/*170:*/
-case 81:
-YY_RULE_SETUP
-#line 283 "shrink.l"
-return HPACK;
-	YY_BREAK
-case 82:
-YY_RULE_SETUP
-#line 284 "shrink.l"
-return HSET;
-	YY_BREAK
-case 83:
-YY_RULE_SETUP
-#line 285 "shrink.l"
-return VPACK;
-	YY_BREAK
-case 84:
-YY_RULE_SETUP
-#line 286 "shrink.l"
-return VSET;
-	YY_BREAK
-case 85:
-YY_RULE_SETUP
-#line 287 "shrink.l"
-return ADD;
-	YY_BREAK
-case 86:
-YY_RULE_SETUP
-#line 288 "shrink.l"
-return TO;
-	YY_BREAK
-case 87:
-YY_RULE_SETUP
-#line 289 "shrink.l"
-return DEPTH;
-	YY_BREAK
-/*:170*/	/*175:*/
-case 88:
-YY_RULE_SETUP
-#line 291 "shrink.l"
-return LEADERS;
-	YY_BREAK
-case 89:
-YY_RULE_SETUP
-#line 292 "shrink.l"
-return ALIGN;
-	YY_BREAK
-case 90:
-YY_RULE_SETUP
-#line 293 "shrink.l"
-return CENTER;
-	YY_BREAK
-case 91:
-YY_RULE_SETUP
-#line 294 "shrink.l"
-return EXPAND;
-	YY_BREAK
-/*:175*/	/*182:*/
-case 92:
-YY_RULE_SETUP
-#line 296 "shrink.l"
-return BASELINE;
-	YY_BREAK
-/*:182*/	/*189:*/
-case 93:
-YY_RULE_SETUP
-#line 298 "shrink.l"
-return LIGATURE;
-	YY_BREAK
-/*:189*/	/*197:*/
-case 94:
-YY_RULE_SETUP
-#line 300 "shrink.l"
-return DISC;
-	YY_BREAK
-/*:197*/	/*205:*/
-case 95:
-YY_RULE_SETUP
-#line 302 "shrink.l"
-return PAR;
-	YY_BREAK
-/*:205*/	/*210:*/
-case 96:
-YY_RULE_SETUP
-#line 304 "shrink.l"
-return MATH;
-	YY_BREAK
-/*:210*/	/*215:*/
-case 97:
-YY_RULE_SETUP
-#line 306 "shrink.l"
-return ON;
-	YY_BREAK
-case 98:
-YY_RULE_SETUP
-#line 307 "shrink.l"
-return OFF;
-	YY_BREAK
-/*:215*/	/*219:*/
-case 99:
-YY_RULE_SETUP
-#line 309 "shrink.l"
-return ADJUST;
-	YY_BREAK
-/*:219*/	/*223:*/
-case 100:
-YY_RULE_SETUP
-#line 311 "shrink.l"
-return TABLE;
-	YY_BREAK
-case 101:
-YY_RULE_SETUP
-#line 312 "shrink.l"
-return ITEM;
-	YY_BREAK
-case 102:
-YY_RULE_SETUP
-#line 313 "shrink.l"
-return ITEM;
-	YY_BREAK
-case 103:
-YY_RULE_SETUP
-#line 314 "shrink.l"
-return ITEM;
-	YY_BREAK
-/*:223*/	/*230:*/
-case 104:
-YY_RULE_SETUP
-#line 316 "shrink.l"
-return IMAGE;
-	YY_BREAK
-/*:230*/	/*247:*/
-case 105:
-YY_RULE_SETUP
-#line 318 "shrink.l"
-return LABEL;
-	YY_BREAK
-case 106:
-YY_RULE_SETUP
-#line 319 "shrink.l"
-return BOT;
-	YY_BREAK
-case 107:
-YY_RULE_SETUP
-#line 320 "shrink.l"
-return MID;
-	YY_BREAK
-/*:247*/	/*261:*/
-case 108:
-YY_RULE_SETUP
-#line 322 "shrink.l"
-return LINK;
-	YY_BREAK
-/*:261*/	/*271:*/
-case 109:
-YY_RULE_SETUP
-#line 324 "shrink.l"
-return OUTLINE;
-	YY_BREAK
-/*:271*/	/*278:*/
-case 110:
-YY_RULE_SETUP
-#line 326 "shrink.l"
-if(section_no==1)return STREAMDEF;else return STREAM;
-	YY_BREAK
-case 111:
-YY_RULE_SETUP
-#line 327 "shrink.l"
-return FIRST;
-	YY_BREAK
-case 112:
-YY_RULE_SETUP
-#line 328 "shrink.l"
-return LAST;
-	YY_BREAK
-case 113:
-YY_RULE_SETUP
-#line 329 "shrink.l"
-return TOP;
-	YY_BREAK
-case 114:
-YY_RULE_SETUP
-#line 330 "shrink.l"
-return NOREFERENCE;
-	YY_BREAK
-/*:278*/	/*288:*/
-case 115:
-YY_RULE_SETUP
-#line 332 "shrink.l"
-return PAGE;
-	YY_BREAK
-/*:288*/	/*296:*/
-case 116:
-YY_RULE_SETUP
-#line 334 "shrink.l"
-return RANGE;
-	YY_BREAK
-/*:296*/	/*323:*/
-case 117:
-YY_RULE_SETUP
-#line 336 "shrink.l"
-return DIRECTORY;
-	YY_BREAK
-case 118:
-YY_RULE_SETUP
-#line 337 "shrink.l"
-return SECTION;
-	YY_BREAK
-/*:323*/	/*342:*/
-case 119:
-YY_RULE_SETUP
-#line 339 "shrink.l"
-return DEFINITIONS;
-	YY_BREAK
-/*:342*/	/*350:*/
-case 120:
-YY_RULE_SETUP
-#line 341 "shrink.l"
-return MAX;
-	YY_BREAK
-/*:350*/	/*365:*/
-case 121:
-YY_RULE_SETUP
-#line 343 "shrink.l"
-return PARAM;
-	YY_BREAK
-/*:365*/	/*374:*/
-case 122:
-YY_RULE_SETUP
-#line 345 "shrink.l"
-return FONT;
-	YY_BREAK
-/*:374*/	/*402:*/
-case 123:
-YY_RULE_SETUP
-#line 347 "shrink.l"
-return CONTENT;
-	YY_BREAK
-/*:402*/
-case 124:
-YY_RULE_SETUP
-#line 349 "shrink.l"
-QUIT("Unexpected keyword '%s' in line %d",yytext,yylineno);
-	YY_BREAK
-case 125:
-YY_RULE_SETUP
-#line 350 "shrink.l"
-QUIT("Unexpected character '%c' (0x%02X) in line %d",yytext[0]>' '?yytext[0]:' ',yytext[0],yylineno);
-	YY_BREAK
-case 126:
-YY_RULE_SETUP
-#line 352 "shrink.l"
-ECHO;
-	YY_BREAK
-#line 2064 "shrink.lex.c"
-case YY_STATE_EOF(INITIAL):
-case YY_STATE_EOF(STR):
-case YY_STATE_EOF(TXT):
-	yyterminate();
-
-	case YY_END_OF_BUFFER:
-		{
-		/* Amount of text matched not including the EOB char. */
-		int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
-
-		/* Undo the effects of YY_DO_BEFORE_ACTION. */
-		*yy_cp = (yy_hold_char);
-		YY_RESTORE_YY_MORE_OFFSET
-
-		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
-			{
-			/* We're scanning a new file or input source.  It's
-			 * possible that this happened because the user
-			 * just pointed yyin at a new source and called
-			 * yylex().  If so, then we have to assure
-			 * consistency between YY_CURRENT_BUFFER and our
-			 * globals.  Here is the right place to do so, because
-			 * this is the first action (other than possibly a
-			 * back-up) that will match for the new input source.
-			 */
-			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
-			YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
-			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
-			}
-
-		/* Note that here we test for yy_c_buf_p "<=" to the position
-		 * of the first EOB in the buffer, since yy_c_buf_p will
-		 * already have been incremented past the NUL character
-		 * (since all states make transitions on EOB to the
-		 * end-of-buffer state).  Contrast this with the test
-		 * in input().
-		 */
-		if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
-			{ /* This was really a NUL. */
-			yy_state_type yy_next_state;
-
-			(yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
-
-			yy_current_state = yy_get_previous_state(  );
-
-			/* Okay, we're now positioned to make the NUL
-			 * transition.  We couldn't have
-			 * yy_get_previous_state() go ahead and do it
-			 * for us because it doesn't know how to deal
-			 * with the possibility of jamming (and we don't
-			 * want to build jamming into it because then it
-			 * will run more slowly).
-			 */
-
-			yy_next_state = yy_try_NUL_trans( yy_current_state );
-
-			yy_bp = (yytext_ptr) + YY_MORE_ADJ;
-
-			if ( yy_next_state )
-				{
-				/* Consume the NUL. */
-				yy_cp = ++(yy_c_buf_p);
-				yy_current_state = yy_next_state;
-				goto yy_match;
-				}
-
-			else
-				{
-/* %% [14.0] code to do back-up for compressed tables and set up yy_cp goes here */
-				yy_cp = (yy_last_accepting_cpos);
-				yy_current_state = (yy_last_accepting_state);
-				goto yy_find_action;
-				}
-			}
-
-		else switch ( yy_get_next_buffer(  ) )
-			{
-			case EOB_ACT_END_OF_FILE:
-				{
-				(yy_did_buffer_switch_on_eof) = 0;
-
-				if ( yywrap( ) )
-					{
-					/* Note: because we've taken care in
-					 * yy_get_next_buffer() to have set up
-					 * yytext, we can now set up
-					 * yy_c_buf_p so that if some total
-					 * hoser (like flex itself) wants to
-					 * call the scanner after we return the
-					 * YY_NULL, it'll still work - another
-					 * YY_NULL will get returned.
-					 */
-					(yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
-
-					yy_act = YY_STATE_EOF(YY_START);
-					goto do_action;
-					}
-
-				else
-					{
-					if ( ! (yy_did_buffer_switch_on_eof) )
-						YY_NEW_FILE;
-					}
-				break;
-				}
-
-			case EOB_ACT_CONTINUE_SCAN:
-				(yy_c_buf_p) =
-					(yytext_ptr) + yy_amount_of_matched_text;
-
-				yy_current_state = yy_get_previous_state(  );
-
-				yy_cp = (yy_c_buf_p);
-				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
-				goto yy_match;
-
-			case EOB_ACT_LAST_MATCH:
-				(yy_c_buf_p) =
-				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
-
-				yy_current_state = yy_get_previous_state(  );
-
-				yy_cp = (yy_c_buf_p);
-				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
-				goto yy_find_action;
-			}
-		break;
-		}
-
-	default:
-		YY_FATAL_ERROR(
-			"fatal flex scanner internal error--no action found" );
-	} /* end of action switch */
-		} /* end of scanning one token */
-} /* end of yylex */
-/* %ok-for-header */
-
-/* %if-c++-only */
-/* %not-for-header */
-
-/* %ok-for-header */
-
-/* %endif */
-
-/* yy_get_next_buffer - try to read in a new buffer
- *
- * Returns a code representing an action:
- *	EOB_ACT_LAST_MATCH -
- *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
- *	EOB_ACT_END_OF_FILE - end of file
- */
-/* %if-c-only */
-static int yy_get_next_buffer (void)
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
-    	register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
-	register char *source = (yytext_ptr);
-	register int number_to_move, i;
-	int ret_val;
-
-	if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
-		YY_FATAL_ERROR(
-		"fatal flex scanner internal error--end of buffer missed" );
-
-	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
-		{ /* Don't try to fill the buffer, so this is an EOF. */
-		if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
-			{
-			/* We matched a single character, the EOB, so
-			 * treat this as a final EOF.
-			 */
-			return EOB_ACT_END_OF_FILE;
-			}
-
-		else
-			{
-			/* We matched some text prior to the EOB, first
-			 * process it.
-			 */
-			return EOB_ACT_LAST_MATCH;
-			}
-		}
-
-	/* Try to read more data. */
-
-	/* First move last chars to start of buffer. */
-	number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
-
-	for ( i = 0; i < number_to_move; ++i )
-		*(dest++) = *(source++);
-
-	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
-		/* don't do the read, it's not guaranteed to return an EOF,
-		 * just force an EOF
-		 */
-		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
-
-	else
-		{
-			yy_size_t num_to_read =
-			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
-
-		while ( num_to_read <= 0 )
-			{ /* Not enough room in the buffer - grow it. */
-
-			/* just a shorter name for the current buffer */
-			YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
-
-			int yy_c_buf_p_offset =
-				(int) ((yy_c_buf_p) - b->yy_ch_buf);
-
-			if ( b->yy_is_our_buffer )
-				{
-				yy_size_t new_size = b->yy_buf_size * 2;
-
-				if ( new_size <= 0 )
-					b->yy_buf_size += b->yy_buf_size / 8;
-				else
-					b->yy_buf_size *= 2;
-
-				b->yy_ch_buf = (char *)
-					/* Include room in for 2 EOB chars. */
-					yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2  );
-				}
-			else
-				/* Can't grow it, we don't own it. */
-				b->yy_ch_buf = 0;
-
-			if ( ! b->yy_ch_buf )
-				YY_FATAL_ERROR(
-				"fatal error - scanner input buffer overflow" );
-
-			(yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
-
-			num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
-						number_to_move - 1;
-
-			}
-
-		if ( num_to_read > YY_READ_BUF_SIZE )
-			num_to_read = YY_READ_BUF_SIZE;
-
-		/* Read in more data. */
-		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
-			(yy_n_chars), num_to_read );
-
-		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
-		}
-
-	if ( (yy_n_chars) == 0 )
-		{
-		if ( number_to_move == YY_MORE_ADJ )
-			{
-			ret_val = EOB_ACT_END_OF_FILE;
-			yyrestart(yyin  );
-			}
-
-		else
-			{
-			ret_val = EOB_ACT_LAST_MATCH;
-			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
-				YY_BUFFER_EOF_PENDING;
-			}
-		}
-
-	else
-		ret_val = EOB_ACT_CONTINUE_SCAN;
-
-	if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
-		/* Extend the array by 50%, plus the number we really need. */
-		yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
-		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size  );
-		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
-			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
-	}
-
-	(yy_n_chars) += number_to_move;
-	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
-	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
-
-	(yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
-
-	return ret_val;
-}
-
-/* yy_get_previous_state - get the state just before the EOB char was reached */
-
-/* %if-c-only */
-/* %not-for-header */
-
-    static yy_state_type yy_get_previous_state (void)
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
-	register yy_state_type yy_current_state;
-	register char *yy_cp;
-    
-/* %% [15.0] code to get the start state into yy_current_state goes here */
-	yy_current_state = (yy_start);
-
-	for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
-		{
-/* %% [16.0] code to find the next state goes here */
-		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
-		if ( yy_accept[yy_current_state] )
-			{
-			(yy_last_accepting_state) = yy_current_state;
-			(yy_last_accepting_cpos) = yy_cp;
-			}
-		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
-			{
-			yy_current_state = (int) yy_def[yy_current_state];
-			if ( yy_current_state >= 371 )
-				yy_c = yy_meta[(unsigned int) yy_c];
-			}
-		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-		}
-
-	return yy_current_state;
-}
-
-/* yy_try_NUL_trans - try to make a transition on the NUL character
- *
- * synopsis
- *	next_state = yy_try_NUL_trans( current_state );
- */
-/* %if-c-only */
-    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state )
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
-	register int yy_is_jam;
-    /* %% [17.0] code to find the next state, and perhaps do backing up, goes here */
-	register char *yy_cp = (yy_c_buf_p);
-
-	register YY_CHAR yy_c = 1;
-	if ( yy_accept[yy_current_state] )
-		{
-		(yy_last_accepting_state) = yy_current_state;
-		(yy_last_accepting_cpos) = yy_cp;
-		}
-	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
-		{
-		yy_current_state = (int) yy_def[yy_current_state];
-		if ( yy_current_state >= 371 )
-			yy_c = yy_meta[(unsigned int) yy_c];
-		}
-	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-	yy_is_jam = (yy_current_state == 370);
-
-		return yy_is_jam ? 0 : yy_current_state;
-}
-
-/* %if-c-only */
-
-/* %endif */
-
-/* %if-c-only */
-#ifndef YY_NO_INPUT
-#ifdef __cplusplus
-    static int yyinput (void)
-#else
-    static int input  (void)
-#endif
-
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
-	int c;
-    
-	*(yy_c_buf_p) = (yy_hold_char);
-
-	if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
-		{
-		/* yy_c_buf_p now points to the character we want to return.
-		 * If this occurs *before* the EOB characters, then it's a
-		 * valid NUL; if not, then we've hit the end of the buffer.
-		 */
-		if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
-			/* This was really a NUL. */
-			*(yy_c_buf_p) = '\0';
-
-		else
-			{ /* need more input */
-			yy_size_t offset = (yy_c_buf_p) - (yytext_ptr);
-			++(yy_c_buf_p);
-
-			switch ( yy_get_next_buffer(  ) )
-				{
-				case EOB_ACT_LAST_MATCH:
-					/* This happens because yy_g_n_b()
-					 * sees that we've accumulated a
-					 * token and flags that we need to
-					 * try matching the token before
-					 * proceeding.  But for input(),
-					 * there's no matching to consider.
-					 * So convert the EOB_ACT_LAST_MATCH
-					 * to EOB_ACT_END_OF_FILE.
-					 */
-
-					/* Reset buffer status. */
-					yyrestart(yyin );
-
-					/*FALLTHROUGH*/
-
-				case EOB_ACT_END_OF_FILE:
-					{
-					if ( yywrap( ) )
-						return EOF;
-
-					if ( ! (yy_did_buffer_switch_on_eof) )
-						YY_NEW_FILE;
-#ifdef __cplusplus
-					return yyinput();
-#else
-					return input();
-#endif
-					}
-
-				case EOB_ACT_CONTINUE_SCAN:
-					(yy_c_buf_p) = (yytext_ptr) + offset;
-					break;
-				}
-			}
-		}
-
-	c = *(unsigned char *) (yy_c_buf_p);	/* cast for 8-bit char's */
-	*(yy_c_buf_p) = '\0';	/* preserve yytext */
-	(yy_hold_char) = *++(yy_c_buf_p);
-
-/* %% [19.0] update BOL and yylineno */
-	if ( c == '\n' )
-		   
-    yylineno++;
-;
-
-	return c;
-}
-/* %if-c-only */
-#endif	/* ifndef YY_NO_INPUT */
-/* %endif */
-
-/** Immediately switch to a different input stream.
- * @param input_file A readable stream.
- * 
- * @note This function does not reset the start condition to @c INITIAL .
- */
-/* %if-c-only */
-    void yyrestart  (FILE * input_file )
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
-    
-	if ( ! YY_CURRENT_BUFFER ){
-        yyensure_buffer_stack ();
-		YY_CURRENT_BUFFER_LVALUE =
-            yy_create_buffer(yyin,YY_BUF_SIZE );
-	}
-
-	yy_init_buffer(YY_CURRENT_BUFFER,input_file );
-	yy_load_buffer_state( );
-}
-
-/** Switch to a different input buffer.
- * @param new_buffer The new input buffer.
- * 
- */
-/* %if-c-only */
-    void yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer )
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
-    
-	/* TODO. We should be able to replace this entire function body
-	 * with
-	 *		yypop_buffer_state();
-	 *		yypush_buffer_state(new_buffer);
-     */
-	yyensure_buffer_stack ();
-	if ( YY_CURRENT_BUFFER == new_buffer )
-		return;
-
-	if ( YY_CURRENT_BUFFER )
-		{
-		/* Flush out information for old buffer. */
-		*(yy_c_buf_p) = (yy_hold_char);
-		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
-		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
-		}
-
-	YY_CURRENT_BUFFER_LVALUE = new_buffer;
-	yy_load_buffer_state( );
-
-	/* We don't actually know whether we did this switch during
-	 * EOF (yywrap()) processing, but the only time this flag
-	 * is looked at is after yywrap() is called, so it's safe
-	 * to go ahead and always set it.
-	 */
-	(yy_did_buffer_switch_on_eof) = 1;
-}
-
-/* %if-c-only */
-static void yy_load_buffer_state  (void)
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
-    	(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
-	(yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
-	yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
-	(yy_hold_char) = *(yy_c_buf_p);
-}
-
-/** Allocate and initialize an input buffer state.
- * @param file A readable stream.
- * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
- * 
- * @return the allocated buffer state.
- */
-/* %if-c-only */
-    YY_BUFFER_STATE yy_create_buffer  (FILE * file, int  size )
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
-	YY_BUFFER_STATE b;
-    
-	b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state )  );
-	if ( ! b )
-		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
-
-	b->yy_buf_size = size;
-
-	/* yy_ch_buf has to be 2 characters longer than the size given because
-	 * we need to put in 2 end-of-buffer characters.
-	 */
-	b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2  );
-	if ( ! b->yy_ch_buf )
-		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
-
-	b->yy_is_our_buffer = 1;
-
-	yy_init_buffer(b,file );
-
-	return b;
-}
-
-/** Destroy the buffer.
- * @param b a buffer created with yy_create_buffer()
- * 
- */
-/* %if-c-only */
-    void yy_delete_buffer (YY_BUFFER_STATE  b )
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
-    
-	if ( ! b )
-		return;
-
-	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
-		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
-
-	if ( b->yy_is_our_buffer )
-		yyfree((void *) b->yy_ch_buf  );
-
-	yyfree((void *) b  );
-}
-
-/* Initializes or reinitializes a buffer.
- * This function is sometimes called more than once on the same buffer,
- * such as during a yyrestart() or at EOF.
- */
-/* %if-c-only */
-    static void yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file )
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-
-{
-	int oerrno = errno;
-    
-	yy_flush_buffer(b );
-
-	b->yy_input_file = file;
-	b->yy_fill_buffer = 1;
-
-    /* If b is the current buffer, then yy_init_buffer was _probably_
-     * called from yyrestart() or through yy_get_next_buffer.
-     * In that case, we don't want to reset the lineno or column.
-     */
-    if (b != YY_CURRENT_BUFFER){
-        b->yy_bs_lineno = 1;
-        b->yy_bs_column = 0;
-    }
-
-/* %if-c-only */
-
-        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
-    
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-	errno = oerrno;
-}
-
-/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
- * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
- * 
- */
-/* %if-c-only */
-    void yy_flush_buffer (YY_BUFFER_STATE  b )
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
-    	if ( ! b )
-		return;
-
-	b->yy_n_chars = 0;
-
-	/* We always need two end-of-buffer characters.  The first causes
-	 * a transition to the end-of-buffer state.  The second causes
-	 * a jam in that state.
-	 */
-	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
-	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
-
-	b->yy_buf_pos = &b->yy_ch_buf[0];
-
-	b->yy_at_bol = 1;
-	b->yy_buffer_status = YY_BUFFER_NEW;
-
-	if ( b == YY_CURRENT_BUFFER )
-		yy_load_buffer_state( );
-}
-
-/* %if-c-or-c++ */
-/** Pushes the new state onto the stack. The new state becomes
- *  the current state. This function will allocate the stack
- *  if necessary.
- *  @param new_buffer The new state.
- *  
- */
-/* %if-c-only */
-void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
-    	if (new_buffer == NULL)
-		return;
-
-	yyensure_buffer_stack();
-
-	/* This block is copied from yy_switch_to_buffer. */
-	if ( YY_CURRENT_BUFFER )
-		{
-		/* Flush out information for old buffer. */
-		*(yy_c_buf_p) = (yy_hold_char);
-		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
-		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
-		}
-
-	/* Only push if top exists. Otherwise, replace top. */
-	if (YY_CURRENT_BUFFER)
-		(yy_buffer_stack_top)++;
-	YY_CURRENT_BUFFER_LVALUE = new_buffer;
-
-	/* copied from yy_switch_to_buffer. */
-	yy_load_buffer_state( );
-	(yy_did_buffer_switch_on_eof) = 1;
-}
-/* %endif */
-
-/* %if-c-or-c++ */
-/** Removes and deletes the top of the stack, if present.
- *  The next element becomes the new top.
- *  
- */
-/* %if-c-only */
-void yypop_buffer_state (void)
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
-    	if (!YY_CURRENT_BUFFER)
-		return;
-
-	yy_delete_buffer(YY_CURRENT_BUFFER );
-	YY_CURRENT_BUFFER_LVALUE = NULL;
-	if ((yy_buffer_stack_top) > 0)
-		--(yy_buffer_stack_top);
-
-	if (YY_CURRENT_BUFFER) {
-		yy_load_buffer_state( );
-		(yy_did_buffer_switch_on_eof) = 1;
-	}
-}
-/* %endif */
-
-/* %if-c-or-c++ */
-/* Allocates the stack if it does not exist.
- *  Guarantees space for at least one push.
- */
-/* %if-c-only */
-static void yyensure_buffer_stack (void)
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
-	yy_size_t num_to_alloc;
-    
-	if (!(yy_buffer_stack)) {
-
-		/* First allocation is just for 2 elements, since we don't know if this
-		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
-		 * immediate realloc on the next call.
-         */
-		num_to_alloc = 1;
-		(yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
-								(num_to_alloc * sizeof(struct yy_buffer_state*)
-								);
-		if ( ! (yy_buffer_stack) )
-			YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
-								  
-		memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
-				
-		(yy_buffer_stack_max) = num_to_alloc;
-		(yy_buffer_stack_top) = 0;
-		return;
-	}
-
-	if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
-
-		/* Increase the buffer to prepare for a possible push. */
-		int grow_size = 8 /* arbitrary grow size */;
-
-		num_to_alloc = (yy_buffer_stack_max) + grow_size;
-		(yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
-								((yy_buffer_stack),
-								num_to_alloc * sizeof(struct yy_buffer_state*)
-								);
-		if ( ! (yy_buffer_stack) )
-			YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
-
-		/* zero only the new slots.*/
-		memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
-		(yy_buffer_stack_max) = num_to_alloc;
-	}
-}
-/* %endif */
-
-/* %if-c-only */
-/** Setup the input buffer state to scan directly from a user-specified character buffer.
- * @param base the character buffer
- * @param size the size in bytes of the character buffer
- * 
- * @return the newly allocated buffer state object. 
- */
-YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size )
-{
-	YY_BUFFER_STATE b;
-    
-	if ( size < 2 ||
-	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
-	     base[size-1] != YY_END_OF_BUFFER_CHAR )
-		/* They forgot to leave room for the EOB's. */
-		return 0;
-
-	b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state )  );
-	if ( ! b )
-		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
-
-	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
-	b->yy_buf_pos = b->yy_ch_buf = base;
-	b->yy_is_our_buffer = 0;
-	b->yy_input_file = 0;
-	b->yy_n_chars = b->yy_buf_size;
-	b->yy_is_interactive = 0;
-	b->yy_at_bol = 1;
-	b->yy_fill_buffer = 0;
-	b->yy_buffer_status = YY_BUFFER_NEW;
-
-	yy_switch_to_buffer(b  );
-
-	return b;
-}
-/* %endif */
-
-/* %if-c-only */
-/** Setup the input buffer state to scan a string. The next call to yylex() will
- * scan from a @e copy of @a str.
- * @param yystr a NUL-terminated string to scan
- * 
- * @return the newly allocated buffer state object.
- * @note If you want to scan bytes that may contain NUL values, then use
- *       yy_scan_bytes() instead.
- */
-YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
-{
-    
-	return yy_scan_bytes(yystr,strlen(yystr) );
-}
-/* %endif */
-
-/* %if-c-only */
-/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
- * scan from a @e copy of @a bytes.
- * @param yybytes the byte buffer to scan
- * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
- * 
- * @return the newly allocated buffer state object.
- */
-YY_BUFFER_STATE yy_scan_bytes  (yyconst char * yybytes, yy_size_t  _yybytes_len )
-{
-	YY_BUFFER_STATE b;
-	char *buf;
-	yy_size_t n;
-	int i;
-    
-	/* Get memory for full buffer, including space for trailing EOB's. */
-	n = _yybytes_len + 2;
-	buf = (char *) yyalloc(n  );
-	if ( ! buf )
-		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
-
-	for ( i = 0; i < _yybytes_len; ++i )
-		buf[i] = yybytes[i];
-
-	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
-
-	b = yy_scan_buffer(buf,n );
-	if ( ! b )
-		YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
-
-	/* It's okay to grow etc. this buffer, and we should throw it
-	 * away when we're done.
-	 */
-	b->yy_is_our_buffer = 1;
-
-	return b;
-}
-/* %endif */
-
-/* %if-c-only */
-    static void yy_push_state (int  new_state )
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
-    	if ( (yy_start_stack_ptr) >= (yy_start_stack_depth) )
-		{
-		yy_size_t new_size;
-
-		(yy_start_stack_depth) += YY_START_STACK_INCR;
-		new_size = (yy_start_stack_depth) * sizeof( int );
-
-		if ( ! (yy_start_stack) )
-			(yy_start_stack) = (int *) yyalloc(new_size  );
-
-		else
-			(yy_start_stack) = (int *) yyrealloc((void *) (yy_start_stack),new_size  );
-
-		if ( ! (yy_start_stack) )
-			YY_FATAL_ERROR( "out of memory expanding start-condition stack" );
-		}
-
-	(yy_start_stack)[(yy_start_stack_ptr)++] = YY_START;
-
-	BEGIN(new_state);
-}
-
-/* %if-c-only */
-    static void yy_pop_state  (void)
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-{
-    	if ( --(yy_start_stack_ptr) < 0 )
-		YY_FATAL_ERROR( "start-condition stack underflow" );
-
-	BEGIN((yy_start_stack)[(yy_start_stack_ptr)]);
-}
-
-#ifndef YY_EXIT_FAILURE
-#define YY_EXIT_FAILURE 2
-#endif
-
-/* %if-c-only */
-static void yy_fatal_error (yyconst char* msg )
-{
-    	(void) fprintf( stderr, "%s\n", msg );
-	exit( YY_EXIT_FAILURE );
-}
-/* %endif */
-/* %if-c++-only */
-/* %endif */
-
-/* Redefine yyless() so it works in section 3 code. */
-
-#undef yyless
-#define yyless(n) \
-	do \
-		{ \
-		/* Undo effects of setting up yytext. */ \
-        int yyless_macro_arg = (n); \
-        YY_LESS_LINENO(yyless_macro_arg);\
-		yytext[yyleng] = (yy_hold_char); \
-		(yy_c_buf_p) = yytext + yyless_macro_arg; \
-		(yy_hold_char) = *(yy_c_buf_p); \
-		*(yy_c_buf_p) = '\0'; \
-		yyleng = yyless_macro_arg; \
-		} \
-	while ( 0 )
-
-/* Accessor  methods (get/set functions) to struct members. */
-
-/* %if-c-only */
-/* %if-reentrant */
-/* %endif */
-
-/** Get the current line number.
- * 
- */
-int yyget_lineno  (void)
-{
-        
-    return yylineno;
-}
-
-/** Get the input stream.
- * 
- */
-FILE *yyget_in  (void)
-{
-        return yyin;
-}
-
-/** Get the output stream.
- * 
- */
-FILE *yyget_out  (void)
-{
-        return yyout;
-}
-
-/** Get the length of the current token.
- * 
- */
-yy_size_t yyget_leng  (void)
-{
-        return yyleng;
-}
-
-/** Get the current token.
- * 
- */
-
-char *yyget_text  (void)
-{
-        return yytext;
-}
-
-/* %if-reentrant */
-/* %endif */
-
-/** Set the current line number.
- * @param line_number
- * 
- */
-void yyset_lineno (int  line_number )
-{
-    
-    yylineno = line_number;
-}
-
-/** Set the input stream. This does not discard the current
- * input buffer.
- * @param in_str A readable stream.
- * 
- * @see yy_switch_to_buffer
- */
-void yyset_in (FILE *  in_str )
-{
-        yyin = in_str ;
-}
-
-void yyset_out (FILE *  out_str )
-{
-        yyout = out_str ;
-}
-
-int yyget_debug  (void)
-{
-        return yy_flex_debug;
-}
-
-void yyset_debug (int  bdebug )
-{
-        yy_flex_debug = bdebug ;
-}
-
-/* %endif */
-
-/* %if-reentrant */
-/* %if-bison-bridge */
-/* %endif */
-/* %endif if-c-only */
-
-/* %if-c-only */
-static int yy_init_globals (void)
-{
-        /* Initialization is the same as for the non-reentrant scanner.
-     * This function is called from yylex_destroy(), so don't allocate here.
-     */
-
-    /* We do not touch yylineno unless the option is enabled. */
-    yylineno =  1;
-    
-    (yy_buffer_stack) = 0;
-    (yy_buffer_stack_top) = 0;
-    (yy_buffer_stack_max) = 0;
-    (yy_c_buf_p) = (char *) 0;
-    (yy_init) = 0;
-    (yy_start) = 0;
-
-    (yy_start_stack_ptr) = 0;
-    (yy_start_stack_depth) = 0;
-    (yy_start_stack) =  NULL;
-
-/* Defined in main.c */
-#ifdef YY_STDINIT
-    yyin = stdin;
-    yyout = stdout;
-#else
-    yyin = (FILE *) 0;
-    yyout = (FILE *) 0;
-#endif
-
-    /* For future reference: Set errno on error, since we are called by
-     * yylex_init()
-     */
-    return 0;
-}
-/* %endif */
-
-/* %if-c-only SNIP! this currently causes conflicts with the c++ scanner */
-/* yylex_destroy is for both reentrant and non-reentrant scanners. */
-int yylex_destroy  (void)
-{
-    
-    /* Pop the buffer stack, destroying each element. */
-	while(YY_CURRENT_BUFFER){
-		yy_delete_buffer(YY_CURRENT_BUFFER  );
-		YY_CURRENT_BUFFER_LVALUE = NULL;
-		yypop_buffer_state();
-	}
-
-	/* Destroy the stack itself. */
-	yyfree((yy_buffer_stack) );
-	(yy_buffer_stack) = NULL;
-
-    /* Destroy the start condition stack. */
-        yyfree((yy_start_stack)  );
-        (yy_start_stack) = NULL;
-
-    /* Reset the globals. This is important in a non-reentrant scanner so the next time
-     * yylex() is called, initialization will occur. */
-    yy_init_globals( );
-
-/* %if-reentrant */
-/* %endif */
-    return 0;
-}
-/* %endif */
-
-/*
- * Internal utility routines.
- */
-
-#ifndef yytext_ptr
-static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
-{
-	register int i;
-	for ( i = 0; i < n; ++i )
-		s1[i] = s2[i];
-}
-#endif
-
-#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * s )
-{
-	register int n;
-	for ( n = 0; s[n]; ++n )
-		;
-
-	return n;
-}
-#endif
-
-void *yyalloc (yy_size_t  size )
-{
-	return (void *) malloc( size );
-}
-
-void *yyrealloc  (void * ptr, yy_size_t  size )
-{
-	/* The cast to (char *) in the following accommodates both
-	 * implementations that use char* generic pointers, and those
-	 * that use void* generic pointers.  It works with the latter
-	 * because both ANSI C and C++ allow castless assignment from
-	 * any pointer type to void*, and deal with argument conversions
-	 * as though doing an assignment.
-	 */
-	return (void *) realloc( (char *) ptr, size );
-}
-
-void yyfree (void * ptr )
-{
-	free( (char *) ptr );	/* see yyrealloc() for (char *) cast */
-}
-
-/* %if-tables-serialization definitions */
-/* %define-yytables   The name for this specific scanner's tables. */
-#define YYTABLES_NAME "yytables"
-/* %endif */
-
-/* %ok-for-header */
-
-#line 352 "shrink.l"
-
-
-	/*:509*/
-

Deleted: trunk/Build/source/texk/web2c/hitexdir/hishrink-parser.c
===================================================================
--- trunk/Build/source/texk/web2c/hitexdir/hishrink-parser.c	2021-11-12 00:49:04 UTC (rev 61032)
+++ trunk/Build/source/texk/web2c/hitexdir/hishrink-parser.c	2021-11-12 11:09:17 UTC (rev 61033)
@@ -1,3896 +0,0 @@
-/* A Bison parser, made by GNU Bison 3.8.2.  */
-
-/* Bison implementation for Yacc-like parsers in C
-
-   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation,
-   Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
-
-/* As a special exception, you may create a larger work that contains
-   part or all of the Bison parser skeleton and distribute that work
-   under terms of your choice, so long as that work isn't itself a
-   parser generator using the skeleton or a modified version thereof
-   as a parser skeleton.  Alternatively, if you modify or redistribute
-   the parser skeleton itself, you may (at your option) remove this
-   special exception, which will cause the skeleton and the resulting
-   Bison output files to be licensed under the GNU General Public
-   License without this special exception.
-
-   This special exception was added by the Free Software Foundation in
-   version 2.2 of Bison.  */
-
-/* C LALR(1) parser skeleton written by Richard Stallman, by
-   simplifying the original so-called "semantic" parser.  */
-
-/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
-   especially those whose name start with YY_ or yy_.  They are
-   private implementation details that can be changed or removed.  */
-
-/* All symbols defined below should begin with yy or YY, to avoid
-   infringing on user name space.  This should be done even for local
-   variables, as they might otherwise be expanded by user macros.
-   There are some unavoidable exceptions within include files to
-   define necessary library symbols; they are noted "INFRINGES ON
-   USER NAME SPACE" below.  */
-
-/* Identify Bison output, and Bison version.  */
-#define YYBISON 30802
-
-/* Bison version string.  */
-#define YYBISON_VERSION "3.8.2"
-
-/* Skeleton name.  */
-#define YYSKELETON_NAME "yacc.c"
-
-/* Pure parsers.  */
-#define YYPURE 0
-
-/* Push parsers.  */
-#define YYPUSH 0
-
-/* Pull parsers.  */
-#define YYPULL 1
-
-
-
-
-/* First part of user prologue.  */
-#line 3 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-
-#include "basetypes.h"
-#include <string.h> 
-#include <math.h> 
-#include "error.h"
-#include "hformat.h"
-#include "hput.h"
-extern char**hfont_name;
-
-/*356:*/
-
-uint32_t definition_bits[0x100/32][32]= {{0}};
-
-#define SET_DBIT(N,K) ((N)> 0xFF?1:(definition_bits[N/32][K]|= (1<<((N)&(32-1)))))
-#define GET_DBIT(N,K) ((N)> 0xFF?1:((definition_bits[N/32][K]>>((N)&(32-1)))&1))
-#define DEF(D,K,N) (D).k= K; (D).n= (N);SET_DBIT((D).n,(D).k);\
- DBG(DBGDEF,"Defining %s %d\n",definition_name[(D).k],(D).n);\
- RNG("Definition",(D).n,max_fixed[(D).k]+1,max_ref[(D).k]);
-#define REF(K,N) REF_RNG(K,N);if(!GET_DBIT(N,K)) \
- QUIT("Reference %d to %s before definition",(N),definition_name[K])
-/*:356*//*360:*/
-
-#define DEF_REF(D,K,M,N)  DEF(D,K,M);\
-if ((M)> max_default[K]) QUIT("Defining non default reference %d for %s",M,definition_name[K]); \
-if ((N)> max_fixed[K]) QUIT("Defining reference %d for %s by non fixed reference %d",M,definition_name[K],N);
-/*:360*/
-
-
-extern void hset_entry(entry_t*e,uint16_t i,uint32_t size,
-uint32_t xsize,char*file_name);
-
-/*423:*/
-
-#ifdef DEBUG
-#define  YYDEBUG 1
-extern int yydebug;
-#else
-#define YYDEBUG 0
-#endif
-/*:423*/
-
-extern int yylex(void);
-
-/*352:*/
-
-void hset_max(kind_t k,int n)
-{DBG(DBGDEF,"Setting max %s to %d\n",definition_name[k],n);
-RNG("Maximum",n,max_fixed[k]+1,MAX_REF(k));
-if(n> max_ref[k])
-max_ref[k]= n;
-}
-/*:352*//*363:*/
-
-void check_param_def(ref_t*df)
-{if(df->k!=int_kind&&df->k!=dimen_kind&&df->k!=glue_kind)
-QUIT("Kind %s not allowed in parameter list",definition_name[df->k]);
-if(df->n<=max_fixed[df->k]||max_default[df->k]<df->n)
-QUIT("Parameter %d for %s not allowed in parameter list",df->n,definition_name[df->k]);
-}
-/*:363*//*422:*/
-
-extern int yylineno;
-int yyerror(const char*msg)
-{QUIT(" in line %d %s",yylineno,msg);
-return 0;
-}
-/*:422*/
-
-
-
-#line 142 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-
-# ifndef YY_CAST
-#  ifdef __cplusplus
-#   define YY_CAST(Type, Val) static_cast<Type> (Val)
-#   define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast<Type> (Val)
-#  else
-#   define YY_CAST(Type, Val) ((Type) (Val))
-#   define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val))
-#  endif
-# endif
-# ifndef YY_NULLPTR
-#  if defined __cplusplus
-#   if 201103L <= __cplusplus
-#    define YY_NULLPTR nullptr
-#   else
-#    define YY_NULLPTR 0
-#   endif
-#  else
-#   define YY_NULLPTR ((void*)0)
-#  endif
-# endif
-
-/* Use api.header.include to #include this header
-   instead of duplicating it here.  */
-#ifndef YY_YY__TEXK_WEB_C_HITEXDIR_HISHRINK_PARSER_H_INCLUDED
-# define YY_YY__TEXK_WEB_C_HITEXDIR_HISHRINK_PARSER_H_INCLUDED
-/* Debug traces.  */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-#if YYDEBUG
-extern int yydebug;
-#endif
-
-/* Token kinds.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-  enum yytokentype
-  {
-    YYEMPTY = -2,
-    YYEOF = 0,                     /* "end of file"  */
-    YYerror = 256,                 /* error  */
-    YYUNDEF = 257,                 /* "invalid token"  */
-    START = 258,                   /* "<"  */
-    END = 259,                     /* ">"  */
-    GLYPH = 260,                   /* "glyph"  */
-    UNSIGNED = 261,                /* UNSIGNED  */
-    REFERENCE = 262,               /* REFERENCE  */
-    SIGNED = 263,                  /* SIGNED  */
-    STRING = 264,                  /* STRING  */
-    CHARCODE = 265,                /* CHARCODE  */
-    FPNUM = 266,                   /* FPNUM  */
-    DIMEN = 267,                   /* "dimen"  */
-    PT = 268,                      /* "pt"  */
-    MM = 269,                      /* "mm"  */
-    INCH = 270,                    /* "in"  */
-    XDIMEN = 271,                  /* "xdimen"  */
-    H = 272,                       /* "h"  */
-    V = 273,                       /* "v"  */
-    FIL = 274,                     /* "fil"  */
-    FILL = 275,                    /* "fill"  */
-    FILLL = 276,                   /* "filll"  */
-    PENALTY = 277,                 /* "penalty"  */
-    INTEGER = 278,                 /* "int"  */
-    LANGUAGE = 279,                /* "language"  */
-    RULE = 280,                    /* "rule"  */
-    RUNNING = 281,                 /* "|"  */
-    KERN = 282,                    /* "kern"  */
-    EXPLICIT = 283,                /* "!"  */
-    GLUE = 284,                    /* "glue"  */
-    PLUS = 285,                    /* "plus"  */
-    MINUS = 286,                   /* "minus"  */
-    TXT_START = 287,               /* TXT_START  */
-    TXT_END = 288,                 /* TXT_END  */
-    TXT_IGNORE = 289,              /* TXT_IGNORE  */
-    TXT_FONT_GLUE = 290,           /* TXT_FONT_GLUE  */
-    TXT_FONT_HYPHEN = 291,         /* TXT_FONT_HYPHEN  */
-    TXT_FONT = 292,                /* TXT_FONT  */
-    TXT_LOCAL = 293,               /* TXT_LOCAL  */
-    TXT_GLOBAL = 294,              /* TXT_GLOBAL  */
-    TXT_CC = 295,                  /* TXT_CC  */
-    HBOX = 296,                    /* "hbox"  */
-    VBOX = 297,                    /* "vbox"  */
-    SHIFTED = 298,                 /* "shifted"  */
-    HPACK = 299,                   /* "hpack"  */
-    HSET = 300,                    /* "hset"  */
-    VPACK = 301,                   /* "vpack"  */
-    VSET = 302,                    /* "vset"  */
-    DEPTH = 303,                   /* "depth"  */
-    ADD = 304,                     /* "add"  */
-    TO = 305,                      /* "to"  */
-    LEADERS = 306,                 /* "leaders"  */
-    ALIGN = 307,                   /* "align"  */
-    CENTER = 308,                  /* "center"  */
-    EXPAND = 309,                  /* "expand"  */
-    BASELINE = 310,                /* "baseline"  */
-    LIGATURE = 311,                /* "ligature"  */
-    DISC = 312,                    /* "disc"  */
-    PAR = 313,                     /* "par"  */
-    MATH = 314,                    /* "math"  */
-    ON = 315,                      /* "on"  */
-    OFF = 316,                     /* "off"  */
-    ADJUST = 317,                  /* "adjust"  */
-    TABLE = 318,                   /* "table"  */
-    ITEM = 319,                    /* "item"  */
-    IMAGE = 320,                   /* "image"  */
-    LABEL = 321,                   /* "label"  */
-    BOT = 322,                     /* "bot"  */
-    MID = 323,                     /* "mid"  */
-    LINK = 324,                    /* "link"  */
-    OUTLINE = 325,                 /* "outline"  */
-    STREAM = 326,                  /* "stream"  */
-    STREAMDEF = 327,               /* "stream (definition)"  */
-    FIRST = 328,                   /* "first"  */
-    LAST = 329,                    /* "last"  */
-    TOP = 330,                     /* "top"  */
-    NOREFERENCE = 331,             /* "*"  */
-    PAGE = 332,                    /* "page"  */
-    RANGE = 333,                   /* "range"  */
-    DIRECTORY = 334,               /* "directory"  */
-    SECTION = 335,                 /* "entry"  */
-    DEFINITIONS = 336,             /* "definitions"  */
-    MAX = 337,                     /* "max"  */
-    PARAM = 338,                   /* "param"  */
-    FONT = 339,                    /* "font"  */
-    CONTENT = 340                  /* "content"  */
-  };
-  typedef enum yytokentype yytoken_kind_t;
-#endif
-/* Token kinds.  */
-#define YYEMPTY -2
-#define YYEOF 0
-#define YYerror 256
-#define YYUNDEF 257
-#define START 258
-#define END 259
-#define GLYPH 260
-#define UNSIGNED 261
-#define REFERENCE 262
-#define SIGNED 263
-#define STRING 264
-#define CHARCODE 265
-#define FPNUM 266
-#define DIMEN 267
-#define PT 268
-#define MM 269
-#define INCH 270
-#define XDIMEN 271
-#define H 272
-#define V 273
-#define FIL 274
-#define FILL 275
-#define FILLL 276
-#define PENALTY 277
-#define INTEGER 278
-#define LANGUAGE 279
-#define RULE 280
-#define RUNNING 281
-#define KERN 282
-#define EXPLICIT 283
-#define GLUE 284
-#define PLUS 285
-#define MINUS 286
-#define TXT_START 287
-#define TXT_END 288
-#define TXT_IGNORE 289
-#define TXT_FONT_GLUE 290
-#define TXT_FONT_HYPHEN 291
-#define TXT_FONT 292
-#define TXT_LOCAL 293
-#define TXT_GLOBAL 294
-#define TXT_CC 295
-#define HBOX 296
-#define VBOX 297
-#define SHIFTED 298
-#define HPACK 299
-#define HSET 300
-#define VPACK 301
-#define VSET 302
-#define DEPTH 303
-#define ADD 304
-#define TO 305
-#define LEADERS 306
-#define ALIGN 307
-#define CENTER 308
-#define EXPAND 309
-#define BASELINE 310
-#define LIGATURE 311
-#define DISC 312
-#define PAR 313
-#define MATH 314
-#define ON 315
-#define OFF 316
-#define ADJUST 317
-#define TABLE 318
-#define ITEM 319
-#define IMAGE 320
-#define LABEL 321
-#define BOT 322
-#define MID 323
-#define LINK 324
-#define OUTLINE 325
-#define STREAM 326
-#define STREAMDEF 327
-#define FIRST 328
-#define LAST 329
-#define TOP 330
-#define NOREFERENCE 331
-#define PAGE 332
-#define RANGE 333
-#define DIRECTORY 334
-#define SECTION 335
-#define DEFINITIONS 336
-#define MAX 337
-#define PARAM 338
-#define FONT 339
-#define CONTENT 340
-
-/* Value type.  */
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-union YYSTYPE
-{
-#line 78 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-uint32_t u;int32_t i;char*s;float64_t f;glyph_t c;
-dimen_t d;stretch_t st;xdimen_t xd;kern_t kt;
-rule_t r;glue_t g;image_t x;
-list_t l;box_t h;disc_t dc;lig_t lg;
-ref_t rf;info_t info;order_t o;bool b;
-
-#line 372 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-
-};
-typedef union YYSTYPE YYSTYPE;
-# define YYSTYPE_IS_TRIVIAL 1
-# define YYSTYPE_IS_DECLARED 1
-#endif
-
-
-extern YYSTYPE yylval;
-
-
-int yyparse (void);
-
-
-#endif /* !YY_YY__TEXK_WEB_C_HITEXDIR_HISHRINK_PARSER_H_INCLUDED  */
-/* Symbol kind.  */
-enum yysymbol_kind_t
-{
-  YYSYMBOL_YYEMPTY = -2,
-  YYSYMBOL_YYEOF = 0,                      /* "end of file"  */
-  YYSYMBOL_YYerror = 1,                    /* error  */
-  YYSYMBOL_YYUNDEF = 2,                    /* "invalid token"  */
-  YYSYMBOL_START = 3,                      /* "<"  */
-  YYSYMBOL_END = 4,                        /* ">"  */
-  YYSYMBOL_GLYPH = 5,                      /* "glyph"  */
-  YYSYMBOL_UNSIGNED = 6,                   /* UNSIGNED  */
-  YYSYMBOL_REFERENCE = 7,                  /* REFERENCE  */
-  YYSYMBOL_SIGNED = 8,                     /* SIGNED  */
-  YYSYMBOL_STRING = 9,                     /* STRING  */
-  YYSYMBOL_CHARCODE = 10,                  /* CHARCODE  */
-  YYSYMBOL_FPNUM = 11,                     /* FPNUM  */
-  YYSYMBOL_DIMEN = 12,                     /* "dimen"  */
-  YYSYMBOL_PT = 13,                        /* "pt"  */
-  YYSYMBOL_MM = 14,                        /* "mm"  */
-  YYSYMBOL_INCH = 15,                      /* "in"  */
-  YYSYMBOL_XDIMEN = 16,                    /* "xdimen"  */
-  YYSYMBOL_H = 17,                         /* "h"  */
-  YYSYMBOL_V = 18,                         /* "v"  */
-  YYSYMBOL_FIL = 19,                       /* "fil"  */
-  YYSYMBOL_FILL = 20,                      /* "fill"  */
-  YYSYMBOL_FILLL = 21,                     /* "filll"  */
-  YYSYMBOL_PENALTY = 22,                   /* "penalty"  */
-  YYSYMBOL_INTEGER = 23,                   /* "int"  */
-  YYSYMBOL_LANGUAGE = 24,                  /* "language"  */
-  YYSYMBOL_RULE = 25,                      /* "rule"  */
-  YYSYMBOL_RUNNING = 26,                   /* "|"  */
-  YYSYMBOL_KERN = 27,                      /* "kern"  */
-  YYSYMBOL_EXPLICIT = 28,                  /* "!"  */
-  YYSYMBOL_GLUE = 29,                      /* "glue"  */
-  YYSYMBOL_PLUS = 30,                      /* "plus"  */
-  YYSYMBOL_MINUS = 31,                     /* "minus"  */
-  YYSYMBOL_TXT_START = 32,                 /* TXT_START  */
-  YYSYMBOL_TXT_END = 33,                   /* TXT_END  */
-  YYSYMBOL_TXT_IGNORE = 34,                /* TXT_IGNORE  */
-  YYSYMBOL_TXT_FONT_GLUE = 35,             /* TXT_FONT_GLUE  */
-  YYSYMBOL_TXT_FONT_HYPHEN = 36,           /* TXT_FONT_HYPHEN  */
-  YYSYMBOL_TXT_FONT = 37,                  /* TXT_FONT  */
-  YYSYMBOL_TXT_LOCAL = 38,                 /* TXT_LOCAL  */
-  YYSYMBOL_TXT_GLOBAL = 39,                /* TXT_GLOBAL  */
-  YYSYMBOL_TXT_CC = 40,                    /* TXT_CC  */
-  YYSYMBOL_HBOX = 41,                      /* "hbox"  */
-  YYSYMBOL_VBOX = 42,                      /* "vbox"  */
-  YYSYMBOL_SHIFTED = 43,                   /* "shifted"  */
-  YYSYMBOL_HPACK = 44,                     /* "hpack"  */
-  YYSYMBOL_HSET = 45,                      /* "hset"  */
-  YYSYMBOL_VPACK = 46,                     /* "vpack"  */
-  YYSYMBOL_VSET = 47,                      /* "vset"  */
-  YYSYMBOL_DEPTH = 48,                     /* "depth"  */
-  YYSYMBOL_ADD = 49,                       /* "add"  */
-  YYSYMBOL_TO = 50,                        /* "to"  */
-  YYSYMBOL_LEADERS = 51,                   /* "leaders"  */
-  YYSYMBOL_ALIGN = 52,                     /* "align"  */
-  YYSYMBOL_CENTER = 53,                    /* "center"  */
-  YYSYMBOL_EXPAND = 54,                    /* "expand"  */
-  YYSYMBOL_BASELINE = 55,                  /* "baseline"  */
-  YYSYMBOL_LIGATURE = 56,                  /* "ligature"  */
-  YYSYMBOL_DISC = 57,                      /* "disc"  */
-  YYSYMBOL_PAR = 58,                       /* "par"  */
-  YYSYMBOL_MATH = 59,                      /* "math"  */
-  YYSYMBOL_ON = 60,                        /* "on"  */
-  YYSYMBOL_OFF = 61,                       /* "off"  */
-  YYSYMBOL_ADJUST = 62,                    /* "adjust"  */
-  YYSYMBOL_TABLE = 63,                     /* "table"  */
-  YYSYMBOL_ITEM = 64,                      /* "item"  */
-  YYSYMBOL_IMAGE = 65,                     /* "image"  */
-  YYSYMBOL_LABEL = 66,                     /* "label"  */
-  YYSYMBOL_BOT = 67,                       /* "bot"  */
-  YYSYMBOL_MID = 68,                       /* "mid"  */
-  YYSYMBOL_LINK = 69,                      /* "link"  */
-  YYSYMBOL_OUTLINE = 70,                   /* "outline"  */
-  YYSYMBOL_STREAM = 71,                    /* "stream"  */
-  YYSYMBOL_STREAMDEF = 72,                 /* "stream (definition)"  */
-  YYSYMBOL_FIRST = 73,                     /* "first"  */
-  YYSYMBOL_LAST = 74,                      /* "last"  */
-  YYSYMBOL_TOP = 75,                       /* "top"  */
-  YYSYMBOL_NOREFERENCE = 76,               /* "*"  */
-  YYSYMBOL_PAGE = 77,                      /* "page"  */
-  YYSYMBOL_RANGE = 78,                     /* "range"  */
-  YYSYMBOL_DIRECTORY = 79,                 /* "directory"  */
-  YYSYMBOL_SECTION = 80,                   /* "entry"  */
-  YYSYMBOL_DEFINITIONS = 81,               /* "definitions"  */
-  YYSYMBOL_MAX = 82,                       /* "max"  */
-  YYSYMBOL_PARAM = 83,                     /* "param"  */
-  YYSYMBOL_FONT = 84,                      /* "font"  */
-  YYSYMBOL_CONTENT = 85,                   /* "content"  */
-  YYSYMBOL_YYACCEPT = 86,                  /* $accept  */
-  YYSYMBOL_glyph = 87,                     /* glyph  */
-  YYSYMBOL_content_node = 88,              /* content_node  */
-  YYSYMBOL_start = 89,                     /* start  */
-  YYSYMBOL_integer = 90,                   /* integer  */
-  YYSYMBOL_string = 91,                    /* string  */
-  YYSYMBOL_number = 92,                    /* number  */
-  YYSYMBOL_dimension = 93,                 /* dimension  */
-  YYSYMBOL_xdimen = 94,                    /* xdimen  */
-  YYSYMBOL_xdimen_node = 95,               /* xdimen_node  */
-  YYSYMBOL_order = 96,                     /* order  */
-  YYSYMBOL_stretch = 97,                   /* stretch  */
-  YYSYMBOL_penalty = 98,                   /* penalty  */
-  YYSYMBOL_rule_dimension = 99,            /* rule_dimension  */
-  YYSYMBOL_rule = 100,                     /* rule  */
-  YYSYMBOL_rule_node = 101,                /* rule_node  */
-  YYSYMBOL_explicit = 102,                 /* explicit  */
-  YYSYMBOL_kern = 103,                     /* kern  */
-  YYSYMBOL_plus = 104,                     /* plus  */
-  YYSYMBOL_minus = 105,                    /* minus  */
-  YYSYMBOL_glue = 106,                     /* glue  */
-  YYSYMBOL_glue_node = 107,                /* glue_node  */
-  YYSYMBOL_position = 108,                 /* position  */
-  YYSYMBOL_content_list = 109,             /* content_list  */
-  YYSYMBOL_estimate = 110,                 /* estimate  */
-  YYSYMBOL_list = 111,                     /* list  */
-  YYSYMBOL_112_1 = 112,                    /* $@1  */
-  YYSYMBOL_text = 113,                     /* text  */
-  YYSYMBOL_txt = 114,                      /* txt  */
-  YYSYMBOL_115_2 = 115,                    /* $@2  */
-  YYSYMBOL_box_dimen = 116,                /* box_dimen  */
-  YYSYMBOL_box_shift = 117,                /* box_shift  */
-  YYSYMBOL_box_glue_set = 118,             /* box_glue_set  */
-  YYSYMBOL_box = 119,                      /* box  */
-  YYSYMBOL_hbox_node = 120,                /* hbox_node  */
-  YYSYMBOL_vbox_node = 121,                /* vbox_node  */
-  YYSYMBOL_box_flex = 122,                 /* box_flex  */
-  YYSYMBOL_xbox = 123,                     /* xbox  */
-  YYSYMBOL_box_goal = 124,                 /* box_goal  */
-  YYSYMBOL_hpack = 125,                    /* hpack  */
-  YYSYMBOL_vpack = 126,                    /* vpack  */
-  YYSYMBOL_127_3 = 127,                    /* $@3  */
-  YYSYMBOL_vxbox_node = 128,               /* vxbox_node  */
-  YYSYMBOL_hxbox_node = 129,               /* hxbox_node  */
-  YYSYMBOL_ltype = 130,                    /* ltype  */
-  YYSYMBOL_leaders = 131,                  /* leaders  */
-  YYSYMBOL_baseline = 132,                 /* baseline  */
-  YYSYMBOL_133_4 = 133,                    /* $@4  */
-  YYSYMBOL_cc_list = 134,                  /* cc_list  */
-  YYSYMBOL_lig_cc = 135,                   /* lig_cc  */
-  YYSYMBOL_ref = 136,                      /* ref  */
-  YYSYMBOL_ligature = 137,                 /* ligature  */
-  YYSYMBOL_138_5 = 138,                    /* $@5  */
-  YYSYMBOL_replace_count = 139,            /* replace_count  */
-  YYSYMBOL_disc = 140,                     /* disc  */
-  YYSYMBOL_disc_node = 141,                /* disc_node  */
-  YYSYMBOL_par_dimen = 142,                /* par_dimen  */
-  YYSYMBOL_par = 143,                      /* par  */
-  YYSYMBOL_144_6 = 144,                    /* $@6  */
-  YYSYMBOL_math = 145,                     /* math  */
-  YYSYMBOL_on_off = 146,                   /* on_off  */
-  YYSYMBOL_span_count = 147,               /* span_count  */
-  YYSYMBOL_table = 148,                    /* table  */
-  YYSYMBOL_image_dimen = 149,              /* image_dimen  */
-  YYSYMBOL_image = 150,                    /* image  */
-  YYSYMBOL_max_value = 151,                /* max_value  */
-  YYSYMBOL_placement = 152,                /* placement  */
-  YYSYMBOL_def_node = 153,                 /* def_node  */
-  YYSYMBOL_stream_link = 154,              /* stream_link  */
-  YYSYMBOL_stream_split = 155,             /* stream_split  */
-  YYSYMBOL_stream_info = 156,              /* stream_info  */
-  YYSYMBOL_157_7 = 157,                    /* $@7  */
-  YYSYMBOL_stream_type = 158,              /* stream_type  */
-  YYSYMBOL_stream_def_node = 159,          /* stream_def_node  */
-  YYSYMBOL_stream_ins_node = 160,          /* stream_ins_node  */
-  YYSYMBOL_stream = 161,                   /* stream  */
-  YYSYMBOL_page_priority = 162,            /* page_priority  */
-  YYSYMBOL_stream_def_list = 163,          /* stream_def_list  */
-  YYSYMBOL_page = 164,                     /* page  */
-  YYSYMBOL_165_8 = 165,                    /* $@8  */
-  YYSYMBOL_166_9 = 166,                    /* $@9  */
-  YYSYMBOL_hint = 167,                     /* hint  */
-  YYSYMBOL_directory_section = 168,        /* directory_section  */
-  YYSYMBOL_169_10 = 169,                   /* $@10  */
-  YYSYMBOL_entry_list = 170,               /* entry_list  */
-  YYSYMBOL_entry = 171,                    /* entry  */
-  YYSYMBOL_definition_section = 172,       /* definition_section  */
-  YYSYMBOL_173_11 = 173,                   /* $@11  */
-  YYSYMBOL_definition_list = 174,          /* definition_list  */
-  YYSYMBOL_max_definitions = 175,          /* max_definitions  */
-  YYSYMBOL_max_list = 176,                 /* max_list  */
-  YYSYMBOL_def_list = 177,                 /* def_list  */
-  YYSYMBOL_parameters = 178,               /* parameters  */
-  YYSYMBOL_empty_param_list = 179,         /* empty_param_list  */
-  YYSYMBOL_non_empty_param_list = 180,     /* non_empty_param_list  */
-  YYSYMBOL_181_12 = 181,                   /* $@12  */
-  YYSYMBOL_font = 182,                     /* font  */
-  YYSYMBOL_font_head = 183,                /* font_head  */
-  YYSYMBOL_font_param_list = 184,          /* font_param_list  */
-  YYSYMBOL_font_param = 185,               /* font_param  */
-  YYSYMBOL_fref = 186,                     /* fref  */
-  YYSYMBOL_xdimen_ref = 187,               /* xdimen_ref  */
-  YYSYMBOL_param_ref = 188,                /* param_ref  */
-  YYSYMBOL_stream_ref = 189,               /* stream_ref  */
-  YYSYMBOL_content_section = 190,          /* content_section  */
-  YYSYMBOL_191_13 = 191                    /* $@13  */
-};
-typedef enum yysymbol_kind_t yysymbol_kind_t;
-
-
-
-
-#ifdef short
-# undef short
-#endif
-
-/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure
-   <limits.h> and (if available) <stdint.h> are included
-   so that the code can choose integer types of a good width.  */
-
-#ifndef __PTRDIFF_MAX__
-# include <limits.h> /* INFRINGES ON USER NAME SPACE */
-# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
-#  include <stdint.h> /* INFRINGES ON USER NAME SPACE */
-#  define YY_STDINT_H
-# endif
-#endif
-
-/* Narrow types that promote to a signed type and that can represent a
-   signed or unsigned integer of at least N bits.  In tables they can
-   save space and decrease cache pressure.  Promoting to a signed type
-   helps avoid bugs in integer arithmetic.  */
-
-#ifdef __INT_LEAST8_MAX__
-typedef __INT_LEAST8_TYPE__ yytype_int8;
-#elif defined YY_STDINT_H
-typedef int_least8_t yytype_int8;
-#else
-typedef signed char yytype_int8;
-#endif
-
-#ifdef __INT_LEAST16_MAX__
-typedef __INT_LEAST16_TYPE__ yytype_int16;
-#elif defined YY_STDINT_H
-typedef int_least16_t yytype_int16;
-#else
-typedef short yytype_int16;
-#endif
-
-/* Work around bug in HP-UX 11.23, which defines these macros
-   incorrectly for preprocessor constants.  This workaround can likely
-   be removed in 2023, as HPE has promised support for HP-UX 11.23
-   (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of
-   <https://h20195.www2.hpe.com/V2/getpdf.aspx/4AA4-7673ENW.pdf>.  */
-#ifdef __hpux
-# undef UINT_LEAST8_MAX
-# undef UINT_LEAST16_MAX
-# define UINT_LEAST8_MAX 255
-# define UINT_LEAST16_MAX 65535
-#endif
-
-#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__
-typedef __UINT_LEAST8_TYPE__ yytype_uint8;
-#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \
-       && UINT_LEAST8_MAX <= INT_MAX)
-typedef uint_least8_t yytype_uint8;
-#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX
-typedef unsigned char yytype_uint8;
-#else
-typedef short yytype_uint8;
-#endif
-
-#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__
-typedef __UINT_LEAST16_TYPE__ yytype_uint16;
-#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \
-       && UINT_LEAST16_MAX <= INT_MAX)
-typedef uint_least16_t yytype_uint16;
-#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX
-typedef unsigned short yytype_uint16;
-#else
-typedef int yytype_uint16;
-#endif
-
-#ifndef YYPTRDIFF_T
-# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__
-#  define YYPTRDIFF_T __PTRDIFF_TYPE__
-#  define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__
-# elif defined PTRDIFF_MAX
-#  ifndef ptrdiff_t
-#   include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-#  endif
-#  define YYPTRDIFF_T ptrdiff_t
-#  define YYPTRDIFF_MAXIMUM PTRDIFF_MAX
-# else
-#  define YYPTRDIFF_T long
-#  define YYPTRDIFF_MAXIMUM LONG_MAX
-# endif
-#endif
-
-#ifndef YYSIZE_T
-# ifdef __SIZE_TYPE__
-#  define YYSIZE_T __SIZE_TYPE__
-# elif defined size_t
-#  define YYSIZE_T size_t
-# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
-#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-#  define YYSIZE_T size_t
-# else
-#  define YYSIZE_T unsigned
-# endif
-#endif
-
-#define YYSIZE_MAXIMUM                                  \
-  YY_CAST (YYPTRDIFF_T,                                 \
-           (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1)  \
-            ? YYPTRDIFF_MAXIMUM                         \
-            : YY_CAST (YYSIZE_T, -1)))
-
-#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X))
-
-
-/* Stored state numbers (used for stacks). */
-typedef yytype_int16 yy_state_t;
-
-/* State numbers in computations.  */
-typedef int yy_state_fast_t;
-
-#ifndef YY_
-# if defined YYENABLE_NLS && YYENABLE_NLS
-#  if ENABLE_NLS
-#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-#   define YY_(Msgid) dgettext ("bison-runtime", Msgid)
-#  endif
-# endif
-# ifndef YY_
-#  define YY_(Msgid) Msgid
-# endif
-#endif
-
-
-#ifndef YY_ATTRIBUTE_PURE
-# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__)
-#  define YY_ATTRIBUTE_PURE __attribute__ ((__pure__))
-# else
-#  define YY_ATTRIBUTE_PURE
-# endif
-#endif
-
-#ifndef YY_ATTRIBUTE_UNUSED
-# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__)
-#  define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__))
-# else
-#  define YY_ATTRIBUTE_UNUSED
-# endif
-#endif
-
-/* Suppress unused-variable warnings by "using" E.  */
-#if ! defined lint || defined __GNUC__
-# define YY_USE(E) ((void) (E))
-#else
-# define YY_USE(E) /* empty */
-#endif
-
-/* Suppress an incorrect diagnostic about yylval being uninitialized.  */
-#if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__
-# if __GNUC__ * 100 + __GNUC_MINOR__ < 407
-#  define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN                           \
-    _Pragma ("GCC diagnostic push")                                     \
-    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")
-# else
-#  define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN                           \
-    _Pragma ("GCC diagnostic push")                                     \
-    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")              \
-    _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
-# endif
-# define YY_IGNORE_MAYBE_UNINITIALIZED_END      \
-    _Pragma ("GCC diagnostic pop")
-#else
-# define YY_INITIAL_VALUE(Value) Value
-#endif
-#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-# define YY_IGNORE_MAYBE_UNINITIALIZED_END
-#endif
-#ifndef YY_INITIAL_VALUE
-# define YY_INITIAL_VALUE(Value) /* Nothing. */
-#endif
-
-#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__
-# define YY_IGNORE_USELESS_CAST_BEGIN                          \
-    _Pragma ("GCC diagnostic push")                            \
-    _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"")
-# define YY_IGNORE_USELESS_CAST_END            \
-    _Pragma ("GCC diagnostic pop")
-#endif
-#ifndef YY_IGNORE_USELESS_CAST_BEGIN
-# define YY_IGNORE_USELESS_CAST_BEGIN
-# define YY_IGNORE_USELESS_CAST_END
-#endif
-
-
-#define YY_ASSERT(E) ((void) (0 && (E)))
-
-#if 1
-
-/* The parser invokes alloca or malloc; define the necessary symbols.  */
-
-# ifdef YYSTACK_USE_ALLOCA
-#  if YYSTACK_USE_ALLOCA
-#   ifdef __GNUC__
-#    define YYSTACK_ALLOC __builtin_alloca
-#   elif defined __BUILTIN_VA_ARG_INCR
-#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
-#   elif defined _AIX
-#    define YYSTACK_ALLOC __alloca
-#   elif defined _MSC_VER
-#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
-#    define alloca _alloca
-#   else
-#    define YYSTACK_ALLOC alloca
-#    if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
-#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-      /* Use EXIT_SUCCESS as a witness for stdlib.h.  */
-#     ifndef EXIT_SUCCESS
-#      define EXIT_SUCCESS 0
-#     endif
-#    endif
-#   endif
-#  endif
-# endif
-
-# ifdef YYSTACK_ALLOC
-   /* Pacify GCC's 'empty if-body' warning.  */
-#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
-#  ifndef YYSTACK_ALLOC_MAXIMUM
-    /* The OS might guarantee only one guard page at the bottom of the stack,
-       and a page size can be as small as 4096 bytes.  So we cannot safely
-       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
-       to allow for a few compiler-allocated temporary stack slots.  */
-#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
-#  endif
-# else
-#  define YYSTACK_ALLOC YYMALLOC
-#  define YYSTACK_FREE YYFREE
-#  ifndef YYSTACK_ALLOC_MAXIMUM
-#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
-#  endif
-#  if (defined __cplusplus && ! defined EXIT_SUCCESS \
-       && ! ((defined YYMALLOC || defined malloc) \
-             && (defined YYFREE || defined free)))
-#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#   ifndef EXIT_SUCCESS
-#    define EXIT_SUCCESS 0
-#   endif
-#  endif
-#  ifndef YYMALLOC
-#   define YYMALLOC malloc
-#   if ! defined malloc && ! defined EXIT_SUCCESS
-void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
-#   endif
-#  endif
-#  ifndef YYFREE
-#   define YYFREE free
-#   if ! defined free && ! defined EXIT_SUCCESS
-void free (void *); /* INFRINGES ON USER NAME SPACE */
-#   endif
-#  endif
-# endif
-#endif /* 1 */
-
-#if (! defined yyoverflow \
-     && (! defined __cplusplus \
-         || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
-
-/* A type that is properly aligned for any stack member.  */
-union yyalloc
-{
-  yy_state_t yyss_alloc;
-  YYSTYPE yyvs_alloc;
-};
-
-/* The size of the maximum gap between one aligned stack and the next.  */
-# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1)
-
-/* The size of an array large to enough to hold all stacks, each with
-   N elements.  */
-# define YYSTACK_BYTES(N) \
-     ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \
-      + YYSTACK_GAP_MAXIMUM)
-
-# define YYCOPY_NEEDED 1
-
-/* Relocate STACK from its old location to the new one.  The
-   local variables YYSIZE and YYSTACKSIZE give the old and new number of
-   elements in the stack, and YYPTR gives the new location of the
-   stack.  Advance YYPTR to a properly aligned location for the next
-   stack.  */
-# define YYSTACK_RELOCATE(Stack_alloc, Stack)                           \
-    do                                                                  \
-      {                                                                 \
-        YYPTRDIFF_T yynewbytes;                                         \
-        YYCOPY (&yyptr->Stack_alloc, Stack, yysize);                    \
-        Stack = &yyptr->Stack_alloc;                                    \
-        yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \
-        yyptr += yynewbytes / YYSIZEOF (*yyptr);                        \
-      }                                                                 \
-    while (0)
-
-#endif
-
-#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
-/* Copy COUNT objects from SRC to DST.  The source and destination do
-   not overlap.  */
-# ifndef YYCOPY
-#  if defined __GNUC__ && 1 < __GNUC__
-#   define YYCOPY(Dst, Src, Count) \
-      __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src)))
-#  else
-#   define YYCOPY(Dst, Src, Count)              \
-      do                                        \
-        {                                       \
-          YYPTRDIFF_T yyi;                      \
-          for (yyi = 0; yyi < (Count); yyi++)   \
-            (Dst)[yyi] = (Src)[yyi];            \
-        }                                       \
-      while (0)
-#  endif
-# endif
-#endif /* !YYCOPY_NEEDED */
-
-/* YYFINAL -- State number of the termination state.  */
-#define YYFINAL  5
-/* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   657
-
-/* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  86
-/* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  106
-/* YYNRULES -- Number of rules.  */
-#define YYNRULES  266
-/* YYNSTATES -- Number of states.  */
-#define YYNSTATES  566
-
-/* YYMAXUTOK -- Last valid token kind.  */
-#define YYMAXUTOK   340
-
-
-/* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM
-   as returned by yylex, with out-of-bounds checking.  */
-#define YYTRANSLATE(YYX)                                \
-  (0 <= (YYX) && (YYX) <= YYMAXUTOK                     \
-   ? YY_CAST (yysymbol_kind_t, yytranslate[YYX])        \
-   : YYSYMBOL_YYUNDEF)
-
-/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
-   as returned by yylex.  */
-static const yytype_int8 yytranslate[] =
-{
-       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
-       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
-      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
-      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
-      35,    36,    37,    38,    39,    40,    41,    42,    43,    44,
-      45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
-      55,    56,    57,    58,    59,    60,    61,    62,    63,    64,
-      65,    66,    67,    68,    69,    70,    71,    72,    73,    74,
-      75,    76,    77,    78,    79,    80,    81,    82,    83,    84,
-      85
-};
-
-#if YYDEBUG
-/* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
-static const yytype_int16 yyrline[] =
-{
-       0,   306,   306,   307,   308,   311,   311,   314,   317,   317,
-     322,   322,   322,   325,   326,   327,   330,   331,   332,   333,
-     337,   341,   341,   341,   341,   343,   346,   347,   350,   350,
-     351,   355,   356,   359,   359,   360,   361,   364,   364,   365,
-     365,   366,   367,   369,   374,   375,   376,   377,   378,   379,
-     385,   384,   389,   389,   391,   392,   393,   394,   395,   396,
-     397,   398,   398,   402,   404,   405,   407,   408,   409,   412,
-     414,   415,   416,   416,   419,   420,   421,   423,   424,   425,
-     426,   428,   429,   429,   431,   432,   435,   436,   438,   438,
-     441,   441,   441,   441,   442,   443,   444,   445,   448,   448,
-     453,   457,   457,   458,   459,   460,   461,   461,   464,   467,
-     468,   470,   472,   473,   476,   479,   482,   483,   484,   485,
-     486,   486,   487,   488,   490,   493,   494,   495,   496,   497,
-     498,   499,   500,   501,   503,   506,   506,   507,   510,   513,
-     514,   515,   516,   518,   519,   521,   524,   524,   525,   526,
-     529,   535,   535,   535,   535,   536,   540,   544,   553,   553,
-     554,   555,   555,   557,   557,   557,   557,   559,   563,   566,
-     566,   569,   570,   571,   572,   576,   577,   579,   579,   581,
-     581,   581,   587,   588,   591,   594,   594,   595,   595,   596,
-     600,   600,   603,   603,   606,   635,   635,   637,   638,   639,
-     640,   641,   642,   643,   644,   645,   646,   647,   648,   649,
-     650,   651,   652,   653,   658,   659,   660,   661,   662,   663,
-     664,   665,   666,   667,   668,   669,   670,   671,   675,   676,
-     677,   680,   681,   682,   685,   686,   686,   691,   693,   696,
-     696,   699,   700,   701,   702,   703,   704,   705,   706,   708,
-     711,   712,   713,   717,   718,   720,   722,   723,   724,   725,
-     726,   727,   728,   729,   731,   737,   737
-};
-#endif
-
-/** Accessing symbol of state STATE.  */
-#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State])
-
-#if 1
-/* The user-facing name of the symbol whose (internal) number is
-   YYSYMBOL.  No bounds checking.  */
-static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED;
-
-/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
-   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
-static const char *const yytname[] =
-{
-  "\"end of file\"", "error", "\"invalid token\"", "\"<\"", "\">\"",
-  "\"glyph\"", "UNSIGNED", "REFERENCE", "SIGNED", "STRING", "CHARCODE",
-  "FPNUM", "\"dimen\"", "\"pt\"", "\"mm\"", "\"in\"", "\"xdimen\"",
-  "\"h\"", "\"v\"", "\"fil\"", "\"fill\"", "\"filll\"", "\"penalty\"",
-  "\"int\"", "\"language\"", "\"rule\"", "\"|\"", "\"kern\"", "\"!\"",
-  "\"glue\"", "\"plus\"", "\"minus\"", "TXT_START", "TXT_END",
-  "TXT_IGNORE", "TXT_FONT_GLUE", "TXT_FONT_HYPHEN", "TXT_FONT",
-  "TXT_LOCAL", "TXT_GLOBAL", "TXT_CC", "\"hbox\"", "\"vbox\"",
-  "\"shifted\"", "\"hpack\"", "\"hset\"", "\"vpack\"", "\"vset\"",
-  "\"depth\"", "\"add\"", "\"to\"", "\"leaders\"", "\"align\"",
-  "\"center\"", "\"expand\"", "\"baseline\"", "\"ligature\"", "\"disc\"",
-  "\"par\"", "\"math\"", "\"on\"", "\"off\"", "\"adjust\"", "\"table\"",
-  "\"item\"", "\"image\"", "\"label\"", "\"bot\"", "\"mid\"", "\"link\"",
-  "\"outline\"", "\"stream\"", "\"stream (definition)\"", "\"first\"",
-  "\"last\"", "\"top\"", "\"*\"", "\"page\"", "\"range\"", "\"directory\"",
-  "\"entry\"", "\"definitions\"", "\"max\"", "\"param\"", "\"font\"",
-  "\"content\"", "$accept", "glyph", "content_node", "start", "integer",
-  "string", "number", "dimension", "xdimen", "xdimen_node", "order",
-  "stretch", "penalty", "rule_dimension", "rule", "rule_node", "explicit",
-  "kern", "plus", "minus", "glue", "glue_node", "position", "content_list",
-  "estimate", "list", "$@1", "text", "txt", "$@2", "box_dimen",
-  "box_shift", "box_glue_set", "box", "hbox_node", "vbox_node", "box_flex",
-  "xbox", "box_goal", "hpack", "vpack", "$@3", "vxbox_node", "hxbox_node",
-  "ltype", "leaders", "baseline", "$@4", "cc_list", "lig_cc", "ref",
-  "ligature", "$@5", "replace_count", "disc", "disc_node", "par_dimen",
-  "par", "$@6", "math", "on_off", "span_count", "table", "image_dimen",
-  "image", "max_value", "placement", "def_node", "stream_link",
-  "stream_split", "stream_info", "$@7", "stream_type", "stream_def_node",
-  "stream_ins_node", "stream", "page_priority", "stream_def_list", "page",
-  "$@8", "$@9", "hint", "directory_section", "$@10", "entry_list", "entry",
-  "definition_section", "$@11", "definition_list", "max_definitions",
-  "max_list", "def_list", "parameters", "empty_param_list",
-  "non_empty_param_list", "$@12", "font", "font_head", "font_param_list",
-  "font_param", "fref", "xdimen_ref", "param_ref", "stream_ref",
-  "content_section", "$@13", YY_NULLPTR
-};
-
-static const char *
-yysymbol_name (yysymbol_kind_t yysymbol)
-{
-  return yytname[yysymbol];
-}
-#endif
-
-#define YYPACT_NINF (-326)
-
-#define yypact_value_is_default(Yyn) \
-  ((Yyn) == YYPACT_NINF)
-
-#define YYTABLE_NINF (-1)
-
-#define yytable_value_is_error(Yyn) \
-  0
-
-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
-   STATE-NUM.  */
-static const yytype_int16 yypact[] =
-{
-      48,    -4,   110,   113,   107,  -326,    52,   137,  -326,  -326,
-      74,  -326,  -326,   153,  -326,   211,    85,  -326,  -326,    94,
-    -326,  -326,  -326,   275,  -326,   278,   190,   280,   159,  -326,
-     313,  -326,    31,  -326,  -326,   585,  -326,  -326,  -326,  -326,
-    -326,  -326,  -326,  -326,   223,   467,  -326,   203,   234,   234,
-     234,   234,   234,   234,   234,   234,   234,   234,   234,   234,
-     234,   234,   240,   248,   116,   219,   253,   140,   210,   229,
-     182,   182,   220,   182,   220,   182,   121,   229,   234,    71,
-     229,    41,    66,   271,    79,   301,   261,   234,   234,  -326,
-    -326,   268,   270,   279,   284,   286,   288,   294,   297,   315,
-     325,   326,   327,   328,   333,   334,   335,   337,   338,   339,
-     343,   242,  -326,   229,   182,   219,   223,   152,   229,   345,
-     182,   234,   210,   348,   223,   350,   223,    82,   251,   323,
-     342,   353,  -326,  -326,  -326,   355,   357,   358,  -326,  -326,
-    -326,  -326,   231,  -326,   152,   359,   361,  -326,   165,   362,
-     182,   341,   372,   373,   182,   220,   375,   377,   182,   264,
-     379,   220,   380,   305,   384,   385,  -326,   363,   200,   387,
-     389,  -326,   390,   391,   395,   396,   398,   397,    66,   401,
-     234,  -326,  -326,   404,   234,  -326,  -326,  -326,  -326,   405,
-    -326,    66,    66,  -326,   350,   406,   264,   264,   407,  -326,
-     408,   530,   409,   399,   182,   410,   411,   255,  -326,   234,
-      80,  -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,
-    -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,
-    -326,  -326,   413,   414,   416,   417,   418,   419,   421,   422,
-     423,   427,   429,  -326,   430,   432,   433,  -326,   435,  -326,
-    -326,   436,   182,   437,   345,  -326,  -326,  -326,   438,   440,
-     441,  -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,
-     152,  -326,  -326,   234,  -326,   442,  -326,   302,   182,   420,
-    -326,  -326,   182,   293,  -326,  -326,  -326,   121,   121,    66,
-    -326,   341,  -326,   400,  -326,  -326,   229,  -326,  -326,  -326,
-     345,  -326,  -326,   345,  -326,  -326,  -326,   176,  -326,  -326,
-    -326,    66,  -326,  -326,    66,  -326,    66,    66,  -326,    38,
-     345,    66,    66,    53,   345,    66,  -326,  -326,  -326,    66,
-      66,  -326,  -326,  -326,   445,   182,   341,  -326,  -326,   446,
-     448,    66,    66,  -326,  -326,  -326,  -326,   439,   450,  -326,
-      66,    66,  -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,
-    -326,  -326,  -326,  -326,  -326,  -326,   452,  -326,  -326,   451,
-    -326,   453,  -326,   345,   345,  -326,  -326,  -326,  -326,   456,
-    -326,   182,  -326,   164,  -326,   182,  -326,  -326,   182,   182,
-      66,  -326,  -326,  -326,  -326,  -326,   420,   121,   182,   458,
-     460,    49,  -326,  -326,  -326,   345,  -326,  -326,   434,  -326,
-      66,    35,  -326,    66,  -326,    66,  -326,  -326,   424,  -326,
-    -326,   345,    66,  -326,  -326,  -326,   324,    66,    66,  -326,
-    -326,   420,  -326,  -326,  -326,    66,  -326,   182,  -326,   345,
-     463,  -326,   345,  -326,   462,   412,  -326,   105,  -326,  -326,
-     454,  -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,
-    -326,    66,    66,  -326,  -326,  -326,   152,  -326,  -326,  -326,
-    -326,  -326,   350,  -326,  -326,  -326,   184,  -326,  -326,  -326,
-    -326,  -326,   466,    39,   345,  -326,   182,  -326,   210,   234,
-     234,   234,   234,   234,   234,   234,   234,  -326,  -326,  -326,
-     264,    72,   471,  -326,  -326,  -326,  -326,  -326,  -326,  -326,
-    -326,  -326,   399,  -326,  -326,  -326,    39,  -326,    66,  -326,
-    -326,   242,   223,   152,   210,   182,   234,   210,   348,    66,
-    -326,  -326,  -326,  -326,   470,   345,   345,   473,   476,   478,
-     182,   480,   481,   482,   483,   484,  -326,  -326,   489,   345,
-    -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,    66,
-    -326,   345,   425,  -326,   234,    69
-};
-
-/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
-   Performed when YYTABLE does not specify something else to do.  Zero
-   means the default is an error.  */
-static const yytype_int16 yydefact[] =
-{
-       0,     0,     0,     0,     0,     1,     0,     0,   185,   190,
-       0,   184,   187,     0,   265,     0,     0,   192,    44,     0,
-     186,   188,   195,     0,    45,     0,     0,     0,     4,   191,
-       0,   193,     4,   266,    46,     0,    32,    72,    73,    88,
-      89,   115,   169,   170,     0,     0,   194,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,    33,     0,
-       0,     0,    64,     0,    64,     0,     0,     0,     0,    33,
-       0,    44,     0,     0,     0,     0,     0,     0,     0,     8,
-       9,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,   105,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,    33,     0,     0,    47,     0,   154,     0,     0,
-       0,     0,     6,     5,    26,     0,     0,     0,    10,    11,
-      12,    29,     0,    28,     0,     0,     0,    34,     0,     0,
-      19,    37,     0,     0,     0,    64,     0,     0,     0,     0,
-       0,    64,     0,     0,     0,     0,     4,     0,    90,     0,
-       0,    98,     0,     0,   106,     0,   109,     0,   113,     0,
-     116,   250,    44,     0,    44,   135,   136,   234,   251,     0,
-     137,     0,     0,    44,    47,     0,     0,     0,     0,   139,
-       0,    47,     0,     0,   147,     0,     0,     0,   252,    44,
-       0,   189,   199,   208,   198,   203,   204,   202,   206,   207,
-     200,   201,   205,   213,   150,   210,   211,   212,   209,   197,
-     196,    44,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,   106,     0,     0,     0,   179,     0,    48,
-      44,     0,     0,     0,     0,   152,   153,   151,     0,     0,
-       0,     2,     7,     3,    27,   253,   263,    13,    15,    14,
-       0,    31,   259,     0,    35,     0,    36,     0,     0,    39,
-      42,   256,     0,    66,    70,    71,    65,     0,     0,     0,
-      87,    37,    86,     0,    85,    84,     0,    91,    92,    93,
-       0,    97,   261,     0,   100,   262,   257,     0,   108,   110,
-     258,   112,   114,   120,     0,   124,     0,     0,   134,    47,
-     128,     0,     0,    47,   125,     0,    50,    44,   138,     0,
-       0,   145,   140,   142,     0,     0,    37,   260,   149,     0,
-       0,     0,     0,   168,   164,   165,   166,     0,     0,   163,
-       0,     0,   216,   229,   219,   215,   228,   217,   220,   218,
-     230,   221,   222,   223,   224,   225,   175,   227,   231,   233,
-     226,     0,   214,     0,   237,   155,   182,   183,    30,     0,
-     254,    17,    18,     0,    38,     0,    41,    63,     0,     0,
-       0,    80,    78,    79,    77,    81,    39,     0,     0,     0,
-       0,     0,    94,    95,    96,     0,   103,   104,     0,   111,
-       0,    47,   123,     0,   119,     0,   117,   235,     0,   129,
-     130,   131,     0,   126,   127,    44,     0,     0,     0,   141,
-     146,    39,   156,   174,   171,     0,   173,     0,   161,     0,
-       0,   176,     0,   232,     0,     0,   239,     0,   240,   255,
-       0,    21,    22,    23,    24,    25,    40,    67,    68,    69,
-      74,     0,     0,    82,    43,   264,     0,    99,   101,   121,
-     122,   118,    47,   132,   133,    52,    61,    49,   143,   144,
-     148,   172,     0,     0,     0,   157,     0,   238,    33,     0,
-       0,     0,     0,     0,     0,     0,     0,    16,    76,    75,
-       0,     0,     0,    51,    60,    58,    59,    55,    57,    56,
-      54,    53,     0,    20,   159,   158,     0,   162,     0,   180,
-     249,     0,     0,     0,    33,     0,     0,    33,     0,     0,
-     107,   102,   236,    62,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,    83,   160,     0,     0,
-     241,   246,   247,   242,   245,   243,   244,   248,   167,     0,
-     177,   181,     0,   178,     0,     0
-};
-
-/* YYPGOTO[NTERM-NUM].  */
-static const yytype_int16 yypgoto[] =
-{
-    -326,  -326,   -65,   -23,    97,   -79,   -83,   -13,   -62,  -232,
-    -326,  -191,   -27,  -118,   -94,   195,   -67,   -26,  -228,  -325,
-     -97,  -226,    -1,   172,   -86,   -55,  -326,  -326,  -326,  -326,
-     198,   -36,  -326,   431,  -111,   201,  -326,   428,  -147,  -326,
-    -326,  -326,  -326,  -326,  -326,   381,   386,  -326,  -326,  -326,
-     -45,   -96,  -326,  -326,   -95,   132,  -326,  -326,  -326,  -326,
-     300,  -326,  -326,  -326,   -93,  -326,  -326,   139,    -7,  -326,
-    -326,  -326,  -326,   -50,  -326,  -326,  -326,  -326,  -326,  -326,
-    -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,  -326,
-    -326,  -326,    42,   -89,  -227,  -326,  -326,  -326,  -326,  -326,
-    -290,  -222,   -92,  -326,  -326,  -326
-};
-
-/* YYDEFGOTO[NTERM-NUM].  */
-static const yytype_int16 yydefgoto[] =
-{
-       0,   131,    34,   194,   134,    91,   142,   150,   151,   348,
-     455,   384,   135,   144,   145,    36,   176,   149,   279,   386,
-     152,   168,   187,    25,   327,   195,   425,   476,   511,   512,
-     155,   159,   390,   156,    37,    38,   397,   162,   289,   160,
-     164,   500,    39,    40,   300,   169,   172,   303,   501,   408,
-     520,   175,   307,   178,   179,    41,   182,   183,   410,   189,
-     190,   203,   198,   336,   206,   110,   258,    31,   516,   517,
-     349,   483,   350,    42,    43,   340,   442,   561,   248,   366,
-     536,     2,     3,    12,    15,    21,     7,    13,    23,    17,
-      27,   369,   251,   191,   322,   472,   253,   254,   374,   448,
-     521,   184,   192,   209,    11,    18
-};
-
-/* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
-   positive, shift that token.  If negative, reduce the rule whose
-   number is the opposite.  If YYTABLE_NINF, syntax error.  */
-static const yytype_int16 yytable[] =
-{
-      30,   148,    35,   113,   114,   115,   116,   117,   118,   119,
-     120,   121,   122,   123,   124,   125,   126,    24,   180,   200,
-     136,   239,   146,   238,   153,   244,   270,   245,   373,   202,
-     246,   170,   173,   174,   177,   181,   188,   237,   163,   250,
-     205,   249,   208,   210,   249,   247,   112,   252,   112,   329,
-     330,     1,   234,   167,   143,   391,   393,   154,   154,   249,
-     154,   201,   154,   396,   171,   392,   394,   277,   233,   166,
-     236,   460,   166,   240,   466,     4,   243,   405,   112,    70,
-     321,   325,    32,   166,   343,   199,   274,   413,   313,   415,
-      70,    71,   317,   314,    70,   316,   167,    62,   193,   147,
-     232,   185,   186,   275,   143,   530,   480,   171,   431,    63,
-       5,   193,   531,     8,   435,   514,     6,   342,   417,   283,
-     341,   417,   129,   311,   166,   291,   130,   489,   112,   490,
-     491,   143,   492,     9,   493,   188,   320,   324,   334,   188,
-      10,   282,   344,   345,   346,   286,   138,   112,   139,   255,
-     256,   140,   378,   344,   345,   346,    16,   257,   138,    14,
-     139,   494,   495,   140,   188,   461,   141,    22,   319,   323,
-     496,   138,   112,   139,    26,   462,   140,   451,   141,   467,
-      35,   273,   406,   452,   453,   454,   407,   347,   138,   403,
-     139,   335,   326,   140,   456,   383,    44,   457,   458,   399,
-     522,   523,   524,   525,   526,   527,   528,   484,   231,   419,
-     111,   422,   235,   423,    19,    20,   486,   503,   504,   505,
-     506,   507,   508,   509,   510,   132,   112,   133,   379,    47,
-     351,   167,    89,    90,   395,   138,   112,   139,   147,   371,
-     140,   112,   181,   181,   267,   268,   269,   127,   132,   368,
-     133,   400,   297,   298,   299,   128,   409,   143,   518,   412,
-     137,   414,   416,   158,   347,   347,   420,   421,   207,   387,
-     424,   161,   211,   161,   427,   428,   212,   401,    28,    29,
-     167,    32,    33,    45,    46,   213,   434,   436,   196,   197,
-     214,   411,   215,   411,   216,   439,   440,   418,   450,   323,
-     217,   418,   383,   218,   549,   383,   383,   204,   112,   548,
-     473,   259,   260,   287,   288,   185,   186,   559,   411,   381,
-     382,   219,   430,   388,   389,    48,    24,    32,   477,    49,
-     261,   220,   221,   222,   223,   459,    50,    51,    52,   224,
-     225,   226,    53,   227,   228,   229,    30,   230,   166,   262,
-     445,   447,   181,   529,   204,   469,   249,   263,   470,   264,
-     471,   265,   266,   271,    54,   272,   276,   474,    55,    56,
-      57,   278,   478,   479,   347,   482,   280,   281,    58,   284,
-     481,   285,   167,   290,   292,   463,   250,   293,   294,   295,
-      59,   301,   296,   302,   304,   305,    60,    61,   418,   306,
-     308,   310,    32,    35,   309,   312,   498,   499,   315,   318,
-     328,   331,   332,   333,   337,   338,   347,   352,   353,   167,
-     354,   355,   356,   357,   475,   358,   359,   360,   542,   539,
-     543,   361,   544,   362,   363,   545,   364,   365,   515,   367,
-     370,   372,   375,   538,   376,   377,   380,   533,   398,   429,
-     432,   385,   433,   143,    28,   437,   438,   540,   441,   444,
-     449,   167,   464,   535,   465,    70,   468,   485,   487,   488,
-     513,   515,   497,   519,   546,   532,   547,   550,   274,    92,
-     551,   243,   552,    93,   553,   554,   555,   556,   557,    35,
-      94,    95,    96,   558,   537,   402,    97,   564,   541,   426,
-     241,   404,   157,   165,   560,   446,   242,   339,   443,   534,
-     143,   563,   167,   347,   502,     0,     0,     0,    98,   565,
-       0,     0,    99,   100,   101,     0,   347,     0,     0,     0,
-       0,     0,   102,   103,     0,    64,   249,   104,   562,   105,
-       0,     0,   347,     0,   106,   107,     0,     0,     0,     0,
-     108,   109,    65,     0,    66,    67,     0,    68,     0,    69,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,    70,    71,     0,    72,    73,    74,    75,     0,     0,
-       0,    76,     0,     0,     0,    77,    78,    79,    80,    81,
-      64,     0,    82,    83,    84,    85,     0,     0,     0,    86,
-       0,    87,    88,     0,     0,     0,     0,    65,     0,    66,
-      67,     0,    68,     0,    69,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,    70,    71,     0,    72,
-      73,    74,    75,     0,     0,     0,    76,     0,     0,     0,
-      77,    78,    79,    80,    81,     0,     0,    82,    83,    84,
-      85,     0,     0,     0,    86,     0,    87,    88
-};
-
-static const yytype_int16 yycheck[] =
-{
-      23,    68,    25,    48,    49,    50,    51,    52,    53,    54,
-      55,    56,    57,    58,    59,    60,    61,    18,    80,    84,
-      65,   118,    67,   117,    69,   121,   144,   122,   254,    84,
-     123,    76,    77,    78,    79,    80,    81,   116,    74,   125,
-      85,     6,    87,    88,     6,   124,     7,   126,     7,   196,
-     197,     3,   114,    76,    67,   287,   288,    70,    71,     6,
-      73,    84,    75,   291,    77,   287,   288,   150,   113,     3,
-     115,   396,     3,   118,    25,    79,   121,   303,     7,    41,
-     191,   192,     3,     3,     4,     6,   148,   314,   180,   316,
-      41,    42,   184,   182,    41,   184,   119,    66,    32,    28,
-     113,    60,    61,   148,   117,    33,   431,   120,   336,    78,
-       0,    32,    40,     6,   341,    76,     3,   209,    83,   155,
-     209,    83,     6,   178,     3,   161,    10,    22,     7,    24,
-      25,   144,    27,    81,    29,   180,   191,   192,   203,   184,
-       3,   154,    73,    74,    75,   158,     6,     7,     8,    67,
-      68,    11,   270,    73,    74,    75,     3,    75,     6,    85,
-       8,    56,    57,    11,   209,   397,    26,    82,   191,   192,
-      65,     6,     7,     8,    80,   397,    11,    13,    26,   405,
-     203,    16,     6,    19,    20,    21,    10,   210,     6,   300,
-       8,   204,   193,    11,   385,   278,     6,   388,   389,   296,
-     490,   491,   492,   493,   494,   495,   496,   439,   111,   320,
-       7,   322,   115,   324,     3,     4,   442,    33,    34,    35,
-      36,    37,    38,    39,    40,     6,     7,     8,   273,    70,
-     231,   254,     9,    10,   289,     6,     7,     8,    28,   252,
-      11,     7,   287,   288,    13,    14,    15,     7,     6,   250,
-       8,   296,    52,    53,    54,     7,   311,   270,   484,   314,
-       7,   316,   317,    43,   287,   288,   321,   322,     7,   282,
-     325,    73,     4,    75,   329,   330,     6,   300,     3,     4,
-     303,     3,     4,     3,     4,     6,   341,   342,    17,    18,
-       6,   314,     6,   316,     6,   350,   351,   320,   381,   322,
-       6,   324,   385,     6,   536,   388,   389,     6,     7,   535,
-     421,    60,    61,    49,    50,    60,    61,   549,   341,    17,
-      18,     6,   335,    30,    31,    12,   327,     3,     4,    16,
-       7,     6,     6,     6,     6,   390,    23,    24,    25,     6,
-       6,     6,    29,     6,     6,     6,   369,     4,     3,     7,
-     373,   374,   397,   500,     6,   410,     6,     4,   413,     4,
-     415,     4,     4,     4,    51,     4,     4,   422,    55,    56,
-      57,    30,   427,   428,   397,   437,     4,     4,    65,     4,
-     435,     4,   405,     4,     4,   398,   472,    82,     4,     4,
-      77,     4,    29,     4,     4,     4,    83,    84,   421,     4,
-       4,     4,     3,   426,     6,     4,   461,   462,     4,     4,
-       4,     4,     4,     4,     4,     4,   439,     4,     4,   442,
-       4,     4,     4,     4,   425,     4,     4,     4,   525,   523,
-     526,     4,   527,     4,     4,   528,     4,     4,   483,     4,
-       4,     4,     4,   522,     4,     4,     4,   512,    48,     4,
-       4,    31,     4,   466,     3,    16,     6,   524,     6,     6,
-       4,   484,     4,   518,     4,    41,    32,     4,     6,    57,
-       4,   516,    18,   486,   529,     4,     6,     4,   540,    12,
-       4,   526,     4,    16,     4,     4,     4,     4,     4,   512,
-      23,    24,    25,     4,   521,   300,    29,    72,   524,   327,
-     119,   300,    71,    75,   559,   373,   120,   207,   369,   516,
-     523,   561,   535,   536,   472,    -1,    -1,    -1,    51,   564,
-      -1,    -1,    55,    56,    57,    -1,   549,    -1,    -1,    -1,
-      -1,    -1,    65,    66,    -1,     5,     6,    70,   561,    72,
-      -1,    -1,   565,    -1,    77,    78,    -1,    -1,    -1,    -1,
-      83,    84,    22,    -1,    24,    25,    -1,    27,    -1,    29,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    41,    42,    -1,    44,    45,    46,    47,    -1,    -1,
-      -1,    51,    -1,    -1,    -1,    55,    56,    57,    58,    59,
-       5,    -1,    62,    63,    64,    65,    -1,    -1,    -1,    69,
-      -1,    71,    72,    -1,    -1,    -1,    -1,    22,    -1,    24,
-      25,    -1,    27,    -1,    29,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    41,    42,    -1,    44,
-      45,    46,    47,    -1,    -1,    -1,    51,    -1,    -1,    -1,
-      55,    56,    57,    58,    59,    -1,    -1,    62,    63,    64,
-      65,    -1,    -1,    -1,    69,    -1,    71,    72
-};
-
-/* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of
-   state STATE-NUM.  */
-static const yytype_uint8 yystos[] =
-{
-       0,     3,   167,   168,    79,     0,     3,   172,     6,    81,
-       3,   190,   169,   173,    85,   170,     3,   175,   191,     3,
-       4,   171,    82,   174,   108,   109,    80,   176,     3,     4,
-      89,   153,     3,     4,    88,    89,   101,   120,   121,   128,
-     129,   141,   159,   160,     6,     3,     4,    70,    12,    16,
-      23,    24,    25,    29,    51,    55,    56,    57,    65,    77,
-      83,    84,    66,    78,     5,    22,    24,    25,    27,    29,
-      41,    42,    44,    45,    46,    47,    51,    55,    56,    57,
-      58,    59,    62,    63,    64,    65,    69,    71,    72,     9,
-      10,    91,    12,    16,    23,    24,    25,    29,    51,    55,
-      56,    57,    65,    66,    70,    72,    77,    78,    83,    84,
-     151,     7,     7,   136,   136,   136,   136,   136,   136,   136,
-     136,   136,   136,   136,   136,   136,   136,     7,     7,     6,
-      10,    87,     6,     8,    90,    98,   136,     7,     6,     8,
-      11,    26,    92,    93,    99,   100,   136,    28,   102,   103,
-      93,    94,   106,   136,    93,   116,   119,   119,    43,   117,
-     125,   116,   123,   117,   126,   123,     3,    89,   107,   131,
-     136,    93,   132,   136,   136,   137,   102,   136,   139,   140,
-      94,   136,   142,   143,   187,    60,    61,   108,   136,   145,
-     146,   179,   188,    32,    89,   111,    17,    18,   148,     6,
-      88,    89,   111,   147,     6,   136,   150,     7,   136,   189,
-     136,     4,     6,     6,     6,     6,     6,     6,     6,     6,
-       6,     6,     6,     6,     6,     6,     6,     6,     6,     6,
-       4,    90,    93,   136,    94,    90,   136,    91,   100,   106,
-     136,   131,   132,   136,   137,   140,   150,    91,   164,     6,
-     110,   178,    91,   182,   183,    67,    68,    75,   152,    60,
-      61,     7,     7,     4,     4,     4,     4,    13,    14,    15,
-      99,     4,     4,    16,    94,   136,     4,    92,    30,   104,
-       4,     4,    93,   117,     4,     4,    93,    49,    50,   124,
-       4,   117,     4,    82,     4,     4,    29,    52,    53,    54,
-     130,     4,     4,   133,     4,     4,     4,   138,     4,     6,
-       4,   111,     4,   188,   179,     4,   179,   188,     4,    89,
-     111,   120,   180,    89,   111,   120,   108,   110,     4,   124,
-     124,     4,     4,     4,    88,    93,   149,     4,     4,   146,
-     161,   179,   188,     4,    73,    74,    75,    89,    95,   156,
-     158,   108,     4,     4,     4,     4,     4,     4,     4,     4,
-       4,     4,     4,     4,     4,     4,   165,     4,   108,   177,
-       4,    93,     4,   107,   184,     4,     4,     4,    99,   136,
-       4,    17,    18,    92,    97,    31,   105,    93,    30,    31,
-     118,    95,   187,    95,   187,   111,   104,   122,    48,   106,
-     136,    89,   101,   120,   121,   107,     6,    10,   135,   111,
-     144,    89,   111,   180,   111,   180,   111,    83,    89,   120,
-     111,   111,   120,   120,   111,   112,   109,   111,   111,     4,
-      93,   104,     4,     4,   111,   180,   111,    16,     6,   111,
-     111,     6,   162,   153,     6,    89,   141,    89,   185,     4,
-      92,    13,    19,    20,    21,    96,    97,    97,    97,   111,
-     105,    95,   187,    93,     4,     4,    25,   107,    32,   111,
-     111,   111,   181,   120,   111,   108,   113,     4,   111,   111,
-     105,   111,    94,   157,    95,     4,   107,     6,    57,    22,
-      24,    25,    27,    29,    56,    57,    65,    18,   111,   111,
-     127,   134,   178,    33,    34,    35,    36,    37,    38,    39,
-      40,   114,   115,     4,    76,   136,   154,   155,   107,    93,
-     136,   186,   186,   186,   186,   186,   186,   186,   186,   124,
-      33,    40,     4,    88,   154,   111,   166,    98,    91,   100,
-     102,   103,   106,   137,   140,   150,   111,     6,   107,    95,
-       4,     4,     4,     4,     4,     4,     4,     4,     4,    95,
-     111,   163,    89,   159,    72,   136
-};
-
-/* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM.  */
-static const yytype_uint8 yyr1[] =
-{
-       0,    86,    87,    88,    89,    90,    90,    87,    91,    91,
-      92,    92,    92,    93,    93,    93,    94,    94,    94,    94,
-      95,    96,    96,    96,    96,    97,    98,    88,    99,    99,
-     100,   101,    88,   102,   102,   103,    88,   104,   104,   105,
-     105,   106,    88,   107,   108,   109,   109,   110,   110,   111,
-     112,   111,   113,   113,   114,   114,   114,   114,   114,   114,
-     114,   115,   114,   116,   117,   117,   118,   118,   118,   119,
-     120,   121,    88,    88,   122,   123,   123,   124,   124,   124,
-     124,   125,   127,   126,   128,   128,   129,   129,    88,    88,
-     130,   130,   130,   130,   131,   131,   131,    88,   133,   132,
-      88,   134,   134,   135,   135,   136,   138,   137,    88,   139,
-     139,   140,   140,   140,   141,    88,   142,   143,   143,   143,
-     144,   143,   143,   143,    88,   145,   145,   145,   145,   145,
-     145,   145,   145,   145,    88,   146,   146,   145,    88,   147,
-      88,    88,    88,   148,   148,    88,   149,   149,   150,    88,
-     151,   152,   152,   152,   152,    88,    88,   153,   154,   154,
-     155,   157,   156,   158,   158,   158,   158,   159,   160,    88,
-      88,   161,   161,   161,    88,   162,   162,   163,   163,   165,
-     166,   164,    88,    88,   167,   169,   168,   170,   170,   171,
-     173,   172,   174,   174,   175,   176,   176,   151,   151,   151,
-     151,   151,   151,   151,   151,   151,   151,   151,   151,   151,
-     151,   151,   151,   151,   153,   153,   153,   153,   153,   153,
-     153,   153,   153,   153,   153,   153,   153,   153,   153,   153,
-     153,   177,   177,   178,   179,   181,   180,   182,   183,   184,
-     184,   185,   185,   185,   185,   185,   185,   185,   185,   186,
-     187,   188,   189,    88,    88,    88,    88,    88,    88,    88,
-      88,    88,    88,    88,   107,   191,   190
-};
-
-/* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM.  */
-static const yytype_int8 yyr2[] =
-{
-       0,     2,     2,     4,     1,     1,     1,     2,     1,     1,
-       1,     1,     1,     2,     2,     2,     5,     3,     3,     1,
-       4,     1,     1,     1,     1,     2,     1,     4,     1,     1,
-       3,     4,     1,     0,     1,     2,     4,     0,     2,     0,
-       2,     3,     4,     4,     0,     1,     2,     0,     1,     4,
-       0,     5,     1,     2,     1,     1,     1,     1,     1,     1,
-       1,     0,     2,     3,     0,     2,     0,     2,     2,     4,
-       4,     4,     1,     1,     2,     5,     5,     2,     2,     2,
-       2,     3,     0,     7,     4,     4,     4,     4,     1,     1,
-       0,     1,     1,     1,     3,     3,     3,     4,     0,     4,
-       4,     0,     2,     1,     1,     1,     0,     6,     4,     1,
-       2,     3,     2,     1,     4,     1,     1,     3,     4,     3,
-       0,     4,     4,     3,     4,     2,     3,     3,     2,     3,
-       3,     3,     4,     4,     4,     1,     1,     1,     4,     1,
-       4,     5,     4,     4,     4,     4,     2,     0,     4,     4,
-       2,     1,     1,     1,     0,     5,     5,     7,     1,     1,
-       3,     0,     4,     1,     1,     1,     1,    10,     4,     1,
-       1,     2,     3,     2,     5,     0,     1,     0,     2,     0,
-       0,    10,     5,     5,     3,     0,     6,     0,     2,     5,
-       0,     6,     0,     2,     4,     0,     4,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     5,     5,     5,     5,     5,     5,
-       5,     5,     5,     5,     5,     5,     5,     5,     5,     5,
-       5,     1,     2,     2,     1,     0,     5,     2,     4,     2,
-       2,     5,     5,     5,     5,     5,     5,     5,     5,     1,
-       1,     1,     1,     4,     5,     6,     4,     4,     4,     4,
-       4,     4,     4,     4,     4,     0,     5
-};
-
-
-enum { YYENOMEM = -2 };
-
-#define yyerrok         (yyerrstatus = 0)
-#define yyclearin       (yychar = YYEMPTY)
-
-#define YYACCEPT        goto yyacceptlab
-#define YYABORT         goto yyabortlab
-#define YYERROR         goto yyerrorlab
-#define YYNOMEM         goto yyexhaustedlab
-
-
-#define YYRECOVERING()  (!!yyerrstatus)
-
-#define YYBACKUP(Token, Value)                                    \
-  do                                                              \
-    if (yychar == YYEMPTY)                                        \
-      {                                                           \
-        yychar = (Token);                                         \
-        yylval = (Value);                                         \
-        YYPOPSTACK (yylen);                                       \
-        yystate = *yyssp;                                         \
-        goto yybackup;                                            \
-      }                                                           \
-    else                                                          \
-      {                                                           \
-        yyerror (YY_("syntax error: cannot back up")); \
-        YYERROR;                                                  \
-      }                                                           \
-  while (0)
-
-/* Backward compatibility with an undocumented macro.
-   Use YYerror or YYUNDEF. */
-#define YYERRCODE YYUNDEF
-
-
-/* Enable debugging if requested.  */
-#if YYDEBUG
-
-# ifndef YYFPRINTF
-#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-#  define YYFPRINTF fprintf
-# endif
-
-# define YYDPRINTF(Args)                        \
-do {                                            \
-  if (yydebug)                                  \
-    YYFPRINTF Args;                             \
-} while (0)
-
-
-
-
-# define YY_SYMBOL_PRINT(Title, Kind, Value, Location)                    \
-do {                                                                      \
-  if (yydebug)                                                            \
-    {                                                                     \
-      YYFPRINTF (stderr, "%s ", Title);                                   \
-      yy_symbol_print (stderr,                                            \
-                  Kind, Value); \
-      YYFPRINTF (stderr, "\n");                                           \
-    }                                                                     \
-} while (0)
-
-
-/*-----------------------------------.
-| Print this symbol's value on YYO.  |
-`-----------------------------------*/
-
-static void
-yy_symbol_value_print (FILE *yyo,
-                       yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep)
-{
-  FILE *yyoutput = yyo;
-  YY_USE (yyoutput);
-  if (!yyvaluep)
-    return;
-  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-  YY_USE (yykind);
-  YY_IGNORE_MAYBE_UNINITIALIZED_END
-}
-
-
-/*---------------------------.
-| Print this symbol on YYO.  |
-`---------------------------*/
-
-static void
-yy_symbol_print (FILE *yyo,
-                 yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep)
-{
-  YYFPRINTF (yyo, "%s %s (",
-             yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind));
-
-  yy_symbol_value_print (yyo, yykind, yyvaluep);
-  YYFPRINTF (yyo, ")");
-}
-
-/*------------------------------------------------------------------.
-| yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (included).                                                   |
-`------------------------------------------------------------------*/
-
-static void
-yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop)
-{
-  YYFPRINTF (stderr, "Stack now");
-  for (; yybottom <= yytop; yybottom++)
-    {
-      int yybot = *yybottom;
-      YYFPRINTF (stderr, " %d", yybot);
-    }
-  YYFPRINTF (stderr, "\n");
-}
-
-# define YY_STACK_PRINT(Bottom, Top)                            \
-do {                                                            \
-  if (yydebug)                                                  \
-    yy_stack_print ((Bottom), (Top));                           \
-} while (0)
-
-
-/*------------------------------------------------.
-| Report that the YYRULE is going to be reduced.  |
-`------------------------------------------------*/
-
-static void
-yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp,
-                 int yyrule)
-{
-  int yylno = yyrline[yyrule];
-  int yynrhs = yyr2[yyrule];
-  int yyi;
-  YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n",
-             yyrule - 1, yylno);
-  /* The symbols being reduced.  */
-  for (yyi = 0; yyi < yynrhs; yyi++)
-    {
-      YYFPRINTF (stderr, "   $%d = ", yyi + 1);
-      yy_symbol_print (stderr,
-                       YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]),
-                       &yyvsp[(yyi + 1) - (yynrhs)]);
-      YYFPRINTF (stderr, "\n");
-    }
-}
-
-# define YY_REDUCE_PRINT(Rule)          \
-do {                                    \
-  if (yydebug)                          \
-    yy_reduce_print (yyssp, yyvsp, Rule); \
-} while (0)
-
-/* Nonzero means print parse trace.  It is left uninitialized so that
-   multiple parsers can coexist.  */
-int yydebug;
-#else /* !YYDEBUG */
-# define YYDPRINTF(Args) ((void) 0)
-# define YY_SYMBOL_PRINT(Title, Kind, Value, Location)
-# define YY_STACK_PRINT(Bottom, Top)
-# define YY_REDUCE_PRINT(Rule)
-#endif /* !YYDEBUG */
-
-
-/* YYINITDEPTH -- initial size of the parser's stacks.  */
-#ifndef YYINITDEPTH
-# define YYINITDEPTH 200
-#endif
-
-/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
-   if the built-in stack extension method is used).
-
-   Do not make this value too large; the results are undefined if
-   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
-   evaluated with infinite-precision integer arithmetic.  */
-
-#ifndef YYMAXDEPTH
-# define YYMAXDEPTH 10000
-#endif
-
-
-/* Context of a parse error.  */
-typedef struct
-{
-  yy_state_t *yyssp;
-  yysymbol_kind_t yytoken;
-} yypcontext_t;
-
-/* Put in YYARG at most YYARGN of the expected tokens given the
-   current YYCTX, and return the number of tokens stored in YYARG.  If
-   YYARG is null, return the number of expected tokens (guaranteed to
-   be less than YYNTOKENS).  Return YYENOMEM on memory exhaustion.
-   Return 0 if there are more than YYARGN expected tokens, yet fill
-   YYARG up to YYARGN. */
-static int
-yypcontext_expected_tokens (const yypcontext_t *yyctx,
-                            yysymbol_kind_t yyarg[], int yyargn)
-{
-  /* Actual size of YYARG. */
-  int yycount = 0;
-  int yyn = yypact[+*yyctx->yyssp];
-  if (!yypact_value_is_default (yyn))
-    {
-      /* Start YYX at -YYN if negative to avoid negative indexes in
-         YYCHECK.  In other words, skip the first -YYN actions for
-         this state because they are default actions.  */
-      int yyxbegin = yyn < 0 ? -yyn : 0;
-      /* Stay within bounds of both yycheck and yytname.  */
-      int yychecklim = YYLAST - yyn + 1;
-      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
-      int yyx;
-      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
-        if (yycheck[yyx + yyn] == yyx && yyx != YYSYMBOL_YYerror
-            && !yytable_value_is_error (yytable[yyx + yyn]))
-          {
-            if (!yyarg)
-              ++yycount;
-            else if (yycount == yyargn)
-              return 0;
-            else
-              yyarg[yycount++] = YY_CAST (yysymbol_kind_t, yyx);
-          }
-    }
-  if (yyarg && yycount == 0 && 0 < yyargn)
-    yyarg[0] = YYSYMBOL_YYEMPTY;
-  return yycount;
-}
-
-
-
-
-#ifndef yystrlen
-# if defined __GLIBC__ && defined _STRING_H
-#  define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S)))
-# else
-/* Return the length of YYSTR.  */
-static YYPTRDIFF_T
-yystrlen (const char *yystr)
-{
-  YYPTRDIFF_T yylen;
-  for (yylen = 0; yystr[yylen]; yylen++)
-    continue;
-  return yylen;
-}
-# endif
-#endif
-
-#ifndef yystpcpy
-# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
-#  define yystpcpy stpcpy
-# else
-/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
-   YYDEST.  */
-static char *
-yystpcpy (char *yydest, const char *yysrc)
-{
-  char *yyd = yydest;
-  const char *yys = yysrc;
-
-  while ((*yyd++ = *yys++) != '\0')
-    continue;
-
-  return yyd - 1;
-}
-# endif
-#endif
-
-#ifndef yytnamerr
-/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
-   quotes and backslashes, so that it's suitable for yyerror.  The
-   heuristic is that double-quoting is unnecessary unless the string
-   contains an apostrophe, a comma, or backslash (other than
-   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
-   null, do not copy; instead, return the length of what the result
-   would have been.  */
-static YYPTRDIFF_T
-yytnamerr (char *yyres, const char *yystr)
-{
-  if (*yystr == '"')
-    {
-      YYPTRDIFF_T yyn = 0;
-      char const *yyp = yystr;
-      for (;;)
-        switch (*++yyp)
-          {
-          case '\'':
-          case ',':
-            goto do_not_strip_quotes;
-
-          case '\\':
-            if (*++yyp != '\\')
-              goto do_not_strip_quotes;
-            else
-              goto append;
-
-          append:
-          default:
-            if (yyres)
-              yyres[yyn] = *yyp;
-            yyn++;
-            break;
-
-          case '"':
-            if (yyres)
-              yyres[yyn] = '\0';
-            return yyn;
-          }
-    do_not_strip_quotes: ;
-    }
-
-  if (yyres)
-    return yystpcpy (yyres, yystr) - yyres;
-  else
-    return yystrlen (yystr);
-}
-#endif
-
-
-static int
-yy_syntax_error_arguments (const yypcontext_t *yyctx,
-                           yysymbol_kind_t yyarg[], int yyargn)
-{
-  /* Actual size of YYARG. */
-  int yycount = 0;
-  /* There are many possibilities here to consider:
-     - If this state is a consistent state with a default action, then
-       the only way this function was invoked is if the default action
-       is an error action.  In that case, don't check for expected
-       tokens because there are none.
-     - The only way there can be no lookahead present (in yychar) is if
-       this state is a consistent state with a default action.  Thus,
-       detecting the absence of a lookahead is sufficient to determine
-       that there is no unexpected or expected token to report.  In that
-       case, just report a simple "syntax error".
-     - Don't assume there isn't a lookahead just because this state is a
-       consistent state with a default action.  There might have been a
-       previous inconsistent state, consistent state with a non-default
-       action, or user semantic action that manipulated yychar.
-     - Of course, the expected token list depends on states to have
-       correct lookahead information, and it depends on the parser not
-       to perform extra reductions after fetching a lookahead from the
-       scanner and before detecting a syntax error.  Thus, state merging
-       (from LALR or IELR) and default reductions corrupt the expected
-       token list.  However, the list is correct for canonical LR with
-       one exception: it will still contain any token that will not be
-       accepted due to an error action in a later state.
-  */
-  if (yyctx->yytoken != YYSYMBOL_YYEMPTY)
-    {
-      int yyn;
-      if (yyarg)
-        yyarg[yycount] = yyctx->yytoken;
-      ++yycount;
-      yyn = yypcontext_expected_tokens (yyctx,
-                                        yyarg ? yyarg + 1 : yyarg, yyargn - 1);
-      if (yyn == YYENOMEM)
-        return YYENOMEM;
-      else
-        yycount += yyn;
-    }
-  return yycount;
-}
-
-/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
-   about the unexpected token YYTOKEN for the state stack whose top is
-   YYSSP.
-
-   Return 0 if *YYMSG was successfully written.  Return -1 if *YYMSG is
-   not large enough to hold the message.  In that case, also set
-   *YYMSG_ALLOC to the required number of bytes.  Return YYENOMEM if the
-   required number of bytes is too large to store.  */
-static int
-yysyntax_error (YYPTRDIFF_T *yymsg_alloc, char **yymsg,
-                const yypcontext_t *yyctx)
-{
-  enum { YYARGS_MAX = 5 };
-  /* Internationalized format string. */
-  const char *yyformat = YY_NULLPTR;
-  /* Arguments of yyformat: reported tokens (one for the "unexpected",
-     one per "expected"). */
-  yysymbol_kind_t yyarg[YYARGS_MAX];
-  /* Cumulated lengths of YYARG.  */
-  YYPTRDIFF_T yysize = 0;
-
-  /* Actual size of YYARG. */
-  int yycount = yy_syntax_error_arguments (yyctx, yyarg, YYARGS_MAX);
-  if (yycount == YYENOMEM)
-    return YYENOMEM;
-
-  switch (yycount)
-    {
-#define YYCASE_(N, S)                       \
-      case N:                               \
-        yyformat = S;                       \
-        break
-    default: /* Avoid compiler warnings. */
-      YYCASE_(0, YY_("syntax error"));
-      YYCASE_(1, YY_("syntax error, unexpected %s"));
-      YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
-      YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
-      YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
-      YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
-#undef YYCASE_
-    }
-
-  /* Compute error message size.  Don't count the "%s"s, but reserve
-     room for the terminator.  */
-  yysize = yystrlen (yyformat) - 2 * yycount + 1;
-  {
-    int yyi;
-    for (yyi = 0; yyi < yycount; ++yyi)
-      {
-        YYPTRDIFF_T yysize1
-          = yysize + yytnamerr (YY_NULLPTR, yytname[yyarg[yyi]]);
-        if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)
-          yysize = yysize1;
-        else
-          return YYENOMEM;
-      }
-  }
-
-  if (*yymsg_alloc < yysize)
-    {
-      *yymsg_alloc = 2 * yysize;
-      if (! (yysize <= *yymsg_alloc
-             && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
-        *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
-      return -1;
-    }
-
-  /* Avoid sprintf, as that infringes on the user's name space.
-     Don't have undefined behavior even if the translation
-     produced a string with the wrong number of "%s"s.  */
-  {
-    char *yyp = *yymsg;
-    int yyi = 0;
-    while ((*yyp = *yyformat) != '\0')
-      if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
-        {
-          yyp += yytnamerr (yyp, yytname[yyarg[yyi++]]);
-          yyformat += 2;
-        }
-      else
-        {
-          ++yyp;
-          ++yyformat;
-        }
-  }
-  return 0;
-}
-
-
-/*-----------------------------------------------.
-| Release the memory associated to this symbol.  |
-`-----------------------------------------------*/
-
-static void
-yydestruct (const char *yymsg,
-            yysymbol_kind_t yykind, YYSTYPE *yyvaluep)
-{
-  YY_USE (yyvaluep);
-  if (!yymsg)
-    yymsg = "Deleting";
-  YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp);
-
-  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-  YY_USE (yykind);
-  YY_IGNORE_MAYBE_UNINITIALIZED_END
-}
-
-
-/* Lookahead token kind.  */
-int yychar;
-
-/* The semantic value of the lookahead symbol.  */
-YYSTYPE yylval;
-/* Number of syntax errors so far.  */
-int yynerrs;
-
-
-
-
-/*----------.
-| yyparse.  |
-`----------*/
-
-int
-yyparse (void)
-{
-    yy_state_fast_t yystate = 0;
-    /* Number of tokens to shift before error messages enabled.  */
-    int yyerrstatus = 0;
-
-    /* Refer to the stacks through separate pointers, to allow yyoverflow
-       to reallocate them elsewhere.  */
-
-    /* Their size.  */
-    YYPTRDIFF_T yystacksize = YYINITDEPTH;
-
-    /* The state stack: array, bottom, top.  */
-    yy_state_t yyssa[YYINITDEPTH];
-    yy_state_t *yyss = yyssa;
-    yy_state_t *yyssp = yyss;
-
-    /* The semantic value stack: array, bottom, top.  */
-    YYSTYPE yyvsa[YYINITDEPTH];
-    YYSTYPE *yyvs = yyvsa;
-    YYSTYPE *yyvsp = yyvs;
-
-  int yyn;
-  /* The return value of yyparse.  */
-  int yyresult;
-  /* Lookahead symbol kind.  */
-  yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY;
-  /* The variables used to return semantic value and location from the
-     action routines.  */
-  YYSTYPE yyval;
-
-  /* Buffer for error messages, and its allocated size.  */
-  char yymsgbuf[128];
-  char *yymsg = yymsgbuf;
-  YYPTRDIFF_T yymsg_alloc = sizeof yymsgbuf;
-
-#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
-
-  /* The number of symbols on the RHS of the reduced rule.
-     Keep to zero when no symbol should be popped.  */
-  int yylen = 0;
-
-  YYDPRINTF ((stderr, "Starting parse\n"));
-
-  yychar = YYEMPTY; /* Cause a token to be read.  */
-
-  goto yysetstate;
-
-
-/*------------------------------------------------------------.
-| yynewstate -- push a new state, which is found in yystate.  |
-`------------------------------------------------------------*/
-yynewstate:
-  /* In all cases, when you get here, the value and location stacks
-     have just been pushed.  So pushing a state here evens the stacks.  */
-  yyssp++;
-
-
-/*--------------------------------------------------------------------.
-| yysetstate -- set current state (the top of the stack) to yystate.  |
-`--------------------------------------------------------------------*/
-yysetstate:
-  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-  YY_ASSERT (0 <= yystate && yystate < YYNSTATES);
-  YY_IGNORE_USELESS_CAST_BEGIN
-  *yyssp = YY_CAST (yy_state_t, yystate);
-  YY_IGNORE_USELESS_CAST_END
-  YY_STACK_PRINT (yyss, yyssp);
-
-  if (yyss + yystacksize - 1 <= yyssp)
-#if !defined yyoverflow && !defined YYSTACK_RELOCATE
-    YYNOMEM;
-#else
-    {
-      /* Get the current used size of the three stacks, in elements.  */
-      YYPTRDIFF_T yysize = yyssp - yyss + 1;
-
-# if defined yyoverflow
-      {
-        /* Give user a chance to reallocate the stack.  Use copies of
-           these so that the &'s don't force the real ones into
-           memory.  */
-        yy_state_t *yyss1 = yyss;
-        YYSTYPE *yyvs1 = yyvs;
-
-        /* Each stack pointer address is followed by the size of the
-           data in use in that stack, in bytes.  This used to be a
-           conditional around just the two extra args, but that might
-           be undefined if yyoverflow is a macro.  */
-        yyoverflow (YY_("memory exhausted"),
-                    &yyss1, yysize * YYSIZEOF (*yyssp),
-                    &yyvs1, yysize * YYSIZEOF (*yyvsp),
-                    &yystacksize);
-        yyss = yyss1;
-        yyvs = yyvs1;
-      }
-# else /* defined YYSTACK_RELOCATE */
-      /* Extend the stack our own way.  */
-      if (YYMAXDEPTH <= yystacksize)
-        YYNOMEM;
-      yystacksize *= 2;
-      if (YYMAXDEPTH < yystacksize)
-        yystacksize = YYMAXDEPTH;
-
-      {
-        yy_state_t *yyss1 = yyss;
-        union yyalloc *yyptr =
-          YY_CAST (union yyalloc *,
-                   YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize))));
-        if (! yyptr)
-          YYNOMEM;
-        YYSTACK_RELOCATE (yyss_alloc, yyss);
-        YYSTACK_RELOCATE (yyvs_alloc, yyvs);
-#  undef YYSTACK_RELOCATE
-        if (yyss1 != yyssa)
-          YYSTACK_FREE (yyss1);
-      }
-# endif
-
-      yyssp = yyss + yysize - 1;
-      yyvsp = yyvs + yysize - 1;
-
-      YY_IGNORE_USELESS_CAST_BEGIN
-      YYDPRINTF ((stderr, "Stack size increased to %ld\n",
-                  YY_CAST (long, yystacksize)));
-      YY_IGNORE_USELESS_CAST_END
-
-      if (yyss + yystacksize - 1 <= yyssp)
-        YYABORT;
-    }
-#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */
-
-
-  if (yystate == YYFINAL)
-    YYACCEPT;
-
-  goto yybackup;
-
-
-/*-----------.
-| yybackup.  |
-`-----------*/
-yybackup:
-  /* Do appropriate processing given the current state.  Read a
-     lookahead token if we need one and don't already have one.  */
-
-  /* First try to decide what to do without reference to lookahead token.  */
-  yyn = yypact[yystate];
-  if (yypact_value_is_default (yyn))
-    goto yydefault;
-
-  /* Not known => get a lookahead token if don't already have one.  */
-
-  /* YYCHAR is either empty, or end-of-input, or a valid lookahead.  */
-  if (yychar == YYEMPTY)
-    {
-      YYDPRINTF ((stderr, "Reading a token\n"));
-      yychar = yylex ();
-    }
-
-  if (yychar <= YYEOF)
-    {
-      yychar = YYEOF;
-      yytoken = YYSYMBOL_YYEOF;
-      YYDPRINTF ((stderr, "Now at end of input.\n"));
-    }
-  else if (yychar == YYerror)
-    {
-      /* The scanner already issued an error message, process directly
-         to error recovery.  But do not keep the error token as
-         lookahead, it is too special and may lead us to an endless
-         loop in error recovery. */
-      yychar = YYUNDEF;
-      yytoken = YYSYMBOL_YYerror;
-      goto yyerrlab1;
-    }
-  else
-    {
-      yytoken = YYTRANSLATE (yychar);
-      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
-    }
-
-  /* If the proper action on seeing token YYTOKEN is to reduce or to
-     detect an error, take that action.  */
-  yyn += yytoken;
-  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
-    goto yydefault;
-  yyn = yytable[yyn];
-  if (yyn <= 0)
-    {
-      if (yytable_value_is_error (yyn))
-        goto yyerrlab;
-      yyn = -yyn;
-      goto yyreduce;
-    }
-
-  /* Count tokens shifted since error; after three, turn off error
-     status.  */
-  if (yyerrstatus)
-    yyerrstatus--;
-
-  /* Shift the lookahead token.  */
-  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
-  yystate = yyn;
-  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-  *++yyvsp = yylval;
-  YY_IGNORE_MAYBE_UNINITIALIZED_END
-
-  /* Discard the shifted token.  */
-  yychar = YYEMPTY;
-  goto yynewstate;
-
-
-/*-----------------------------------------------------------.
-| yydefault -- do the default action for the current state.  |
-`-----------------------------------------------------------*/
-yydefault:
-  yyn = yydefact[yystate];
-  if (yyn == 0)
-    goto yyerrlab;
-  goto yyreduce;
-
-
-/*-----------------------------.
-| yyreduce -- do a reduction.  |
-`-----------------------------*/
-yyreduce:
-  /* yyn is the number of a rule to reduce with.  */
-  yylen = yyr2[yyn];
-
-  /* If YYLEN is nonzero, implement the default value of the action:
-     '$$ = $1'.
-
-     Otherwise, the following line sets YYVAL to garbage.
-     This behavior is undocumented and Bison
-     users should not rely upon it.  Assigning to YYVAL
-     unconditionally makes the parser a bit smaller, and it avoids a
-     GCC warning that YYVAL may be used uninitialized.  */
-  yyval = yyvsp[1-yylen];
-
-
-  YY_REDUCE_PRINT (yyn);
-  switch (yyn)
-    {
-  case 2: /* glyph: UNSIGNED REFERENCE  */
-#line 306 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                        {(yyval.c).c= (yyvsp[-1].u);REF(font_kind,(yyvsp[0].u));(yyval.c).f= (yyvsp[0].u);}
-#line 2236 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 3: /* content_node: start "glyph" glyph ">"  */
-#line 307 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                  {hput_tags((yyvsp[-3].u),hput_glyph(&((yyvsp[-1].c))));}
-#line 2242 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 4: /* start: "<"  */
-#line 308 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-           {HPUTNODE;(yyval.u)= (uint32_t)(hpos++-hstart);}
-#line 2248 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 6: /* integer: UNSIGNED  */
-#line 311 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                       {RNG("number",(yyvsp[0].u),0,INT32_MAX);}
-#line 2254 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 7: /* glyph: CHARCODE REFERENCE  */
-#line 314 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                        {(yyval.c).c= (yyvsp[-1].u);REF(font_kind,(yyvsp[0].u));(yyval.c).f= (yyvsp[0].u);}
-#line 2260 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 9: /* string: CHARCODE  */
-#line 317 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                      {static char s[2];
-RNG("String element",(yyvsp[0].u),0x20,0x7E);
-s[0]= (yyvsp[0].u);s[1]= 0;(yyval.s)= s;}
-#line 2268 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 10: /* number: UNSIGNED  */
-#line 322 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-               {(yyval.f)= (float64_t)(yyvsp[0].u);}
-#line 2274 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 11: /* number: SIGNED  */
-#line 322 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                          {(yyval.f)= (float64_t)(yyvsp[0].i);}
-#line 2280 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 13: /* dimension: number "pt"  */
-#line 325 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                   {(yyval.d)= ROUND((yyvsp[-1].f)*ONE);RNG("Dimension",(yyval.d),-MAX_DIMEN,MAX_DIMEN);}
-#line 2286 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 14: /* dimension: number "in"  */
-#line 326 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-            {(yyval.d)= ROUND((yyvsp[-1].f)*ONE*72.27);RNG("Dimension",(yyval.d),-MAX_DIMEN,MAX_DIMEN);}
-#line 2292 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 15: /* dimension: number "mm"  */
-#line 327 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-          {(yyval.d)= ROUND((yyvsp[-1].f)*ONE*(72.27/25.4));RNG("Dimension",(yyval.d),-MAX_DIMEN,MAX_DIMEN);}
-#line 2298 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 16: /* xdimen: dimension number "h" number "v"  */
-#line 330 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                  {(yyval.xd).w= (yyvsp[-4].d);(yyval.xd).h= (yyvsp[-3].f);(yyval.xd).v= (yyvsp[-1].f);}
-#line 2304 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 17: /* xdimen: dimension number "h"  */
-#line 331 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                   {(yyval.xd).w= (yyvsp[-2].d);(yyval.xd).h= (yyvsp[-1].f);(yyval.xd).v= 0.0;}
-#line 2310 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 18: /* xdimen: dimension number "v"  */
-#line 332 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                   {(yyval.xd).w= (yyvsp[-2].d);(yyval.xd).h= 0.0;(yyval.xd).v= (yyvsp[-1].f);}
-#line 2316 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 19: /* xdimen: dimension  */
-#line 333 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-          {(yyval.xd).w= (yyvsp[0].d);(yyval.xd).h= 0.0;(yyval.xd).v= 0.0;}
-#line 2322 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 20: /* xdimen_node: start "xdimen" xdimen ">"  */
-#line 337 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                   {hput_tags((yyvsp[-3].u),hput_xdimen(&((yyvsp[-1].xd))));}
-#line 2328 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 21: /* order: "pt"  */
-#line 341 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-        {(yyval.o)= normal_o;}
-#line 2334 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 22: /* order: "fil"  */
-#line 341 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                           {(yyval.o)= fil_o;}
-#line 2340 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 23: /* order: "fill"  */
-#line 341 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                            {(yyval.o)= fill_o;}
-#line 2346 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 24: /* order: "filll"  */
-#line 341 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                                               {(yyval.o)= filll_o;}
-#line 2352 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 25: /* stretch: number order  */
-#line 343 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                    {(yyval.st).f= (yyvsp[-1].f);(yyval.st).o= (yyvsp[0].o);}
-#line 2358 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 26: /* penalty: integer  */
-#line 346 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-               {RNG("Penalty",(yyvsp[0].i),-20000,+20000);(yyval.i)= (yyvsp[0].i);}
-#line 2364 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 27: /* content_node: start "penalty" penalty ">"  */
-#line 347 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                      {hput_tags((yyvsp[-3].u),hput_int((yyvsp[-1].i)));}
-#line 2370 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 29: /* rule_dimension: "|"  */
-#line 350 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                {(yyval.d)= RUNNING_DIMEN;}
-#line 2376 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 30: /* rule: rule_dimension rule_dimension rule_dimension  */
-#line 352 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-{(yyval.r).h= (yyvsp[-2].d);(yyval.r).d= (yyvsp[-1].d);(yyval.r).w= (yyvsp[0].d);
-if((yyvsp[0].d)==RUNNING_DIMEN&&((yyvsp[-2].d)==RUNNING_DIMEN||(yyvsp[-1].d)==RUNNING_DIMEN))
-QUIT("Incompatible running dimensions 0x%x 0x%x 0x%x",(yyvsp[-2].d),(yyvsp[-1].d),(yyvsp[0].d));}
-#line 2384 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 31: /* rule_node: start "rule" rule ">"  */
-#line 355 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                             {hput_tags((yyvsp[-3].u),hput_rule(&((yyvsp[-1].r))));}
-#line 2390 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 33: /* explicit: %empty  */
-#line 359 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-         {(yyval.b)= false;}
-#line 2396 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 34: /* explicit: "!"  */
-#line 359 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                              {(yyval.b)= true;}
-#line 2402 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 35: /* kern: explicit xdimen  */
-#line 360 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                    {(yyval.kt).x= (yyvsp[-1].b);(yyval.kt).d= (yyvsp[0].xd);}
-#line 2408 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 36: /* content_node: start "kern" kern ">"  */
-#line 361 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                {hput_tags((yyvsp[-3].u),hput_kern(&((yyvsp[-1].kt))));}
-#line 2414 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 37: /* plus: %empty  */
-#line 364 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-     {(yyval.st).f= 0.0;(yyval.st).o= 0;}
-#line 2420 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 38: /* plus: "plus" stretch  */
-#line 364 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                      {(yyval.st)= (yyvsp[0].st);}
-#line 2426 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 39: /* minus: %empty  */
-#line 365 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-      {(yyval.st).f= 0.0;(yyval.st).o= 0;}
-#line 2432 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 40: /* minus: "minus" stretch  */
-#line 365 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                        {(yyval.st)= (yyvsp[0].st);}
-#line 2438 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 41: /* glue: xdimen plus minus  */
-#line 366 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                      {(yyval.g).w= (yyvsp[-2].xd);(yyval.g).p= (yyvsp[-1].st);(yyval.g).m= (yyvsp[0].st);}
-#line 2444 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 42: /* content_node: start "glue" glue ">"  */
-#line 367 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                {if(ZERO_GLUE((yyvsp[-1].g))){HPUT8(zero_skip_no);
-hput_tags((yyvsp[-3].u),TAG(glue_kind,0));}else hput_tags((yyvsp[-3].u),hput_glue(&((yyvsp[-1].g))));}
-#line 2451 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 43: /* glue_node: start "glue" glue ">"  */
-#line 370 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-{if(ZERO_GLUE((yyvsp[-1].g))){hpos--;(yyval.b)= false;}
-else{hput_tags((yyvsp[-3].u),hput_glue(&((yyvsp[-1].g))));(yyval.b)= true;}}
-#line 2458 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 44: /* position: %empty  */
-#line 374 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-         {(yyval.u)= hpos-hstart;}
-#line 2464 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 47: /* estimate: %empty  */
-#line 377 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-         {hpos+= 2;}
-#line 2470 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 48: /* estimate: UNSIGNED  */
-#line 378 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-         {hpos+= hsize_bytes((yyvsp[0].u))+1;}
-#line 2476 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 49: /* list: start estimate content_list ">"  */
-#line 380 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-{(yyval.l).k= list_kind;(yyval.l).p= (yyvsp[-1].u);(yyval.l).s= (hpos-hstart)-(yyvsp[-1].u);
-hput_tags((yyvsp[-3].u),hput_list((yyvsp[-3].u)+1,&((yyval.l))));}
-#line 2483 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 50: /* $@1: %empty  */
-#line 385 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-{hpos+= 4;}
-#line 2489 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 51: /* list: TXT_START position $@1 text TXT_END  */
-#line 387 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-{(yyval.l).k= text_kind;(yyval.l).p= (yyvsp[-1].u);(yyval.l).s= (hpos-hstart)-(yyvsp[-1].u);
-hput_tags((yyvsp[-3].u),hput_list((yyvsp[-3].u)+1,&((yyval.l))));}
-#line 2496 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 54: /* txt: TXT_CC  */
-#line 391 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-          {hput_txt_cc((yyvsp[0].u));}
-#line 2502 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 55: /* txt: TXT_FONT  */
-#line 392 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-         {REF(font_kind,(yyvsp[0].u));hput_txt_font((yyvsp[0].u));}
-#line 2508 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 56: /* txt: TXT_GLOBAL  */
-#line 393 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-           {REF((yyvsp[0].rf).k,(yyvsp[0].rf).n);hput_txt_global(&((yyvsp[0].rf)));}
-#line 2514 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 57: /* txt: TXT_LOCAL  */
-#line 394 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-          {RNG("Font parameter",(yyvsp[0].u),0,11);hput_txt_local((yyvsp[0].u));}
-#line 2520 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 58: /* txt: TXT_FONT_GLUE  */
-#line 395 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-              {HPUTX(1);HPUT8(txt_glue);}
-#line 2526 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 59: /* txt: TXT_FONT_HYPHEN  */
-#line 396 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                {HPUTX(1);HPUT8(txt_hyphen);}
-#line 2532 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 60: /* txt: TXT_IGNORE  */
-#line 397 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-           {HPUTX(1);HPUT8(txt_ignore);}
-#line 2538 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 61: /* $@2: %empty  */
-#line 398 "../../../texk/web2c/hitexdir/hishrink-parser.y"
- {HPUTX(1);HPUT8(txt_node);}
-#line 2544 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 63: /* box_dimen: dimension dimension dimension  */
-#line 403 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-{(yyval.info)= hput_box_dimen((yyvsp[-2].d),(yyvsp[-1].d),(yyvsp[0].d));}
-#line 2550 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 64: /* box_shift: %empty  */
-#line 404 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-          {(yyval.info)= b000;}
-#line 2556 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 65: /* box_shift: "shifted" dimension  */
-#line 405 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                  {(yyval.info)= hput_box_shift((yyvsp[0].d));}
-#line 2562 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 66: /* box_glue_set: %empty  */
-#line 407 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-             {(yyval.info)= b000;}
-#line 2568 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 67: /* box_glue_set: "plus" stretch  */
-#line 408 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-             {(yyval.info)= hput_box_glue_set(+1,(yyvsp[0].st).f,(yyvsp[0].st).o);}
-#line 2574 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 68: /* box_glue_set: "minus" stretch  */
-#line 409 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-              {(yyval.info)= hput_box_glue_set(-1,(yyvsp[0].st).f,(yyvsp[0].st).o);}
-#line 2580 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 69: /* box: box_dimen box_shift box_glue_set list  */
-#line 412 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                         {(yyval.info)= (yyvsp[-3].info)|(yyvsp[-2].info)|(yyvsp[-1].info);}
-#line 2586 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 70: /* hbox_node: start "hbox" box ">"  */
-#line 414 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                            {hput_tags((yyvsp[-3].u),TAG(hbox_kind,(yyvsp[-1].info)));}
-#line 2592 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 71: /* vbox_node: start "vbox" box ">"  */
-#line 415 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                            {hput_tags((yyvsp[-3].u),TAG(vbox_kind,(yyvsp[-1].info)));}
-#line 2598 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 74: /* box_flex: plus minus  */
-#line 419 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                   {hput_stretch(&((yyvsp[-1].st)));hput_stretch(&((yyvsp[0].st)));}
-#line 2604 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 75: /* xbox: box_dimen box_shift box_flex xdimen_ref list  */
-#line 420 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                                 {(yyval.info)= (yyvsp[-4].info)|(yyvsp[-3].info);}
-#line 2610 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 76: /* xbox: box_dimen box_shift box_flex xdimen_node list  */
-#line 421 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                              {(yyval.info)= (yyvsp[-4].info)|(yyvsp[-3].info)|b100;}
-#line 2616 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 77: /* box_goal: "to" xdimen_ref  */
-#line 423 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                      {(yyval.info)= b000;}
-#line 2622 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 78: /* box_goal: "add" xdimen_ref  */
-#line 424 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-               {(yyval.info)= b001;}
-#line 2628 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 79: /* box_goal: "to" xdimen_node  */
-#line 425 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-               {(yyval.info)= b100;}
-#line 2634 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 80: /* box_goal: "add" xdimen_node  */
-#line 426 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                {(yyval.info)= b101;}
-#line 2640 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 81: /* hpack: box_shift box_goal list  */
-#line 428 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                             {(yyval.info)= (yyvsp[-1].info);}
-#line 2646 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 82: /* $@3: %empty  */
-#line 429 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                   {HPUT32((yyvsp[0].d));}
-#line 2652 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 83: /* vpack: box_shift "max" "depth" dimension $@3 box_goal list  */
-#line 429 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                                             {(yyval.info)= (yyvsp[-6].info)|(yyvsp[-1].info);}
-#line 2658 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 84: /* vxbox_node: start "vset" xbox ">"  */
-#line 431 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                              {hput_tags((yyvsp[-3].u),TAG(vset_kind,(yyvsp[-1].info)));}
-#line 2664 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 85: /* vxbox_node: start "vpack" vpack ">"  */
-#line 432 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                      {hput_tags((yyvsp[-3].u),TAG(vpack_kind,(yyvsp[-1].info)));}
-#line 2670 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 86: /* hxbox_node: start "hset" xbox ">"  */
-#line 435 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                              {hput_tags((yyvsp[-3].u),TAG(hset_kind,(yyvsp[-1].info)));}
-#line 2676 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 87: /* hxbox_node: start "hpack" hpack ">"  */
-#line 436 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                      {hput_tags((yyvsp[-3].u),TAG(hpack_kind,(yyvsp[-1].info)));}
-#line 2682 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 90: /* ltype: %empty  */
-#line 441 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-      {(yyval.info)= 1;}
-#line 2688 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 91: /* ltype: "align"  */
-#line 441 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                    {(yyval.info)= 1;}
-#line 2694 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 92: /* ltype: "center"  */
-#line 441 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                   {(yyval.info)= 2;}
-#line 2700 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 93: /* ltype: "expand"  */
-#line 441 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                                  {(yyval.info)= 3;}
-#line 2706 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 94: /* leaders: glue_node ltype rule_node  */
-#line 442 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                 {if((yyvsp[-2].b))(yyval.info)= (yyvsp[-1].info)|b100;else (yyval.info)= (yyvsp[-1].info);}
-#line 2712 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 95: /* leaders: glue_node ltype hbox_node  */
-#line 443 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                          {if((yyvsp[-2].b))(yyval.info)= (yyvsp[-1].info)|b100;else (yyval.info)= (yyvsp[-1].info);}
-#line 2718 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 96: /* leaders: glue_node ltype vbox_node  */
-#line 444 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                          {if((yyvsp[-2].b))(yyval.info)= (yyvsp[-1].info)|b100;else (yyval.info)= (yyvsp[-1].info);}
-#line 2724 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 97: /* content_node: start "leaders" leaders ">"  */
-#line 445 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                      {hput_tags((yyvsp[-3].u),TAG(leaders_kind,(yyvsp[-1].info)));}
-#line 2730 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 98: /* $@4: %empty  */
-#line 448 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                  {if((yyvsp[0].d)!=0)HPUT32((yyvsp[0].d));}
-#line 2736 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 99: /* baseline: dimension $@4 glue_node glue_node  */
-#line 449 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                   {(yyval.info)= b000;if((yyvsp[-3].d)!=0)(yyval.info)|= b001;
-if((yyvsp[-1].b))(yyval.info)|= b100;
-if((yyvsp[0].b))(yyval.info)|= b010;
-}
-#line 2745 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 100: /* content_node: start "baseline" baseline ">"  */
-#line 454 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-{if((yyvsp[-1].info)==b000)HPUT8(0);hput_tags((yyvsp[-3].u),TAG(baseline_kind,(yyvsp[-1].info)));}
-#line 2751 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 102: /* cc_list: cc_list TXT_CC  */
-#line 457 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                       {hput_utf8((yyvsp[0].u));}
-#line 2757 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 103: /* lig_cc: UNSIGNED  */
-#line 458 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-               {RNG("UTF-8 code",(yyvsp[0].u),0,0x1FFFFF);(yyval.u)= hpos-hstart;hput_utf8((yyvsp[0].u));}
-#line 2763 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 104: /* lig_cc: CHARCODE  */
-#line 459 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-               {(yyval.u)= hpos-hstart;hput_utf8((yyvsp[0].u));}
-#line 2769 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 105: /* ref: REFERENCE  */
-#line 460 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-             {HPUT8((yyvsp[0].u));(yyval.u)= (yyvsp[0].u);}
-#line 2775 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 106: /* $@5: %empty  */
-#line 461 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-            {REF(font_kind,(yyvsp[0].u));}
-#line 2781 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 107: /* ligature: ref $@5 lig_cc TXT_START cc_list TXT_END  */
-#line 462 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-{(yyval.lg).f= (yyvsp[-5].u);(yyval.lg).l.p= (yyvsp[-3].u);(yyval.lg).l.s= (hpos-hstart)-(yyvsp[-3].u);
-RNG("Ligature size",(yyval.lg).l.s,0,255);}
-#line 2788 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 108: /* content_node: start "ligature" ligature ">"  */
-#line 464 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                        {hput_tags((yyvsp[-3].u),hput_ligature(&((yyvsp[-1].lg))));}
-#line 2794 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 109: /* replace_count: explicit  */
-#line 467 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                      {if((yyvsp[0].b)){(yyval.u)= 0x80;HPUT8(0x80);}else (yyval.u)= 0x00;}
-#line 2800 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 110: /* replace_count: explicit UNSIGNED  */
-#line 468 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                  {RNG("Replace count",(yyvsp[0].u),0,31);
-(yyval.u)= ((yyvsp[0].u))|(((yyvsp[-1].b))?0x80:0x00);if((yyval.u)!=0)HPUT8((yyval.u));}
-#line 2807 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 111: /* disc: replace_count list list  */
-#line 470 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                            {(yyval.dc).r= (yyvsp[-2].u);(yyval.dc).p= (yyvsp[-1].l);(yyval.dc).q= (yyvsp[0].l);
-if((yyvsp[0].l).s==0){hpos= hpos-2;if((yyvsp[-1].l).s==0)hpos= hpos-2;}}
-#line 2814 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 112: /* disc: replace_count list  */
-#line 472 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                   {(yyval.dc).r= (yyvsp[-1].u);(yyval.dc).p= (yyvsp[0].l);if((yyvsp[0].l).s==0)hpos= hpos-2;(yyval.dc).q.s= 0;}
-#line 2820 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 113: /* disc: replace_count  */
-#line 473 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-              {(yyval.dc).r= (yyvsp[0].u);(yyval.dc).p.s= 0;(yyval.dc).q.s= 0;}
-#line 2826 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 114: /* disc_node: start "disc" disc ">"  */
-#line 477 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-{hput_tags((yyvsp[-3].u),hput_disc(&((yyvsp[-1].dc))));}
-#line 2832 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 116: /* par_dimen: xdimen  */
-#line 482 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                {hput_xdimen_node(&((yyvsp[0].xd)));}
-#line 2838 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 117: /* par: xdimen_ref param_ref list  */
-#line 483 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                             {(yyval.info)= b000;}
-#line 2844 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 118: /* par: xdimen_ref empty_param_list non_empty_param_list list  */
-#line 484 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                                      {(yyval.info)= b010;}
-#line 2850 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 119: /* par: xdimen_ref empty_param_list list  */
-#line 485 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                 {(yyval.info)= b010;}
-#line 2856 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 120: /* $@6: %empty  */
-#line 486 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                 {hput_xdimen_node(&((yyvsp[-1].xd)));}
-#line 2862 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 121: /* par: xdimen param_ref $@6 list  */
-#line 486 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                               {(yyval.info)= b100;}
-#line 2868 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 122: /* par: par_dimen empty_param_list non_empty_param_list list  */
-#line 487 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                                     {(yyval.info)= b110;}
-#line 2874 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 123: /* par: par_dimen empty_param_list list  */
-#line 488 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                {(yyval.info)= b110;}
-#line 2880 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 124: /* content_node: start "par" par ">"  */
-#line 490 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                              {hput_tags((yyvsp[-3].u),TAG(par_kind,(yyvsp[-1].info)));}
-#line 2886 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 125: /* math: param_ref list  */
-#line 493 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                   {(yyval.info)= b000;}
-#line 2892 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 126: /* math: param_ref list hbox_node  */
-#line 494 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                         {(yyval.info)= b001;}
-#line 2898 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 127: /* math: param_ref hbox_node list  */
-#line 495 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                         {(yyval.info)= b010;}
-#line 2904 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 128: /* math: empty_param_list list  */
-#line 496 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                      {(yyval.info)= b100;}
-#line 2910 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 129: /* math: empty_param_list list hbox_node  */
-#line 497 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                {(yyval.info)= b101;}
-#line 2916 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 130: /* math: empty_param_list hbox_node list  */
-#line 498 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                {(yyval.info)= b110;}
-#line 2922 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 131: /* math: empty_param_list non_empty_param_list list  */
-#line 499 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                           {(yyval.info)= b100;}
-#line 2928 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 132: /* math: empty_param_list non_empty_param_list list hbox_node  */
-#line 500 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                                     {(yyval.info)= b101;}
-#line 2934 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 133: /* math: empty_param_list non_empty_param_list hbox_node list  */
-#line 501 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                                     {(yyval.info)= b110;}
-#line 2940 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 134: /* content_node: start "math" math ">"  */
-#line 503 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                {hput_tags((yyvsp[-3].u),TAG(math_kind,(yyvsp[-1].info)));}
-#line 2946 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 135: /* on_off: "on"  */
-#line 506 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-         {(yyval.i)= 1;}
-#line 2952 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 136: /* on_off: "off"  */
-#line 506 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                     {(yyval.i)= 0;}
-#line 2958 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 137: /* math: on_off  */
-#line 507 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-           {(yyval.info)= b011|((yyvsp[0].i)<<2);}
-#line 2964 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 138: /* content_node: start "adjust" list ">"  */
-#line 510 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                  {hput_tags((yyvsp[-3].u),TAG(adjust_kind,1));}
-#line 2970 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 139: /* span_count: UNSIGNED  */
-#line 513 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                   {(yyval.info)= hput_span_count((yyvsp[0].u));}
-#line 2976 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 140: /* content_node: start "item" content_node ">"  */
-#line 514 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                        {hput_tags((yyvsp[-3].u),TAG(item_kind,1));}
-#line 2982 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 141: /* content_node: start "item" span_count content_node ">"  */
-#line 515 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                                   {hput_tags((yyvsp[-4].u),TAG(item_kind,(yyvsp[-2].info)));}
-#line 2988 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 142: /* content_node: start "item" list ">"  */
-#line 516 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                {hput_tags((yyvsp[-3].u),TAG(item_kind,b000));}
-#line 2994 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 143: /* table: "h" box_goal list list  */
-#line 518 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                          {(yyval.info)= (yyvsp[-2].info);}
-#line 3000 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 144: /* table: "v" box_goal list list  */
-#line 519 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                          {(yyval.info)= (yyvsp[-2].info)|b010;}
-#line 3006 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 145: /* content_node: start "table" table ">"  */
-#line 521 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                  {hput_tags((yyvsp[-3].u),TAG(table_kind,(yyvsp[-1].info)));}
-#line 3012 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 146: /* image_dimen: dimension dimension  */
-#line 524 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                               {(yyval.x).w= (yyvsp[-1].d);(yyval.x).h= (yyvsp[0].d);}
-#line 3018 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 147: /* image_dimen: %empty  */
-#line 524 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                                    {(yyval.x).w= (yyval.x).h= 0;}
-#line 3024 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 148: /* image: UNSIGNED image_dimen plus minus  */
-#line 525 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                     {(yyval.x).w= (yyvsp[-2].x).w;(yyval.x).h= (yyvsp[-2].x).h;(yyval.x).p= (yyvsp[-1].st);(yyval.x).m= (yyvsp[0].st);RNG("Section number",(yyvsp[-3].u),3,max_section_no);(yyval.x).n= (yyvsp[-3].u);}
-#line 3030 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 149: /* content_node: start "image" image ">"  */
-#line 526 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                  {hput_tags((yyvsp[-3].u),hput_image(&((yyvsp[-1].x))));}
-#line 3036 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 150: /* max_value: "outline" UNSIGNED  */
-#line 529 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                          {max_outline= (yyvsp[0].u);
-RNG("max outline",max_outline,0,0xFFFF);
-DBG(DBGDEF|DBGLABEL,"Setting max outline to %d\n",max_outline);
-}
-#line 3045 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 151: /* placement: "top"  */
-#line 535 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-             {(yyval.i)= LABEL_TOP;}
-#line 3051 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 152: /* placement: "bot"  */
-#line 535 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                 {(yyval.i)= LABEL_BOT;}
-#line 3057 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 153: /* placement: "mid"  */
-#line 535 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                                     {(yyval.i)= LABEL_MID;}
-#line 3063 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 154: /* placement: %empty  */
-#line 535 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                                                      {(yyval.i)= LABEL_MID;}
-#line 3069 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 155: /* content_node: "<" "label" REFERENCE placement ">"  */
-#line 537 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-{hset_label((yyvsp[-2].u),(yyvsp[-1].i));}
-#line 3075 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 156: /* content_node: start "link" REFERENCE on_off ">"  */
-#line 541 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-{hput_tags((yyvsp[-4].u),hput_link((yyvsp[-2].u),(yyvsp[-1].i)));}
-#line 3081 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 157: /* def_node: "<" "outline" REFERENCE integer position list ">"  */
-#line 544 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                                          {
-static int outline_no= -1;
-(yyval.rf).k= outline_kind;(yyval.rf).n= (yyvsp[-4].u);
-if((yyvsp[-1].l).s==0)QUIT("Outline with empty title in line %d",yylineno);
-outline_no++;
-hset_outline(outline_no,(yyvsp[-4].u),(yyvsp[-3].i),(yyvsp[-2].u));
-}
-#line 3093 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 158: /* stream_link: ref  */
-#line 553 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-               {REF_RNG(stream_kind,(yyvsp[0].u));}
-#line 3099 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 159: /* stream_link: "*"  */
-#line 553 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                                     {HPUT8(255);}
-#line 3105 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 160: /* stream_split: stream_link stream_link UNSIGNED  */
-#line 554 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                             {RNG("split ratio",(yyvsp[0].u),0,1000);HPUT16((yyvsp[0].u));}
-#line 3111 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 161: /* $@7: %empty  */
-#line 555 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                {RNG("magnification factor",(yyvsp[0].u),0,1000);HPUT16((yyvsp[0].u));}
-#line 3117 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 163: /* stream_type: stream_info  */
-#line 557 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                       {(yyval.info)= 0;}
-#line 3123 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 164: /* stream_type: "first"  */
-#line 557 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                     {(yyval.info)= 1;}
-#line 3129 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 165: /* stream_type: "last"  */
-#line 557 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                                  {(yyval.info)= 2;}
-#line 3135 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 166: /* stream_type: "top"  */
-#line 557 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                                              {(yyval.info)= 3;}
-#line 3141 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 167: /* stream_def_node: start "stream (definition)" ref stream_type list xdimen_node glue_node list glue_node ">"  */
-#line 561 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-{DEF((yyval.rf),stream_kind,(yyvsp[-7].u));hput_tags((yyvsp[-9].u),TAG(stream_kind,(yyvsp[-6].info)|b100));}
-#line 3147 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 168: /* stream_ins_node: start "stream (definition)" ref ">"  */
-#line 564 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-{RNG("Stream insertion",(yyvsp[-1].u),0,max_ref[stream_kind]);hput_tags((yyvsp[-3].u),TAG(stream_kind,b100));}
-#line 3153 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 171: /* stream: empty_param_list list  */
-#line 569 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                            {(yyval.info)= b010;}
-#line 3159 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 172: /* stream: empty_param_list non_empty_param_list list  */
-#line 570 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                           {(yyval.info)= b010;}
-#line 3165 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 173: /* stream: param_ref list  */
-#line 571 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-               {(yyval.info)= b000;}
-#line 3171 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 174: /* content_node: start "stream" stream_ref stream ">"  */
-#line 573 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-{hput_tags((yyvsp[-4].u),TAG(stream_kind,(yyvsp[-1].info)));}
-#line 3177 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 175: /* page_priority: %empty  */
-#line 576 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-              {HPUT8(1);}
-#line 3183 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 176: /* page_priority: UNSIGNED  */
-#line 577 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-         {RNG("page priority",(yyvsp[0].u),0,255);HPUT8((yyvsp[0].u));}
-#line 3189 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 179: /* $@8: %empty  */
-#line 581 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-           {hput_string((yyvsp[0].s));}
-#line 3195 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 180: /* $@9: %empty  */
-#line 581 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                                              {HPUT32((yyvsp[0].d));}
-#line 3201 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 182: /* content_node: "<" "range" REFERENCE "on" ">"  */
-#line 587 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                         {REF(page_kind,(yyvsp[-2].u));hput_range((yyvsp[-2].u),true);}
-#line 3207 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 183: /* content_node: "<" "range" REFERENCE "off" ">"  */
-#line 588 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                              {REF(page_kind,(yyvsp[-2].u));hput_range((yyvsp[-2].u),false);}
-#line 3213 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 185: /* $@10: %empty  */
-#line 594 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                          {new_directory((yyvsp[0].u)+1);new_output_buffers();}
-#line 3219 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 189: /* entry: "<" "entry" UNSIGNED string ">"  */
-#line 597 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-{RNG("Section number",(yyvsp[-2].u),3,max_section_no);hset_entry(&(dir[(yyvsp[-2].u)]),(yyvsp[-2].u),0,0,(yyvsp[-1].s));}
-#line 3225 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 190: /* $@11: %empty  */
-#line 600 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                    {hput_definitions_start();}
-#line 3231 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 191: /* definition_section: "<" "definitions" $@11 max_definitions definition_list ">"  */
-#line 602 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-   {hput_definitions_end();}
-#line 3237 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 194: /* max_definitions: "<" "max" max_list ">"  */
-#line 607 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-{/*245:*/
-
-if(max_ref[label_kind]>=0)
-ALLOCATE(labels,max_ref[label_kind]+1,label_t);
-/*:245*//*266:*/
-
-if(max_outline>=0)
-ALLOCATE(outlines,max_outline+1,outline_t);
-/*:266*//*293:*/
-
-ALLOCATE(page_on,max_ref[page_kind]+1,int);
-ALLOCATE(range_pos,2*(max_ref[range_kind]+1),range_pos_t);
-/*:293*//*357:*/
-
-definition_bits[0][int_kind]= (1<<(MAX_INT_DEFAULT+1))-1;
-definition_bits[0][dimen_kind]= (1<<(MAX_DIMEN_DEFAULT+1))-1;
-definition_bits[0][xdimen_kind]= (1<<(MAX_XDIMEN_DEFAULT+1))-1;
-definition_bits[0][glue_kind]= (1<<(MAX_GLUE_DEFAULT+1))-1;
-definition_bits[0][baseline_kind]= (1<<(MAX_BASELINE_DEFAULT+1))-1;
-definition_bits[0][page_kind]= (1<<(MAX_PAGE_DEFAULT+1))-1;
-definition_bits[0][stream_kind]= (1<<(MAX_STREAM_DEFAULT+1))-1;
-definition_bits[0][range_kind]= (1<<(MAX_RANGE_DEFAULT+1))-1;
-/*:357*//*372:*/
-
-ALLOCATE(hfont_name,max_ref[font_kind]+1,char*);
-/*:372*/
-hput_max_definitions();}
-#line 3269 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 197: /* max_value: "font" UNSIGNED  */
-#line 637 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                       {hset_max(font_kind,(yyvsp[0].u));}
-#line 3275 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 198: /* max_value: "int" UNSIGNED  */
-#line 638 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                 {hset_max(int_kind,(yyvsp[0].u));}
-#line 3281 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 199: /* max_value: "dimen" UNSIGNED  */
-#line 639 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-               {hset_max(dimen_kind,(yyvsp[0].u));}
-#line 3287 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 200: /* max_value: "ligature" UNSIGNED  */
-#line 640 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                  {hset_max(ligature_kind,(yyvsp[0].u));}
-#line 3293 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 201: /* max_value: "disc" UNSIGNED  */
-#line 641 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-              {hset_max(disc_kind,(yyvsp[0].u));}
-#line 3299 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 202: /* max_value: "glue" UNSIGNED  */
-#line 642 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-              {hset_max(glue_kind,(yyvsp[0].u));}
-#line 3305 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 203: /* max_value: "language" UNSIGNED  */
-#line 643 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                  {hset_max(language_kind,(yyvsp[0].u));}
-#line 3311 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 204: /* max_value: "rule" UNSIGNED  */
-#line 644 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-              {hset_max(rule_kind,(yyvsp[0].u));}
-#line 3317 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 205: /* max_value: "image" UNSIGNED  */
-#line 645 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-               {hset_max(image_kind,(yyvsp[0].u));}
-#line 3323 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 206: /* max_value: "leaders" UNSIGNED  */
-#line 646 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                 {hset_max(leaders_kind,(yyvsp[0].u));}
-#line 3329 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 207: /* max_value: "baseline" UNSIGNED  */
-#line 647 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                  {hset_max(baseline_kind,(yyvsp[0].u));}
-#line 3335 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 208: /* max_value: "xdimen" UNSIGNED  */
-#line 648 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                {hset_max(xdimen_kind,(yyvsp[0].u));}
-#line 3341 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 209: /* max_value: "param" UNSIGNED  */
-#line 649 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-               {hset_max(param_kind,(yyvsp[0].u));}
-#line 3347 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 210: /* max_value: "stream (definition)" UNSIGNED  */
-#line 650 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                   {hset_max(stream_kind,(yyvsp[0].u));}
-#line 3353 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 211: /* max_value: "page" UNSIGNED  */
-#line 651 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-              {hset_max(page_kind,(yyvsp[0].u));}
-#line 3359 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 212: /* max_value: "range" UNSIGNED  */
-#line 652 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-               {hset_max(range_kind,(yyvsp[0].u));}
-#line 3365 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 213: /* max_value: "label" UNSIGNED  */
-#line 653 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-               {hset_max(label_kind,(yyvsp[0].u));}
-#line 3371 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 214: /* def_node: start "font" ref font ">"  */
-#line 658 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                       {DEF((yyval.rf),font_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),(yyvsp[-1].info));}
-#line 3377 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 215: /* def_node: start "int" ref integer ">"  */
-#line 659 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                              {DEF((yyval.rf),int_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),hput_int((yyvsp[-1].i)));}
-#line 3383 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 216: /* def_node: start "dimen" ref dimension ">"  */
-#line 660 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                              {DEF((yyval.rf),dimen_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),hput_dimen((yyvsp[-1].d)));}
-#line 3389 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 217: /* def_node: start "language" ref string ">"  */
-#line 661 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                              {DEF((yyval.rf),language_kind,(yyvsp[-2].u));hput_string((yyvsp[-1].s));hput_tags((yyvsp[-4].u),TAG(language_kind,0));}
-#line 3395 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 218: /* def_node: start "glue" ref glue ">"  */
-#line 662 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                        {DEF((yyval.rf),glue_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),hput_glue(&((yyvsp[-1].g))));}
-#line 3401 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 219: /* def_node: start "xdimen" ref xdimen ">"  */
-#line 663 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                            {DEF((yyval.rf),xdimen_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),hput_xdimen(&((yyvsp[-1].xd))));}
-#line 3407 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 220: /* def_node: start "rule" ref rule ">"  */
-#line 664 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                        {DEF((yyval.rf),rule_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),hput_rule(&((yyvsp[-1].r))));}
-#line 3413 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 221: /* def_node: start "leaders" ref leaders ">"  */
-#line 665 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                              {DEF((yyval.rf),leaders_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),TAG(leaders_kind,(yyvsp[-1].info)));}
-#line 3419 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 222: /* def_node: start "baseline" ref baseline ">"  */
-#line 666 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                {DEF((yyval.rf),baseline_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),TAG(baseline_kind,(yyvsp[-1].info)));}
-#line 3425 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 223: /* def_node: start "ligature" ref ligature ">"  */
-#line 667 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                {DEF((yyval.rf),ligature_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),hput_ligature(&((yyvsp[-1].lg))));}
-#line 3431 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 224: /* def_node: start "disc" ref disc ">"  */
-#line 668 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                        {DEF((yyval.rf),disc_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),hput_disc(&((yyvsp[-1].dc))));}
-#line 3437 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 225: /* def_node: start "image" ref image ">"  */
-#line 669 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                          {DEF((yyval.rf),image_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),hput_image(&((yyvsp[-1].x))));}
-#line 3443 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 226: /* def_node: start "param" ref parameters ">"  */
-#line 670 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                               {DEF((yyval.rf),param_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),hput_list((yyvsp[-4].u)+2,&((yyvsp[-1].l))));}
-#line 3449 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 227: /* def_node: start "page" ref page ">"  */
-#line 671 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                        {DEF((yyval.rf),page_kind,(yyvsp[-2].u));hput_tags((yyvsp[-4].u),TAG(page_kind,0));}
-#line 3455 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 228: /* def_node: start "int" ref ref ">"  */
-#line 675 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                         {DEF_REF((yyval.rf),int_kind,(yyvsp[-2].u),(yyvsp[-1].u));hput_tags((yyvsp[-4].u),TAG(int_kind,0));}
-#line 3461 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 229: /* def_node: start "dimen" ref ref ">"  */
-#line 676 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                        {DEF_REF((yyval.rf),dimen_kind,(yyvsp[-2].u),(yyvsp[-1].u));hput_tags((yyvsp[-4].u),TAG(dimen_kind,0));}
-#line 3467 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 230: /* def_node: start "glue" ref ref ">"  */
-#line 677 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                       {DEF_REF((yyval.rf),glue_kind,(yyvsp[-2].u),(yyvsp[-1].u));hput_tags((yyvsp[-4].u),TAG(glue_kind,0));}
-#line 3473 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 232: /* def_list: def_list def_node  */
-#line 681 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                  {check_param_def(&((yyvsp[0].rf)));}
-#line 3479 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 233: /* parameters: estimate def_list  */
-#line 682 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                            {(yyval.l).p= (yyvsp[0].u);(yyval.l).k= param_kind;(yyval.l).s= (hpos-hstart)-(yyvsp[0].u);}
-#line 3485 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 234: /* empty_param_list: position  */
-#line 685 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                         {HPUTX(2);hpos++;hput_tags((yyvsp[0].u),TAG(param_kind,1));}
-#line 3491 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 235: /* $@12: %empty  */
-#line 686 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                {hpos= hpos-2;}
-#line 3497 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 236: /* non_empty_param_list: start "param" $@12 parameters ">"  */
-#line 687 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-{hput_tags((yyvsp[-4].u)-2,hput_list((yyvsp[-4].u)-1,&((yyvsp[-1].l))));}
-#line 3503 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 238: /* font_head: string dimension UNSIGNED UNSIGNED  */
-#line 694 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-{uint8_t f= (yyvsp[-4].u);SET_DBIT(f,font_kind);hfont_name[f]= strdup((yyvsp[-3].s));(yyval.info)= hput_font_head(f,hfont_name[f],(yyvsp[-2].d),(yyvsp[-1].u),(yyvsp[0].u));}
-#line 3509 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 241: /* font_param: start "penalty" fref penalty ">"  */
-#line 699 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                              {hput_tags((yyvsp[-4].u),hput_int((yyvsp[-1].i)));}
-#line 3515 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 242: /* font_param: start "kern" fref kern ">"  */
-#line 700 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                         {hput_tags((yyvsp[-4].u),hput_kern(&((yyvsp[-1].kt))));}
-#line 3521 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 243: /* font_param: start "ligature" fref ligature ">"  */
-#line 701 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                                 {hput_tags((yyvsp[-4].u),hput_ligature(&((yyvsp[-1].lg))));}
-#line 3527 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 244: /* font_param: start "disc" fref disc ">"  */
-#line 702 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                         {hput_tags((yyvsp[-4].u),hput_disc(&((yyvsp[-1].dc))));}
-#line 3533 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 245: /* font_param: start "glue" fref glue ">"  */
-#line 703 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                         {hput_tags((yyvsp[-4].u),hput_glue(&((yyvsp[-1].g))));}
-#line 3539 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 246: /* font_param: start "language" fref string ">"  */
-#line 704 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                               {hput_string((yyvsp[-1].s));hput_tags((yyvsp[-4].u),TAG(language_kind,0));}
-#line 3545 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 247: /* font_param: start "rule" fref rule ">"  */
-#line 705 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                         {hput_tags((yyvsp[-4].u),hput_rule(&((yyvsp[-1].r))));}
-#line 3551 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 248: /* font_param: start "image" fref image ">"  */
-#line 706 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                           {hput_tags((yyvsp[-4].u),hput_image(&((yyvsp[-1].x))));}
-#line 3557 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 249: /* fref: ref  */
-#line 708 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-        {RNG("Font parameter",(yyvsp[0].u),0,MAX_FONT_PARAMS);}
-#line 3563 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 250: /* xdimen_ref: ref  */
-#line 711 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-              {REF(xdimen_kind,(yyvsp[0].u));}
-#line 3569 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 251: /* param_ref: ref  */
-#line 712 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-             {REF(param_kind,(yyvsp[0].u));}
-#line 3575 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 252: /* stream_ref: ref  */
-#line 713 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-              {REF_RNG(stream_kind,(yyvsp[0].u));}
-#line 3581 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 253: /* content_node: start "penalty" ref ">"  */
-#line 717 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                     {REF(penalty_kind,(yyvsp[-1].u));hput_tags((yyvsp[-3].u),TAG(penalty_kind,0));}
-#line 3587 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 254: /* content_node: start "kern" explicit ref ">"  */
-#line 719 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-{REF(dimen_kind,(yyvsp[-1].u));hput_tags((yyvsp[-4].u),TAG(kern_kind,((yyvsp[-2].b))?b100:b000));}
-#line 3593 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 255: /* content_node: start "kern" explicit "xdimen" ref ">"  */
-#line 721 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-{REF(xdimen_kind,(yyvsp[-1].u));hput_tags((yyvsp[-5].u),TAG(kern_kind,((yyvsp[-3].b))?b101:b001));}
-#line 3599 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 256: /* content_node: start "glue" ref ">"  */
-#line 722 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                   {REF(glue_kind,(yyvsp[-1].u));hput_tags((yyvsp[-3].u),TAG(glue_kind,0));}
-#line 3605 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 257: /* content_node: start "ligature" ref ">"  */
-#line 723 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                       {REF(ligature_kind,(yyvsp[-1].u));hput_tags((yyvsp[-3].u),TAG(ligature_kind,0));}
-#line 3611 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 258: /* content_node: start "disc" ref ">"  */
-#line 724 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                   {REF(disc_kind,(yyvsp[-1].u));hput_tags((yyvsp[-3].u),TAG(disc_kind,0));}
-#line 3617 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 259: /* content_node: start "rule" ref ">"  */
-#line 725 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                   {REF(rule_kind,(yyvsp[-1].u));hput_tags((yyvsp[-3].u),TAG(rule_kind,0));}
-#line 3623 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 260: /* content_node: start "image" ref ">"  */
-#line 726 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                    {REF(image_kind,(yyvsp[-1].u));hput_tags((yyvsp[-3].u),TAG(image_kind,0));}
-#line 3629 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 261: /* content_node: start "leaders" ref ">"  */
-#line 727 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                      {REF(leaders_kind,(yyvsp[-1].u));hput_tags((yyvsp[-3].u),TAG(leaders_kind,0));}
-#line 3635 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 262: /* content_node: start "baseline" ref ">"  */
-#line 728 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                       {REF(baseline_kind,(yyvsp[-1].u));hput_tags((yyvsp[-3].u),TAG(baseline_kind,0));}
-#line 3641 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 263: /* content_node: start "language" REFERENCE ">"  */
-#line 729 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                             {REF(language_kind,(yyvsp[-1].u));hput_tags((yyvsp[-3].u),hput_language((yyvsp[-1].u)));}
-#line 3647 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 264: /* glue_node: start "glue" ref ">"  */
-#line 731 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                            {REF(glue_kind,(yyvsp[-1].u));
-if((yyvsp[-1].u)==zero_skip_no){hpos= hpos-2;(yyval.b)= false;}
-else{hput_tags((yyvsp[-3].u),TAG(glue_kind,0));(yyval.b)= true;}}
-#line 3655 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 265: /* $@13: %empty  */
-#line 737 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-                             {hput_content_start();}
-#line 3661 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-  case 266: /* content_section: "<" "content" $@13 content_list ">"  */
-#line 738 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-{hput_content_end();hput_range_defs();hput_label_defs();}
-#line 3667 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-    break;
-
-
-#line 3671 "../../../texk/web2c/hitexdir/hishrink-parser.c"
-
-      default: break;
-    }
-  /* User semantic actions sometimes alter yychar, and that requires
-     that yytoken be updated with the new translation.  We take the
-     approach of translating immediately before every use of yytoken.
-     One alternative is translating here after every semantic action,
-     but that translation would be missed if the semantic action invokes
-     YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
-     if it invokes YYBACKUP.  In the case of YYABORT or YYACCEPT, an
-     incorrect destructor might then be invoked immediately.  In the
-     case of YYERROR or YYBACKUP, subsequent parser actions might lead
-     to an incorrect destructor call or verbose syntax error message
-     before the lookahead is translated.  */
-  YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc);
-
-  YYPOPSTACK (yylen);
-  yylen = 0;
-
-  *++yyvsp = yyval;
-
-  /* Now 'shift' the result of the reduction.  Determine what state
-     that goes to, based on the state we popped back to and the rule
-     number reduced by.  */
-  {
-    const int yylhs = yyr1[yyn] - YYNTOKENS;
-    const int yyi = yypgoto[yylhs] + *yyssp;
-    yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp
-               ? yytable[yyi]
-               : yydefgoto[yylhs]);
-  }
-
-  goto yynewstate;
-
-
-/*--------------------------------------.
-| yyerrlab -- here on detecting error.  |
-`--------------------------------------*/
-yyerrlab:
-  /* Make sure we have latest lookahead translation.  See comments at
-     user semantic actions for why this is necessary.  */
-  yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar);
-  /* If not already recovering from an error, report this error.  */
-  if (!yyerrstatus)
-    {
-      ++yynerrs;
-      {
-        yypcontext_t yyctx
-          = {yyssp, yytoken};
-        char const *yymsgp = YY_("syntax error");
-        int yysyntax_error_status;
-        yysyntax_error_status = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
-        if (yysyntax_error_status == 0)
-          yymsgp = yymsg;
-        else if (yysyntax_error_status == -1)
-          {
-            if (yymsg != yymsgbuf)
-              YYSTACK_FREE (yymsg);
-            yymsg = YY_CAST (char *,
-                             YYSTACK_ALLOC (YY_CAST (YYSIZE_T, yymsg_alloc)));
-            if (yymsg)
-              {
-                yysyntax_error_status
-                  = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
-                yymsgp = yymsg;
-              }
-            else
-              {
-                yymsg = yymsgbuf;
-                yymsg_alloc = sizeof yymsgbuf;
-                yysyntax_error_status = YYENOMEM;
-              }
-          }
-        yyerror (yymsgp);
-        if (yysyntax_error_status == YYENOMEM)
-          YYNOMEM;
-      }
-    }
-
-  if (yyerrstatus == 3)
-    {
-      /* If just tried and failed to reuse lookahead token after an
-         error, discard it.  */
-
-      if (yychar <= YYEOF)
-        {
-          /* Return failure if at end of input.  */
-          if (yychar == YYEOF)
-            YYABORT;
-        }
-      else
-        {
-          yydestruct ("Error: discarding",
-                      yytoken, &yylval);
-          yychar = YYEMPTY;
-        }
-    }
-
-  /* Else will try to reuse lookahead token after shifting the error
-     token.  */
-  goto yyerrlab1;
-
-
-/*---------------------------------------------------.
-| yyerrorlab -- error raised explicitly by YYERROR.  |
-`---------------------------------------------------*/
-yyerrorlab:
-  /* Pacify compilers when the user code never invokes YYERROR and the
-     label yyerrorlab therefore never appears in user code.  */
-  if (0)
-    YYERROR;
-  ++yynerrs;
-
-  /* Do not reclaim the symbols of the rule whose action triggered
-     this YYERROR.  */
-  YYPOPSTACK (yylen);
-  yylen = 0;
-  YY_STACK_PRINT (yyss, yyssp);
-  yystate = *yyssp;
-  goto yyerrlab1;
-
-
-/*-------------------------------------------------------------.
-| yyerrlab1 -- common code for both syntax error and YYERROR.  |
-`-------------------------------------------------------------*/
-yyerrlab1:
-  yyerrstatus = 3;      /* Each real token shifted decrements this.  */
-
-  /* Pop stack until we find a state that shifts the error token.  */
-  for (;;)
-    {
-      yyn = yypact[yystate];
-      if (!yypact_value_is_default (yyn))
-        {
-          yyn += YYSYMBOL_YYerror;
-          if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror)
-            {
-              yyn = yytable[yyn];
-              if (0 < yyn)
-                break;
-            }
-        }
-
-      /* Pop the current state because it cannot handle the error token.  */
-      if (yyssp == yyss)
-        YYABORT;
-
-
-      yydestruct ("Error: popping",
-                  YY_ACCESSING_SYMBOL (yystate), yyvsp);
-      YYPOPSTACK (1);
-      yystate = *yyssp;
-      YY_STACK_PRINT (yyss, yyssp);
-    }
-
-  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-  *++yyvsp = yylval;
-  YY_IGNORE_MAYBE_UNINITIALIZED_END
-
-
-  /* Shift the error token.  */
-  YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp);
-
-  yystate = yyn;
-  goto yynewstate;
-
-
-/*-------------------------------------.
-| yyacceptlab -- YYACCEPT comes here.  |
-`-------------------------------------*/
-yyacceptlab:
-  yyresult = 0;
-  goto yyreturnlab;
-
-
-/*-----------------------------------.
-| yyabortlab -- YYABORT comes here.  |
-`-----------------------------------*/
-yyabortlab:
-  yyresult = 1;
-  goto yyreturnlab;
-
-
-/*-----------------------------------------------------------.
-| yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here.  |
-`-----------------------------------------------------------*/
-yyexhaustedlab:
-  yyerror (YY_("memory exhausted"));
-  yyresult = 2;
-  goto yyreturnlab;
-
-
-/*----------------------------------------------------------.
-| yyreturnlab -- parsing is finished, clean up and return.  |
-`----------------------------------------------------------*/
-yyreturnlab:
-  if (yychar != YYEMPTY)
-    {
-      /* Make sure we have latest lookahead translation.  See comments at
-         user semantic actions for why this is necessary.  */
-      yytoken = YYTRANSLATE (yychar);
-      yydestruct ("Cleanup: discarding lookahead",
-                  yytoken, &yylval);
-    }
-  /* Do not reclaim the symbols of the rule whose action triggered
-     this YYABORT or YYACCEPT.  */
-  YYPOPSTACK (yylen);
-  YY_STACK_PRINT (yyss, yyssp);
-  while (yyssp != yyss)
-    {
-      yydestruct ("Cleanup: popping",
-                  YY_ACCESSING_SYMBOL (+*yyssp), yyvsp);
-      YYPOPSTACK (1);
-    }
-#ifndef yyoverflow
-  if (yyss != yyssa)
-    YYSTACK_FREE (yyss);
-#endif
-  if (yymsg != yymsgbuf)
-    YYSTACK_FREE (yymsg);
-  return yyresult;
-}
-
-#line 741 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-
-/*:510*/

Deleted: trunk/Build/source/texk/web2c/hitexdir/hishrink-parser.h
===================================================================
--- trunk/Build/source/texk/web2c/hitexdir/hishrink-parser.h	2021-11-12 00:49:04 UTC (rev 61032)
+++ trunk/Build/source/texk/web2c/hitexdir/hishrink-parser.h	2021-11-12 11:09:17 UTC (rev 61033)
@@ -1,258 +0,0 @@
-/* A Bison parser, made by GNU Bison 3.8.2.  */
-
-/* Bison interface for Yacc-like parsers in C
-
-   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation,
-   Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
-
-/* As a special exception, you may create a larger work that contains
-   part or all of the Bison parser skeleton and distribute that work
-   under terms of your choice, so long as that work isn't itself a
-   parser generator using the skeleton or a modified version thereof
-   as a parser skeleton.  Alternatively, if you modify or redistribute
-   the parser skeleton itself, you may (at your option) remove this
-   special exception, which will cause the skeleton and the resulting
-   Bison output files to be licensed under the GNU General Public
-   License without this special exception.
-
-   This special exception was added by the Free Software Foundation in
-   version 2.2 of Bison.  */
-
-/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
-   especially those whose name start with YY_ or yy_.  They are
-   private implementation details that can be changed or removed.  */
-
-#ifndef YY_YY__TEXK_WEB_C_HITEXDIR_HISHRINK_PARSER_H_INCLUDED
-# define YY_YY__TEXK_WEB_C_HITEXDIR_HISHRINK_PARSER_H_INCLUDED
-/* Debug traces.  */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-#if YYDEBUG
-extern int yydebug;
-#endif
-
-/* Token kinds.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-  enum yytokentype
-  {
-    YYEMPTY = -2,
-    YYEOF = 0,                     /* "end of file"  */
-    YYerror = 256,                 /* error  */
-    YYUNDEF = 257,                 /* "invalid token"  */
-    START = 258,                   /* "<"  */
-    END = 259,                     /* ">"  */
-    GLYPH = 260,                   /* "glyph"  */
-    UNSIGNED = 261,                /* UNSIGNED  */
-    REFERENCE = 262,               /* REFERENCE  */
-    SIGNED = 263,                  /* SIGNED  */
-    STRING = 264,                  /* STRING  */
-    CHARCODE = 265,                /* CHARCODE  */
-    FPNUM = 266,                   /* FPNUM  */
-    DIMEN = 267,                   /* "dimen"  */
-    PT = 268,                      /* "pt"  */
-    MM = 269,                      /* "mm"  */
-    INCH = 270,                    /* "in"  */
-    XDIMEN = 271,                  /* "xdimen"  */
-    H = 272,                       /* "h"  */
-    V = 273,                       /* "v"  */
-    FIL = 274,                     /* "fil"  */
-    FILL = 275,                    /* "fill"  */
-    FILLL = 276,                   /* "filll"  */
-    PENALTY = 277,                 /* "penalty"  */
-    INTEGER = 278,                 /* "int"  */
-    LANGUAGE = 279,                /* "language"  */
-    RULE = 280,                    /* "rule"  */
-    RUNNING = 281,                 /* "|"  */
-    KERN = 282,                    /* "kern"  */
-    EXPLICIT = 283,                /* "!"  */
-    GLUE = 284,                    /* "glue"  */
-    PLUS = 285,                    /* "plus"  */
-    MINUS = 286,                   /* "minus"  */
-    TXT_START = 287,               /* TXT_START  */
-    TXT_END = 288,                 /* TXT_END  */
-    TXT_IGNORE = 289,              /* TXT_IGNORE  */
-    TXT_FONT_GLUE = 290,           /* TXT_FONT_GLUE  */
-    TXT_FONT_HYPHEN = 291,         /* TXT_FONT_HYPHEN  */
-    TXT_FONT = 292,                /* TXT_FONT  */
-    TXT_LOCAL = 293,               /* TXT_LOCAL  */
-    TXT_GLOBAL = 294,              /* TXT_GLOBAL  */
-    TXT_CC = 295,                  /* TXT_CC  */
-    HBOX = 296,                    /* "hbox"  */
-    VBOX = 297,                    /* "vbox"  */
-    SHIFTED = 298,                 /* "shifted"  */
-    HPACK = 299,                   /* "hpack"  */
-    HSET = 300,                    /* "hset"  */
-    VPACK = 301,                   /* "vpack"  */
-    VSET = 302,                    /* "vset"  */
-    DEPTH = 303,                   /* "depth"  */
-    ADD = 304,                     /* "add"  */
-    TO = 305,                      /* "to"  */
-    LEADERS = 306,                 /* "leaders"  */
-    ALIGN = 307,                   /* "align"  */
-    CENTER = 308,                  /* "center"  */
-    EXPAND = 309,                  /* "expand"  */
-    BASELINE = 310,                /* "baseline"  */
-    LIGATURE = 311,                /* "ligature"  */
-    DISC = 312,                    /* "disc"  */
-    PAR = 313,                     /* "par"  */
-    MATH = 314,                    /* "math"  */
-    ON = 315,                      /* "on"  */
-    OFF = 316,                     /* "off"  */
-    ADJUST = 317,                  /* "adjust"  */
-    TABLE = 318,                   /* "table"  */
-    ITEM = 319,                    /* "item"  */
-    IMAGE = 320,                   /* "image"  */
-    LABEL = 321,                   /* "label"  */
-    BOT = 322,                     /* "bot"  */
-    MID = 323,                     /* "mid"  */
-    LINK = 324,                    /* "link"  */
-    OUTLINE = 325,                 /* "outline"  */
-    STREAM = 326,                  /* "stream"  */
-    STREAMDEF = 327,               /* "stream (definition)"  */
-    FIRST = 328,                   /* "first"  */
-    LAST = 329,                    /* "last"  */
-    TOP = 330,                     /* "top"  */
-    NOREFERENCE = 331,             /* "*"  */
-    PAGE = 332,                    /* "page"  */
-    RANGE = 333,                   /* "range"  */
-    DIRECTORY = 334,               /* "directory"  */
-    SECTION = 335,                 /* "entry"  */
-    DEFINITIONS = 336,             /* "definitions"  */
-    MAX = 337,                     /* "max"  */
-    PARAM = 338,                   /* "param"  */
-    FONT = 339,                    /* "font"  */
-    CONTENT = 340                  /* "content"  */
-  };
-  typedef enum yytokentype yytoken_kind_t;
-#endif
-/* Token kinds.  */
-#define YYEMPTY -2
-#define YYEOF 0
-#define YYerror 256
-#define YYUNDEF 257
-#define START 258
-#define END 259
-#define GLYPH 260
-#define UNSIGNED 261
-#define REFERENCE 262
-#define SIGNED 263
-#define STRING 264
-#define CHARCODE 265
-#define FPNUM 266
-#define DIMEN 267
-#define PT 268
-#define MM 269
-#define INCH 270
-#define XDIMEN 271
-#define H 272
-#define V 273
-#define FIL 274
-#define FILL 275
-#define FILLL 276
-#define PENALTY 277
-#define INTEGER 278
-#define LANGUAGE 279
-#define RULE 280
-#define RUNNING 281
-#define KERN 282
-#define EXPLICIT 283
-#define GLUE 284
-#define PLUS 285
-#define MINUS 286
-#define TXT_START 287
-#define TXT_END 288
-#define TXT_IGNORE 289
-#define TXT_FONT_GLUE 290
-#define TXT_FONT_HYPHEN 291
-#define TXT_FONT 292
-#define TXT_LOCAL 293
-#define TXT_GLOBAL 294
-#define TXT_CC 295
-#define HBOX 296
-#define VBOX 297
-#define SHIFTED 298
-#define HPACK 299
-#define HSET 300
-#define VPACK 301
-#define VSET 302
-#define DEPTH 303
-#define ADD 304
-#define TO 305
-#define LEADERS 306
-#define ALIGN 307
-#define CENTER 308
-#define EXPAND 309
-#define BASELINE 310
-#define LIGATURE 311
-#define DISC 312
-#define PAR 313
-#define MATH 314
-#define ON 315
-#define OFF 316
-#define ADJUST 317
-#define TABLE 318
-#define ITEM 319
-#define IMAGE 320
-#define LABEL 321
-#define BOT 322
-#define MID 323
-#define LINK 324
-#define OUTLINE 325
-#define STREAM 326
-#define STREAMDEF 327
-#define FIRST 328
-#define LAST 329
-#define TOP 330
-#define NOREFERENCE 331
-#define PAGE 332
-#define RANGE 333
-#define DIRECTORY 334
-#define SECTION 335
-#define DEFINITIONS 336
-#define MAX 337
-#define PARAM 338
-#define FONT 339
-#define CONTENT 340
-
-/* Value type.  */
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-union YYSTYPE
-{
-#line 78 "../../../texk/web2c/hitexdir/hishrink-parser.y"
-uint32_t u;int32_t i;char*s;float64_t f;glyph_t c;
-dimen_t d;stretch_t st;xdimen_t xd;kern_t kt;
-rule_t r;glue_t g;image_t x;
-list_t l;box_t h;disc_t dc;lig_t lg;
-ref_t rf;info_t info;order_t o;bool b;
-
-#line 244 "../../../texk/web2c/hitexdir/hishrink-parser.h"
-
-};
-typedef union YYSTYPE YYSTYPE;
-# define YYSTYPE_IS_TRIVIAL 1
-# define YYSTYPE_IS_DECLARED 1
-#endif
-
-
-extern YYSTYPE yylval;
-
-
-int yyparse (void);
-
-
-#endif /* !YY_YY__TEXK_WEB_C_HITEXDIR_HISHRINK_PARSER_H_INCLUDED  */

Modified: trunk/Build/source/texk/web2c/hitexdir/hitex.w
===================================================================
--- trunk/Build/source/texk/web2c/hitexdir/hitex.w	2021-11-12 00:49:04 UTC (rev 61032)
+++ trunk/Build/source/texk/web2c/hitexdir/hitex.w	2021-11-12 11:09:17 UTC (rev 61033)
@@ -24,207 +24,29924 @@
 % dealings in this Software without prior written authorization from the
 % copyright holders.
 
-\input ../hint.sty
-\input ../changefile.sty
+% The HINT program is derived from Donald E. Knuth's TeX and the
+% subsequent e-TeX extension of TeX.
 
-%% defining how to display certain C identifiers
+% Prote is copyright (C) 2021 by Thierry Laronde and put under
+% the kerTeX Public License version 1.0 (a BSD type license with a
+% simplified advertising clause).
+%
+% As TeX and e-TeX are reserved names for the unchanged (except for the
+% necessary implementation of system dependencies) instances of, resp.,
+% Donald E. Knuth's program and the NTS team's e-TeX implementation, the
+% name Prote is reserved for this kerTeX implementation.
+%
+% Hence, this is neither TeX (even if it is compatible at start) nor
+% e-TeX (even if is compatible when entering the first set of
+% extensions).
+
+% Version 0 was released in September 1982 after it passed a variety of tests.
+% Version 1 was released in November 1983 after thorough testing.
+% Version 1.1 fixed ``disappearing font identifiers'' et alia (July 1984).
+% Version 1.2 allowed `0' in response to an error, et alia (October 1984).
+% Version 1.3 made memory allocation more flexible and local (November 1984).
+% Version 1.4 fixed accents right after line breaks, et alia (April 1985).
+% Version 1.5 fixed \the\toks after other expansion in \edefs (August 1985).
+% Version 2.0 (almost identical to 1.5) corresponds to "Volume B" (April 1986).
+% Version 2.1 corrected anomalies in discretionary breaks (January 1987).
+% Version 2.2 corrected "(Please type...)" with null \endlinechar (April 1987).
+% Version 2.3 avoided incomplete page in premature termination (August 1987).
+% Version 2.4 fixed \noaligned rules in indented displays (August 1987).
+% Version 2.5 saved cur_order when expanding tokens (September 1987).
+% Version 2.6 added 10sp slop when shipping leaders (November 1987).
+% Version 2.7 improved rounding of negative-width characters (November 1987).
+% Version 2.8 fixed weird bug if no \patterns are used (December 1987).
+% Version 2.9 made \csname\endcsname's "relax" local (December 1987).
+% Version 2.91 fixed \outer\def\a0{}\a\a bug (April 1988).
+% Version 2.92 fixed \patterns, also file names with complex macros (May 1988).
+% Version 2.93 fixed negative halving in allocator when mem_min<0 (June 1988).
+% Version 2.94 kept open_log_file from calling fatal_error (November 1988).
+% Version 2.95 solved that problem a better way (December 1988).
+% Version 2.96 corrected bug in "Infinite shrinkage" recovery (January 1989).
+% Version 2.97 corrected blunder in creating 2.95 (February 1989).
+% Version 2.98 omitted save_for_after at outer level (March 1989).
+% Version 2.99 caught $$\begingroup\halign..$$ (June 1989).
+% Version 2.991 caught .5\ifdim.6... (June 1989).
+% Version 2.992 introduced major changes for 8-bit extensions (September 1989).
+% Version 2.993 fixed a save_stack synchronization bug et alia (December 1989).
+% Version 3.0 fixed unusual displays; was more \output robust (March 1990).
+% Version 3.1 fixed nullfont, disabled \write{\the\prevgraf} (September 1990).
+% Version 3.14 fixed unprintable font names and corrected typos (March 1991).
+% Version 3.141 more of same; reconstituted ligatures better (March 1992).
+% Version 3.1415 preserved nonexplicit kerns, tidied up (February 1993).
+% Version 3.14159 allowed fontmemsize to change; bulletproofing (March 1995).
+% Version 3.141592 fixed \xleaders, glueset, weird alignments (December 2002).
+% Version 3.1415926 was a general cleanup with minor fixes (February 2008).
+% Version 3.14159265 was similar (January 2014).
+% Version 3.141592653 was similar but more extensive (January 2021).
+
+% A reward of $327.68 will be paid to the first finder of any remaining bug.
+
+% This is a beta version of 1.0 of Prote, developed during August 2021,
+% and corrected during september/october 2021.
+%
+% 1.0: adds primitives needed by LaTeX as listed in ltnews31.
+%  History towards 1.0 release:
+%    0.99.4:
+%      - typos and style corrections provided by Martin Ruckert for
+%      clean translation in Pascal (forward declarations and underscores
+%      omitted);
+%      - adjustements against e-TeX 2.6 instead of 2.1 (T. Laronde).
+%    0.99.7:
+%      - \expanded was using an e-TeX procedure not doing def handling
+%        => using scan_toks() now. Reported by Martin Ruckert and
+%        test code narrowed down by Phelype Oleinik.
+%    0.99.8:
+%      - \expanded again: scan_toks() sets def_ref. But back_list()
+%        has to take not the refernce count, but the first token.
+%        Passing def_ref, a next invocation of scan_toks() was inserting
+%        a missing left brace and then reading pass the end of the token
+%        list to find a matching right one. def_ref => link(def_ref).
+%        Test code narrowed down by Phelype Oleinik (a great help!).
+%      - The API for file related primitives has been changed: no error
+%        is reported on failure to find/open and nothing is returned
+%        (matches current other implementations).
+%
+% This work was done by Thierry Laronde and is under the kerTeX
+% Public License version 1.0. There is absolutely no warranty of any
+% kind! Use it at your own risks!
+%
+%
+
+% Here is TeX material that gets inserted after \input webmac
+\def\hang{\hangindent 3em\noindent\ignorespaces}
+\def\hangg#1 {\hang\hbox{#1 }}
+\def\textindent#1{\hangindent2.5em\noindent\hbox to2.5em{\hss#1 }\ignorespaces}
+\font\ninerm=cmr9
+\let\mc=\ninerm % medium caps for names like SAIL
+\def\Prote{{\tenrm P\kern-0.1em R\kern-0.15em\raise.11ex\hbox{o}%
+  \kern-0.22em T\kern-0.05em E}}
+\ifacro
+\sanitizecommand{\eTeX}{eTeX}
+\sanitizecommand{\Prote}{PRoTE}
+\fi
+\font\tenlogo=logo10
+\def\MP{{\tenlogo META}\-{\tenlogo POST}}
+\def\eTeX{$\varepsilon$-\TeX}
+\font\sf=cmss10 % used for the HINT name
+\def\HINT{\leavevmode\hbox{\sf HINT\spacefactor1000}}
+\ifacro\sanitizecommand{\HINT}{HINT}\fi
+\font\revrm=xbmc10 % for right-to-left text
+% to generate xbmc10 (i.e., reflected cmbx10) use a file
+% xbmc10.mf containing:
+%+++++++++++++++++++++++++++++++++++++++++++++++++
+%     if unknown cmbase: input cmbase fi
+%     extra_endchar := extra_endchar &
+%       "currentpicture:=currentpicture " &
+%       "reflectedabout((.5[l,r],0),(.5[l,r],1));";
+%     input cmbx10
+%+++++++++++++++++++++++++++++++++++++++++++++++++
+\ifx\beginL\undefined % this is TeX
+  \def\XeT{X\kern-.125em\lower.5ex\hbox{E}\kern-.1667emT}
+  \def\TeXeT{\TeX-\hbox{\revrm \XeT}}   % for TeX-XeT
+  \def\TeXXeT{\TeX-\hbox{\revrm -\XeT}} % for TeX--XeT
+\else
+  \ifx\eTeXversion\undefined % this is \TeXeT
+    \def\TeXeT{\TeX-{\revrm\beginR\TeX\endR}}   % for TeX-XeT
+    \def\TeXXeT{\TeX-{\revrm\beginR\TeX-\endR}} % for TeX--XeT
+  \else % this is \eTeX
+    \def\TeXeT{\TeX-{\TeXXeTstate=1\revrm\beginR\TeX\endR}}   % for TeX-XeT
+    \def\TeXXeT{\TeX-{\TeXXeTstate=1\revrm\beginR\TeX-\endR}} % for TeX--XeT
+  \fi
+\fi
+\def\PASCAL{Pascal}
+\def\ph{\hbox{Pascal-H}}
+\def\pct!{{\char`\%}} % percent sign in ordinary text
+\def\grp{\.{\char'173...\char'175}}
+\font\logo=logo10 % font used for the METAFONT logo
+\def\MF{{\logo META}\-{\logo FONT}}
+\def\<#1>{$\langle#1\rangle$}
+\def\section{\mathhexbox278}
+
+\def\(#1){} % this is used to make section names sort themselves better
+\def\9#1{} % this is used for sort keys in the index via @@:sort key}{entry@@>
+
+\let\@@=\relax % we want to be able to \write a \?
+
+\def\title{Hi\TeX}
+\def\LaTeX{L\kern-.36em\raise.3ex\hbox{\sc A}\kern-.15em\TeX}%
+% system dependent redefinitions of \title should come later
+% and should use:
+%    \toks0=\expandafter{\title}
+%    \edef\title{...\the\toks0...}
+%\let\maybe=\iffalse % print only changed modules
+\def\topofcontents{\hsize 5.5in
+  \vglue 0pt plus 1fil minus 1.5in
+  \def\@@##1]{\hbox to 1in{\hfil##1.\ }}
+  }
+\def\botofcontents{\vskip 0pt plus 1fil minus 1.5in}
+\pageno=3
+\def\glob{13} % this should be the section number of "<Global...>"
+\def\gglob{20, 26} % this should be the next two sections of "<Global...>"
+
+\def\.#1{\leavevmode\hbox{\tentex % typewriter type for strings
+  \let\\=\BS % backslash in a string
+  \let\'=\RQ % right quote in a string
+  \let\`=\LQ % left quote in a string
+  \let\{=\LB % left brace in a string
+  \let\}=\RB % right brace in a string
+  \let\~=\TL % tilde in a string
+  \let\ =\SP % space in a string
+  \let\_=\UL % underline in a string
+  \let\&=\AM % ampersand in a string
+  #1\kern.05em}}
+\def\^{\ifmmode\mathchar"222 \else\char`^ \fi} % pointer or hat
+\def\LQ{{\tt\char'22}} % left quote in a string
+\def\RQ{{\tt\char'23}} % right quote in a string
+\def\dotdot{\mathrel{.\,.}} % double dot, used only in math mode
+ at s dotdot TeX
+@* Introduction.
+This is Hi\TeX, a program derived from and extending the capabilities
+of \TeX\ plus \eTeX\ plus \Prote\ plus k\TeX,
+a document compiler intended to produce typesetting of high
+quality.
+The \PASCAL\ program that follows is the definition of \TeX82, a standard
+@:PASCAL}{\PASCAL@>
+@!@:TeX82}{\TeX82@>
+version of \TeX\ that is designed to be highly portable so that identical output
+will be obtainable on a great variety of computers.
+
+The main purpose of the following program is to explain the algorithms of \TeX\
+as clearly as possible. As a result, the program will not necessarily be very
+efficient when a particular \PASCAL\ compiler has translated it into a
+particular machine language. However, the program has been written so that it
+can be tuned to run efficiently in a wide variety of operating environments
+by making comparatively few changes. Such flexibility is possible because
+the documentation that follows is written in the \.{WEB} language, which is
+at a higher level than \PASCAL; the preprocessing step that converts \.{WEB}
+to \PASCAL\ is able to introduce most of the necessary refinements.
+Semi-automatic translation to other languages is also feasible, because the
+program below does not make extensive use of features that are peculiar to
+\PASCAL.
+
+A large piece of software like \TeX\ has inherent complexity that cannot
+be reduced below a certain level of difficulty, although each individual
+part is fairly simple by itself. The \.{WEB} language is intended to make
+the algorithms as readable as possible, by reflecting the way the
+individual program pieces fit together and by providing the
+cross-references that connect different parts. Detailed comments about
+what is going on, and about why things were done in certain ways, have
+been liberally sprinkled throughout the program.  These comments explain
+features of the implementation, but they rarely attempt to explain the
+\TeX\ language itself, since the reader is supposed to be familiar with
+{\sl The \TeX book}.
+ at .WEB@>
+@:TeXbook}{\sl The \TeX book@>
+
+@ The present implementation has a long ancestry, beginning in the summer
+of~1977, when Michael~F. Plass and Frank~M. Liang designed and coded
+a prototype
+@^Plass, Michael Frederick@>
+@^Liang, Franklin Mark@>
+@^Knuth, Donald Ervin@>
+based on some specifications that the author (in the following, unless
+specified, ``the author'' refers to D.E.~Knuth) had made in May of that year.
+This original proto\TeX\ included macro definitions and elementary
+manipulations on boxes and glue, but it did not have line-breaking,
+page-breaking, mathematical formulas, alignment routines, error recovery,
+or the present semantic nest; furthermore,
+it used character lists instead of token lists, so that a control sequence
+like \.{\\halign} was represented by a list of seven characters. A
+complete version of \TeX\ was designed and coded by the author in late
+1977 and early 1978; that program, like its prototype, was written in the
+{\mc SAIL} language, for which an excellent debugging system was
+available. Preliminary plans to convert the {\mc SAIL} code into a form
+somewhat like the present ``web'' were developed by Luis Trabb~Pardo and
+@^Trabb Pardo, Luis Isidoro@>
+the author at the beginning of 1979, and a complete implementation was
+created by Ignacio~A. Zabala in 1979 and 1980. The \TeX82 program, which
+@^Zabala Salelles, Ignacio Andr\'es@>
+was written by the author during the latter part of 1981 and the early
+part of 1982, also incorporates ideas from the 1979 implementation of
+@^Guibas, Leonidas Ioannis@>
+@^Sedgewick, Robert@>
+@^Wyatt, Douglas Kirk@>
+\TeX\ in {\mc MESA} that was written by Leonidas Guibas, Robert Sedgewick,
+and Douglas Wyatt at the Xerox Palo Alto Research Center.  Several hundred
+refinements were introduced into \TeX82 based on the experiences gained with
+the original implementations, so that essentially every part of the system
+has been substantially improved. After the appearance of ``Version 0'' in
+September 1982, this program benefited greatly from the comments of
+many other people, notably David~R. Fuchs and Howard~W. Trickey.
+A final revision in September 1989 extended the input character set to
+eight-bit codes and introduced the ability to hyphenate words from
+different languages, based on some ideas of Michael~J. Ferguson.
+@^Fuchs, David Raymond@>
+@^Trickey, Howard Wellington@>
+@^Ferguson, Michael John@>
+
+No doubt there still is plenty of room for improvement, but the author
+is firmly committed to keeping \TeX82 ``frozen'' from now on; stability
+and reliability are to be its main virtues.
+
+On the other hand, the \.{WEB} description can be extended without changing
+the core of \TeX82 itself, and the program has been designed so that such
+extensions are not extremely difficult to make.
+The |banner| string defined here should be changed whenever \TeX\
+undergoes any modifications, so that it will be clear which version of
+\TeX\ might be the guilty party when a problem arises.
+@^extensions to \TeX@>
+@^system dependencies@>
+
+This program contains code for various features extending \TeX,
+therefore this program is called `\Prote' and not
+`\TeX'; the official name `\TeX' by itself is reserved
+for software systems that are fully compatible with each other.
+A special test suite called the ``\.{TRIP} test'' is available for
+helping to determine whether a particular implementation deserves to be
+known as `\TeX' [cf.~Stanford Computer Science report CS1027,
+November 1984].
+
+A similar test suite called the ``\.{SELLETTE} test'' is available for
+helping to determine whether a particular implementation deserves to be
+known as `\Prote'.
+
+ at d eTeX_version 2 /* \.{\\eTeXversion} */
+ at d eTeX_revision ".6" /* \.{\\eTeXrevision} */
+ at d eTeX_version_string "-2.6" /*current \eTeX\ version*/
+@#
+ at d TeX_banner "This is TeX, Version 3.141592653" /*printed when \TeX\ starts*/
+@#
+@#
+ at d TEX ETEX /*change program name into |ETEX|*/
+@#
+ at d eTeX_states 1 /*number of \eTeX\ state variables in |eqtb|*/
+@#
+ at d Prote_version_string "3.141592653-2.6-0.99.8" /*current \Prote\ version*/
+ at d Prote_version 0 /* \.{\\Proteversion} */
+ at d Prote_revision ".99.8" /* \.{\\Proterevision} */
+@#
+ at d Prote_banner "This is Prote, Version " Prote_version_string
+   /*printed when \Prote\ starts*/
+@#
+ at d HiTeX_version_string Prote_version_string "-1.0"
+@#
+ at d banner "This is HiTeX, Version 3.141592653" HiTeX_version_string  /*printed when \TeX\ starts*/
+
+@ Different \PASCAL s have slightly different conventions, and the present
+@!@:PASCAL H}{\ph@>
+program expresses \TeX\ in terms of the \PASCAL\ that was
+available to the author in 1982. Constructions that apply to
+this particular compiler, which we shall call \ph, should help the
+reader see how to make an appropriate interface for other systems
+if necessary. (\ph\ is Charles Hedrick's modification of a compiler
+@^Hedrick, Charles Locke@>
+for the DECsystem-10 that was originally developed at the University of
+Hamburg; cf.\ {\sl Software---Practice and Experience \bf6} (1976),
+29--42. The \TeX\ program below is intended to be adaptable, without
+extensive changes, to most other versions of \PASCAL, so it does not fully
+use the admirable features of \ph. Indeed, a conscious effort has been
+made here to avoid using several idiosyncratic features of standard
+\PASCAL\ itself, so that most of the code can be translated mechanically
+into other high-level languages. For example, the `\&{with}' and `\\{new}'
+features are not used, nor are pointer types, set types, or enumerated
+scalar types; there are no `\&{var}' parameters, except in the case of files
+--- \eTeX, however, does use `\&{var}' parameters for the |reverse| function;
+there are no tag fields on variant records; there are no assignments
+|double=int|; no procedures are declared local to other procedures.)
+
+The portions of this program that involve system-dependent code, where
+changes might be necessary because of differences between \PASCAL\ compilers
+and/or differences between
+operating systems, can be identified by looking at the sections whose
+numbers are listed under `system dependencies' in the index. Furthermore,
+the index entries for `dirty \PASCAL' list all places where the restrictions
+of \PASCAL\ have not been followed perfectly, for one reason or another.
+@!@^system dependencies@>
+@!@^dirty \PASCAL@>
+
+Incidentally, \PASCAL's standard |round| function can be problematical,
+because it disagrees with the IEEE floating-point standard.
+Many implementors have
+therefore chosen to substitute their own home-grown rounding procedure.
+
+@ The following is an outline of the program, whose
+components will be filled in later, using the conventions of \.{WEB}.
+ at .WEB@>
+For example, the portion of the program called `\X\glob:Global
+variables\X' below will be replaced by a sequence of variable declarations
+that starts in $\section\glob$ of this documentation. In this way, we are able
+to define each individual global variable when we are prepared to
+understand what it means; we do not have to define all of the globals at
+once.  Cross references in $\section\glob$, where it says ``See also
+sections \gglob, \dots,'' also make it possible to look at the set of
+all global variables, if desired.  Similar remarks apply to the other
+portions of the program.
+
+ at p @<Header files and function declarations@>@;
+ at h
+enum {@+@<Constants in the outer block@>@+};
+@<Types in the outer block@>@;
+@<Forward declarations@>@;
+@<Global variables@>@;
+@#
+static void initialize(void) /*this procedure gets things started properly*/
+  {@+@<Local variables for initialization@>@;
+  @<Initialize whatever \TeX\ might access@>;
+  } @#
+@<Basic printing procedures@>@;
+@<Error handling procedures@>@;
+
+@ The overall \TeX\ program begins with the heading just shown, after which
+comes a bunch of procedure declarations and function declarations.
+Finally we will get to the main program, which begins with the
+comment `|start_here|'. If you want to skip down to the
+main program now, you can look up `|start_here|' in the index.
+But the author suggests that the best way to understand this program
+is to follow pretty much the order of \TeX's components as they appear in the
+\.{WEB} description you are now reading, since the present ordering is
+intended to combine the advantages of the ``bottom up'' and ``top down''
+approaches to the problem of understanding a somewhat complicated system.
+
+@ There is no need to declare labels in \CEE/, but occasionally
+it is necessary to insert header files and declare functions
+very early in the program. For example, the function |s_no|
+which uses |make_string| to convert a \CEE/ string into
+a string number is used in |initialize| and needs a forward
+declaration.
+
+@<Header files and function declarations@>=
+static int s_no(const char *str);
+
+@ Some of the code below is intended to be used only when diagnosing the
+strange behavior that sometimes occurs when \TeX\ is being installed or
+when system wizards are fooling around with \TeX\ without quite knowing
+what they are doing. Such code will not normally be compiled; it is
+delimited by the codewords `$|debug|\ldots|debug|$', with apologies
+to people who wish to preserve the purity of English.
+
+Similarly, there is some conditional code delimited by
+`$|stat|\ldots|tats|$' that is intended for use when statistics are to be
+kept about \TeX's memory usage.  The |stat| $\ldots$ |tats| code also
+implements diagnostic information for \.{\\tracingparagraphs},
+\.{\\tracingpages}, and \.{\\tracingrestores}.
+@^debugging@>
+
+@ This program has two important variations: (1) There is a long and slow
+version called \.{INITEX}, which does the extra calculations needed to
+ at .INITEX@>
+initialize \TeX's internal tables; and (2)~there is a shorter and faster
+production version, which cuts the initialization to a bare minimum.
+Parts of the program that are needed in (1) but not in (2) are delimited by
+|#ifdef| |INIT|\dots\ |#endif|.
+
+\TeX\ Live has established the common practice
+to select the initialization code at runtime
+using the |iniversion| variable.
+
+@<Initialize whatever...@>=
+@<Set initial values of key variables@>@/
+#ifdef @!INIT
+if (iniversion) {@+@<Initialize table entries (done by \.{INITEX} only)@>@;@+}
+#endif
+
+@ The declaration of all basic type definitions needed by Hi\TeX\ are
+contained in a system dependent header file.
+
 @s uint8_t int
+ at s int16_t int
 @s uint16_t int
+ at s int32_t int
 @s uint32_t int
- at s uint64_t int
- at s int8_t int
- at s int16_t int
- at s int32_t int
- at s float64_t int
- at s float32_t int
- at s scaled int
+ at s halfword int
+ at s in TeX
+ at s line normal
+ at s to   do
+
+@<Header files and function declarations@>=
+#include "hibasetypes.h"
+#include <string.h>
+#include <math.h>
+
+@ Further it is necessary to define some build in primitives of
+\PASCAL\ that are otherwise not available in \CEE/.
+@:PASCAL H}{\ph@>
+
+ at d odd(X)       ((X)&1)
+ at d chr(X)       ((unsigned char)(X))
+ at d ord(X)       ((unsigned int)(X))
+ at d abs(X)       ((X)>-(X)?(X):-(X))
+ at d round(X)     ((int)((X)>=0.0?floor((X)+0.5):ceil((X)-0.5)))
+
+@ The following parameters can be changed at compile time to extend or
+reduce \TeX's capacity. They may have different values in \.{INITEX} and
+in production versions of \TeX.
+ at .INITEX@>
+@^system dependencies@>
+
+@<Constants...@>=
+@!mem_max=5000000, /*greatest index in \TeX's internal |mem| array;
+  must be strictly less than |max_halfword|;
+  must be equal to |mem_top| in \.{INITEX}, otherwise | >= mem_top|*/
+@!mem_min=0, /*smallest index in \TeX's internal |mem| array;
+  must be |min_halfword| or more;
+  must be equal to |mem_bot| in \.{INITEX}, otherwise | <= mem_bot|*/
+@!buf_size=2000000, /*maximum number of characters simultaneously present in
+  current lines of open files and in control sequences between
+  \.{\\csname} and \.{\\endcsname}; must not exceed |max_halfword|*/
+@!error_line=79, /*width of context lines on terminal error messages*/
+@!half_error_line=50, /*width of first lines of contexts in terminal
+  error messages; should be between 30 and |error_line-15|*/
+@!max_print_line=79, /*width of longest text lines output; should be at least 60*/
+@!stack_size=5000, /*maximum number of simultaneous input sources*/
+@!max_in_open=15, /*maximum number of input files and error insertions that
+  can be going on simultaneously*/
+@!font_max=255, /*maximum internal font number; must not exceed |max_quarterword|
+  and must be at most |font_base+256|*/
+@!font_mem_size=8000000, /*number of words of |font_info| for all fonts*/
+@!param_size=10000, /*maximum number of simultaneous macro parameters*/
+@!nest_size=500, /*maximum number of semantic levels simultaneously active*/
+@!max_strings=500000, /*maximum number of strings; must not exceed |max_halfword|*/
+@!string_vacancies=90000, /*the minimum number of characters that should be
+  available for the user's control sequences and font names,
+  after \TeX's own error messages are stored*/
+@!pool_size=6250000, /*maximum number of characters in strings, including all
+  error messages and help texts, and the names of all fonts and
+  control sequences; must exceed |string_vacancies| by the total
+  length of \TeX's own strings, which is currently about 23000*/
+@!save_size=100000, /*space for saving values outside of current group; must be
+  at most |max_halfword|*/
+@!trie_size=1000000, /*space for hyphenation patterns; should be larger for
+  \.{INITEX} than it is in production versions of \TeX*/
+@!trie_op_size=35111, /*space for ``opcodes'' in the hyphenation patterns*/
+@!dvi_buf_size=16384, /*size of the output buffer; must be a multiple of 8*/
+@!file_name_size=1024, /*file names shouldn't be longer than this*/
+@!xchg_buffer_size=64, /*must be at least 64*/
+   /*size of |eight_bits| buffer for exchange with system routines*/
+@!empty_string=256 /*the empty string follows after 256 characters*/
+
+@ Like the preceding parameters, the following quantities can be changed
+at compile time to extend or reduce \TeX's capacity. But if they are changed,
+it is necessary to rerun the initialization program \.{INITEX}
+ at .INITEX@>
+to generate new tables for the production \TeX\ program.
+One can't simply make helter-skelter changes to the following constants,
+since certain rather complex initialization
+numbers are computed from them. They are defined here using
+\.{WEB} macros, instead of being put into \PASCAL's |const| list, in order to
+emphasize this distinction.
+
+ at d mem_bot 0 /*smallest index in the |mem| array dumped by \.{INITEX};
+  must not be less than |mem_min|*/
+ at d mem_top 5000000 /*largest index in the |mem| array dumped by \.{INITEX};
+  must be substantially larger than |mem_bot|
+  and not greater than |mem_max|*/
+ at d font_base 0 /*smallest internal font number; must not be less
+  than |min_quarterword|*/
+ at d hash_size 45000 /*maximum number of control sequences; it should be at most
+  about |(mem_max-mem_min)/(double)10|*/
+ at d hash_prime 35999 /*a prime number equal to about 85\pct! of |hash_size|*/
+ at d hyph_size 8191 /*another prime; the number of \.{\\hyphenation} exceptions*/
+@^system dependencies@>
+
+@ In case somebody has inadvertently made bad settings of the ``constants,''
+\TeX\ checks them using a global variable called |bad|.
+
+This is the first of many sections of \TeX\ where global variables are
+defined.
+
+@<Glob...@>=
+static int @!bad; /*is some ``constant'' wrong?*/
+
+@ Later on we will say `\ignorespaces|if (mem_max >= max_halfword) bad=14|',
+or something similar. (We can't do that until |max_halfword| has been defined.)
+
+@<Check the ``constant'' values for consistency@>=
+bad=0;
+if ((half_error_line < 30)||(half_error_line > error_line-15)) bad=1;
+if (max_print_line < 60) bad=2;
+if (dvi_buf_size%8!=0) bad=3;
+if (mem_bot+1100 > mem_top) bad=4;
+if (hash_prime > hash_size) bad=5;
+if (max_in_open >= 128) bad=6;
+if (mem_top < 256+11) bad=7; /*we will want |null_list > 255|*/
+
+@ Labels are given symbolic names by the following definitions, so that
+occasional |goto| statements will be meaningful. We insert the label
+`|end|' just before the `\ignorespaces|} |\unskip' of a procedure in
+which we have used the `|goto end|' statement defined below; the label
+`|restart|' is occasionally used at the very beginning of a procedure; and
+the label `|reswitch|' is occasionally used just prior to a |case|
+statement in which some cases change the conditions and we wish to branch
+to the newly applicable case.  Loops that are set up with the |loop|
+construction defined below are commonly exited by going to `|done|' or to
+`|found|' or to `|not_found|', and they are sometimes repeated by going to
+`|resume|'.  If two or more parts of a subroutine start differently but
+end up the same, the shared code may be gathered together at
+`|common_ending|'.
+
+Incidentally, this program never declares a label that isn't actually used,
+because some fussy \PASCAL\ compilers will complain about redundant labels.
+
+@ Here are some macros for common programming idioms.
+
+ at d incr(A) A=A+1 /*increase a variable by unity*/
+ at d decr(A) A=A-1 /*decrease a variable by unity*/
+ at d negate(A) A=-A /*change the sign of a variable*/
+ at d loop @+while (true) @+ /*repeat over and over until a |goto| happens*/
+ at f loop else
+   /*\.{WEB}'s |else| acts like `\ignorespaces|while true do|\unskip'*/
+ at d do_nothing  /*empty statement*/
+ at d empty 0 /*symbolic name for a null constant*/
+
+@* The character set.
+In order to make \TeX\ readily portable to a wide variety of
+computers, all of its input text is converted to an internal eight-bit
+code that includes standard ASCII, the ``American Standard Code for
+Information Interchange.''  This conversion is done immediately when each
+character is read in. Conversely, characters are converted from ASCII to
+the user's external representation just before they are output to a
+text file.
+
+Such an internal code is relevant to users of \TeX\ primarily because it
+governs the positions of characters in the fonts. For example, the
+character `\.A' has ASCII code $65=0101$, and when \TeX\ typesets
+this letter it specifies character number 65 in the current font.
+If that font actually has `\.A' in a different position, \TeX\ doesn't
+know what the real position is; the program that does the actual printing from
+\TeX's device-independent files is responsible for converting from ASCII to
+a particular font encoding.
+@^ASCII code@>
+
+\TeX's internal code also defines the value of constants
+that begin with a reverse apostrophe; and it provides an index to the
+\.{\\catcode}, \.{\\mathcode}, \.{\\uccode}, \.{\\lccode}, and \.{\\delcode}
+tables.
+
+@ Characters of text that have been converted to \TeX's internal form
+are said to be of type |ASCII_code|, which is a subrange of the integers.
+
+@<Types...@>=
+typedef uint8_t ASCII_code; /*eight-bit numbers*/
+
+@ The original \PASCAL\ compiler was designed in the late 60s, when six-bit
+character sets were common, so it did not make provision for lowercase
+letters. Nowadays, of course, we need to deal with both capital and small
+letters in a convenient way, especially in a program for typesetting;
+so the present specification of \TeX\ has been written under the assumption
+that the \PASCAL\ compiler and run-time system permit the use of text files
+with more than 64 distinguishable characters. More precisely, we assume that
+the character set contains at least the letters and symbols associated
+with ASCII codes 040 through 0176; all of these characters are now
+available on most computer terminals.
+
+Since we are dealing with more characters than were present in the first
+\PASCAL\ compilers, we have to decide what to call the associated data
+type. Some \PASCAL s use the original name |unsigned char| for the
+characters in text files, even though there now are more than 64 such
+characters, while other \PASCAL s consider |unsigned char| to be a 64-element
+subrange of a larger data type that has some other name.
+
+In order to accommodate this difference, we shall use the name |text_char|
+to stand for the data type of the characters that are converted to and
+from |ASCII_code| when they are input and output. We shall also assume
+that |text_char| consists of the elements |chr(first_text_char)| through
+|chr(last_text_char)|, inclusive. The following definitions should be
+adjusted if necessary.
+@^system dependencies@>
+
+ at s text_char char
+ at d text_char unsigned char /*the data type of characters in text files*/
+ at d first_text_char 0 /*ordinal number of the smallest element of |text_char|*/
+ at d last_text_char 255 /*ordinal number of the largest element of |text_char|*/
+
+@<Local variables for init...@>=
+int @!i;
+
+@ The \TeX\ processor converts between ASCII code and
+the user's external character set by means of arrays |xord| and |xchr|
+that are analogous to \PASCAL's |ord| and |chr| functions.
+
+@<Glob...@>=
+static ASCII_code @!xord[256];
+   /*specifies conversion of input characters*/
+static text_char @!xchr[256];
+   /*specifies conversion of output characters*/
+
+@ Since we are assuming that our \PASCAL\ system is able to read and
+write the visible characters of standard ASCII (although not
+necessarily using the ASCII codes to represent them), the following
+assignment statements initialize the standard part of the |xchr| array
+properly, without needing any system-dependent changes. On the other
+hand, it is possible to implement \TeX\ with less complete character
+sets, and in such cases it will be necessary to change something here.
+@^system dependencies@>
+
+@<Set init...@>=
+xchr[040]=' ';
+xchr[041]='!';
+xchr[042]='"';
+xchr[043]='#';
+xchr[044]='$';
+xchr[045]='%';
+xchr[046]='&';
+xchr[047]='\'';@/
+xchr[050]='(';
+xchr[051]=')';
+xchr[052]='*';
+xchr[053]='+';
+xchr[054]=',';
+xchr[055]='-';
+xchr[056]='.';
+xchr[057]='/';@/
+xchr[060]='0';
+xchr[061]='1';
+xchr[062]='2';
+xchr[063]='3';
+xchr[064]='4';
+xchr[065]='5';
+xchr[066]='6';
+xchr[067]='7';@/
+xchr[070]='8';
+xchr[071]='9';
+xchr[072]=':';
+xchr[073]=';';
+xchr[074]='<';
+xchr[075]='=';
+xchr[076]='>';
+xchr[077]='?';@/
+xchr[0100]='@@';
+xchr[0101]='A';
+xchr[0102]='B';
+xchr[0103]='C';
+xchr[0104]='D';
+xchr[0105]='E';
+xchr[0106]='F';
+xchr[0107]='G';@/
+xchr[0110]='H';
+xchr[0111]='I';
+xchr[0112]='J';
+xchr[0113]='K';
+xchr[0114]='L';
+xchr[0115]='M';
+xchr[0116]='N';
+xchr[0117]='O';@/
+xchr[0120]='P';
+xchr[0121]='Q';
+xchr[0122]='R';
+xchr[0123]='S';
+xchr[0124]='T';
+xchr[0125]='U';
+xchr[0126]='V';
+xchr[0127]='W';@/
+xchr[0130]='X';
+xchr[0131]='Y';
+xchr[0132]='Z';
+xchr[0133]='[';
+xchr[0134]='\\';
+xchr[0135]=']';
+xchr[0136]='^';
+xchr[0137]='_';@/
+xchr[0140]='`';
+xchr[0141]='a';
+xchr[0142]='b';
+xchr[0143]='c';
+xchr[0144]='d';
+xchr[0145]='e';
+xchr[0146]='f';
+xchr[0147]='g';@/
+xchr[0150]='h';
+xchr[0151]='i';
+xchr[0152]='j';
+xchr[0153]='k';
+xchr[0154]='l';
+xchr[0155]='m';
+xchr[0156]='n';
+xchr[0157]='o';@/
+xchr[0160]='p';
+xchr[0161]='q';
+xchr[0162]='r';
+xchr[0163]='s';
+xchr[0164]='t';
+xchr[0165]='u';
+xchr[0166]='v';
+xchr[0167]='w';@/
+xchr[0170]='x';
+xchr[0171]='y';
+xchr[0172]='z';
+xchr[0173]='{';
+xchr[0174]='|';
+xchr[0175]='}';
+xchr[0176]='~';@/
+
+@ Some of the ASCII codes without visible characters have been given symbolic
+names in this program because they are used with a special meaning.
+
+ at d null_code 00 /*ASCII code that might disappear*/
+ at d carriage_return 015 /*ASCII code used at end of line*/
+ at d invalid_code 0177 /*ASCII code that many systems prohibit in text files*/
+
+@ The ASCII code is ``standard'' only to a certain extent, since many
+computer installations have found it advantageous to have ready access
+to more than 94 printing characters. Appendix~C of {\sl The \TeX book\/}
+gives a complete specification of the intended correspondence between
+characters and \TeX's internal representation.
+@:TeXbook}{\sl The \TeX book@>
+
+If \TeX\ is being used
+on a garden-variety \PASCAL\ for which only standard ASCII
+codes will appear in the input and output files, it doesn't really matter
+what codes are specified in |xchr[0 dotdot 037]|, but the safest policy is to
+blank everything out by using the code shown below.
+
+However, other settings of |xchr| will make \TeX\ more friendly on
+computers that have an extended character set, so that users can type things
+like `\.^^Z' instead of `\.{\\ne}'. People with extended character sets can
+assign codes arbitrarily, giving an |xchr| equivalent to whatever
+characters the users of \TeX\ are allowed to have in their input files.
+It is best to make the codes correspond to the intended interpretations as
+shown in Appendix~C whenever possible; but this is not necessary. For
+example, in countries with an alphabet of more than 26 letters, it is
+usually best to map the additional letters into codes less than~040.
+To get the most ``permissive'' character set, change |' '| on the
+right of these assignment statements to |chr(i)|.
+@^character set dependencies@>
+@^system dependencies@>
+
+@<Set init...@>=
+for (i=0; i<=037; i++) xchr[i]=chr(i); /* k\TeX\ */
+for (i=0177; i<=0377; i++) xchr[i]=chr(i); /* k\TeX\ */
+
+@ The following system-independent code makes the |xord| array contain a
+suitable inverse to the information in |xchr|. Note that if |xchr[i]==xchr[j]|
+where |i < j < 0177|, the value of |xord[xchr[i]]| will turn out to be
+|j| or more; hence, standard ASCII code numbers will be used instead of
+codes below 040 in case there is a coincidence.
+
+@<Set init...@>=
+for (i=first_text_char; i<=last_text_char; i++) xord[chr(i)]=invalid_code;
+for (i=0200; i<=0377; i++) xord[xchr[i]]=i;
+for (i=0; i<=0176; i++) xord[xchr[i]]=i;
+
+@* Input and output.
+The bane of portability is the fact that different operating systems treat
+input and output quite differently, perhaps because computer scientists
+have not given sufficient attention to this problem. People have felt somehow
+that input and output are not part of ``real'' programming. Well, it is true
+that some kinds of programming are more fun than others. With existing
+input/output conventions being so diverse and so messy, the only sources of
+joy in such parts of the code are the rare occasions when one can find a
+way to make the program a little less bad than it might have been. We have
+two choices, either to attack I/O now and get it over with, or to postpone
+I/O until near the end. Neither prospect is very attractive, so let's
+get it over with.
+
+The basic operations we need to do are (1)~inputting and outputting of
+text, to or from a file or the user's terminal; (2)~inputting and
+outputting of eight-bit bytes, to or from a file; (3)~instructing the
+operating system to initiate (``open'') or to terminate (``close'') input or
+output from a specified file; (4)~testing whether the end of an input
+file has been reached.
+
+\TeX\ needs to deal with two kinds of files.
+We shall use the term |alpha_file| for a file that contains textual data,
+and the term |byte_file| for a file that contains eight-bit binary information.
+These two types turn out to be the same on many computers, but
+sometimes there is a significant distinction, so we shall be careful to
+distinguish between them. Standard protocols for transferring
+such files from computer to computer, via high-speed networks, are
+now becoming available to more and more communities of users.
+
+The program actually makes use also of a third kind of file, called a
+|word_file|, when dumping and reloading base information for its own
+initialization.  We shall define a word file later; but it will be possible
+for us to specify simple operations on word files before they are defined.
+
+@<Types...@>=
+typedef uint8_t eight_bits; /*unsigned one-byte quantity*/
+typedef struct {@+FILE *f;@+text_char@,d;@+} alpha_file; /*files that contain textual data*/
+typedef struct {@+FILE *f;@+eight_bits@,d;@+} byte_file; /*files that contain binary data*/
+
+@ Most of what we need to do with respect to input and output can be handled
+by the I/O facilities that are standard in \PASCAL, i.e., the routines
+called |get|, |put|, |eof|, and so on. But
+standard \PASCAL\ does not allow file variables to be associated with file
+names that are determined at run time, so it cannot be used to implement
+\TeX; some sort of extension to \PASCAL's ordinary |reset| and |rewrite|
+is crucial for our purposes. We shall assume that |name_of_file| is a variable
+of an appropriate type such that the \PASCAL\ run-time system being used to
+implement \TeX\ can open a file whose external name is specified by
+|name_of_file|.
+@^system dependencies@>
+
+@<Glob...@>=
+static unsigned char @!name_of_file0[file_name_size+1]={0}, *const @!name_of_file = @!name_of_file0-1;@;@/
+   /*on some systems this may be a \&{record} variable*/
+static int @!name_length;@/ /*this many characters are actually
+  relevant in |name_of_file| (the rest are blank)*/
+
+@ k\TeX\ uses the {\tt kpathsearch} library to implement access to files.
+So most of the code to find and open files is contained in two functions,
+|open_in| and |open_out| defined later.
+\TeX's file-opening functions do not to issue their own
+error messages if something goes wrong. If a file identified by
+|name_of_file| cannot be found,
+or if such a file cannot be opened for some other reason
+(e.g., someone may already be trying to write the same file)
+\TeX's file-opening functions return |false|.
+This allows \TeX\ to undertake appropriate corrective action.
+@^system dependencies@>
+
+ at p
+static FILE*open_in(char*filename,kpse_file_format_type t,const char*rwb);
+static bool a_open_in(alpha_file *f) /*open a text file for input*/
+{@+f->f= open_in((char *)name_of_file+1,kpse_tex_format,"r");
+   if (f->f!=NULL) get(*f);
+   return f->f!=NULL && ferror(f->f)==0;
+}
+
+static bool b_open_in(byte_file *f)   /*open a binary file for input*/
+{@+f->f= kpse_open_file((char *)name_of_file+1,kpse_tfm_format);
+   if (f->f!=NULL) get(*f);
+   return f->f!=NULL && ferror(f->f)==0;
+}
+
+static bool w_open_in(word_file *f)   /*open a word file for input*/
+{@+
+  f->f=NULL;
+  if (name_of_file[1]!=0)
+    f->f= open_in((char*)name_of_file+1,kpse_fmt_format,"rb");
+  if (f->f!=NULL) get(*f);
+  return f->f!=NULL && ferror(f->f)==0;
+}
+
+static FILE *open_out(const char *file_name, const char *file_mode);
+static bool a_open_out(alpha_file *f)  /*open a text file for output*/
+{@+f->f=open_out((char*)name_of_file+1,"w");
+  return f->f!=NULL && ferror(f->f)==0;@+
+}
+
+static bool b_open_out(byte_file *f)  /*open a binary file for output*/
+{@+f->f=open_out((char *)name_of_file+1,"wb");
+return f->f!=NULL && ferror(f->f)==0;@+
+}
+
+#ifdef @!INIT
+static bool w_open_out(word_file *f)  /*open a word file for output*/
+{@+f->f=open_out((char *)name_of_file+1,"wb");
+   return f->f!=NULL && ferror(f->f)==0;@+
+}
+#endif
+
+@ Files can be closed with the \ph\ routine `|pascal_close(f)|', which
+@:PASCAL H}{\ph@>
+@^system dependencies@>
+should be used when all input or output with respect to |f| has been completed.
+This makes |f| available to be opened again, if desired; and if |f| was used for
+output, the |pascal_close| operation makes the corresponding external file appear
+on the user's area, ready to be read.
+
+These procedures should not generate error messages if a file is
+being closed before it has been successfully opened.
+
+ at p static void a_close(alpha_file *f) /*close a text file*/
+{@+pascal_close((*f));
+}
+@#
+static void b_close(byte_file *f) /*close a binary file*/
+{@+pascal_close((*f));
+}
+@#
+static void w_close(word_file *f) /*close a word file*/
+{@+pascal_close((*f));
+}
+
+@ Binary input and output are done with \PASCAL's ordinary |get| and |put|
+procedures, so we don't have to make any other special arrangements for
+binary~I/O. Text output is also easy to do with standard \PASCAL\ routines.
+The treatment of text input is more difficult, however, because
+of the necessary translation to |ASCII_code| values.
+\TeX's conventions should be efficient, and they should
+blend nicely with the user's operating environment.
+
+@ Input from text files is read one line at a time, using a routine called
+|input_ln|. This function is defined in terms of global variables called
+|buffer|, |first|, and |last| that will be described in detail later; for
+now, it suffices for us to know that |buffer| is an array of |ASCII_code|
+values, and that |first| and |last| are indices into this array
+representing the beginning and ending of a line of text.
+
+@<Glob...@>=
+static ASCII_code @!buffer[buf_size+1]; /*lines of characters being read*/
+static int @!first; /*the first unused position in |buffer|*/
+static int @!last; /*end of the line just input to |buffer|*/
+static int @!max_buf_stack; /*largest index used in |buffer|*/
+
+@ The |input_ln| function brings the next line of input from the specified
+file into available positions of the buffer array and returns the value
+|true|, unless the file has already been entirely read, in which case it
+returns |false| and sets |last=first|.  In general, the |ASCII_code|
+numbers that represent the next line of the file are input into
+|buffer[first]|, |buffer[first+1]|, \dots, |buffer[last-1]|; and the
+global variable |last| is set equal to |first| plus the length of the
+line. Trailing blanks are removed from the line; thus, either |last==first|
+(in which case the line was entirely blank) or |buffer[last-1]!=' '|.
+
+An overflow error is given, however, if the normal actions of |input_ln|
+would make |last >= buf_size|; this is done so that other parts of \TeX\
+can safely look at the contents of |buffer[last+1]| without overstepping
+the bounds of the |buffer| array. Upon entry to |input_ln|, the condition
+|first < buf_size| will always hold, so that there is always room for an
+``empty'' line.
+
+The variable |max_buf_stack|, which is used to keep track of how large
+the |buf_size| parameter must be to accommodate the present job, is
+also kept up to date by |input_ln|.
+
+If the |bypass_eoln| parameter is |true|, |input_ln| will do a |get|
+before looking at the first character of the line; this skips over
+an |eoln| that was in |f.d|. The procedure does not do a |get| when it
+reaches the end of the line; therefore it can be used to acquire input
+from the user's terminal as well as from ordinary text files.
+
+Standard \PASCAL\ says that a file should have |eoln| immediately
+before |eof|, but \TeX\ needs only a weaker restriction: If |eof|
+occurs in the middle of a line, the system function |eoln| should return
+a |true| result (even though |f.d| will be undefined).
+
+Since the inner loop of |input_ln| is part of \TeX's ``inner loop''---each
+character of input comes in at this place---it is wise to reduce system
+overhead by making use of special routines that read in an entire array
+of characters at once, if such routines are available. The following
+code uses standard \PASCAL\ to illustrate what needs to be done, but
+finer tuning is often possible at well-developed \PASCAL\ sites.
+@^inner loop@>
+
+ at p static bool input_ln(alpha_file *f, bool @!bypass_eoln)
+   /*inputs the next line or returns |false|*/
+{@+int last_nonblank; /*|last| with trailing blanks removed*/
+if (bypass_eoln) if (!eof((*f))) get((*f));
+   /*input the first character of the line into |f.d|*/
+last=first; /*cf.\ Matthew 19\thinspace:\thinspace30*/
+if (eof((*f))) return false;
+else{@+last_nonblank=first;
+  while (!eoln((*f)))
+    {@+if (last >= max_buf_stack)
+      {@+max_buf_stack=last+1;
+      if (max_buf_stack==buf_size)
+        @<Report overflow of the input buffer, and abort@>;
+      }
+    buffer[last]=xord[(*f).d];get((*f));incr(last);
+    if (buffer[last-1]!=' ') last_nonblank=last;
+    }
+  last=last_nonblank;return true;
+  }
+}
+
+@ The user's terminal acts essentially like other files of text, except
+that it is used both for input and for output. When the terminal is
+considered an input file, the file variable is called |term_in|, and when it
+is considered an output file the file variable is |term_out|.
+@^system dependencies@>
+
+@<Glob...@>=
+static alpha_file @!term_in; /*the terminal as an input file*/
+static alpha_file @!term_out; /*the terminal as an output file*/
+
+@ Here is how to open the terminal files
+in \ph. The `\.{/I}' switch suppresses the first |get|.
+@:PASCAL H}{\ph@>
+@^system dependencies@>
+
+ at d t_open_in term_in.f=stdin /*open the terminal for text input*/
+ at d t_open_out   term_out.f=stdout /*open the terminal for text output*/
+
+@ Sometimes it is necessary to synchronize the input/output mixture that
+happens on the user's terminal, and three system-dependent
+procedures are used for this
+purpose. The first of these, |update_terminal|, is called when we want
+to make sure that everything we have output to the terminal so far has
+actually left the computer's internal buffers and been sent.
+The second, |clear_terminal|, is called when we wish to cancel any
+input that the user may have typed ahead (since we are about to
+issue an unexpected error message). The third, |wake_up_terminal|,
+is supposed to revive the terminal if the user has disabled it by
+some instruction to the operating system.  The following macros show how
+these operations can be specified in \ph:
+@:PASCAL H}{\ph@>
+@^system dependencies@>
+
+ at d update_terminal fflush(term_out.f) /*empty the terminal output buffer*/
+ at d clear_terminal fflush(term_in.f) /*clear the terminal input buffer*/
+ at d wake_up_terminal do_nothing /*cancel the user's cancellation of output*/
+
+@ We need a special routine to read the first line of \TeX\ input from
+the user's terminal. This line is different because it is read before we
+have opened the transcript file; there is sort of a ``chicken and
+egg'' problem here. If the user types `\.{\\input paper}' on the first
+line, or if some macro invoked by that line does such an \.{\\input},
+the transcript file will be named `\.{paper.log}'; but if no \.{\\input}
+commands are performed during the first line of terminal input, the transcript
+file will acquire its default name `\.{texput.log}'. (The transcript file
+will not contain error messages generated by the first line before the
+first \.{\\input} command.)
+ at .texput@>
+
+The first line is even more special if we are lucky enough to have an operating
+system that treats \TeX\ differently from a run-of-the-mill \PASCAL\ object
+program. It's nice to let the user start running a \TeX\ job by typing
+a command line like `\.{tex paper}'; in such a case, \TeX\ will operate
+as if the first line of input were `\.{paper}', i.e., the first line will
+consist of the remainder of the command line, after the part that invoked
+\TeX.
+
+The first line is special also because it may be read before \TeX\ has
+input a format file. In such cases, normal error messages cannot yet
+be given. The following code uses concepts that will be explained later.
+(If the \PASCAL\ compiler does not support non-local |@!goto|\unskip, the
+@^system dependencies@>
+statement `|goto exit(0)|' should be replaced by something that
+quietly terminates the program.)
+
+@<Report overflow of the input buffer, and abort@>=
+if (format_ident==0)
+  {@+write_ln(term_out,"Buffer size exceeded!");exit(0);
+ at .Buffer size exceeded@>
+  }
+else{@+cur_input.loc_field=first;cur_input.limit_field=last-1;
+  overflow("buffer size", buf_size);
+@:TeX capacity exceeded buffer size}{\quad buffer size@>
+  }
+
+@ Different systems have different ways to get started. But regardless of
+what conventions are adopted, the routine that initializes the terminal
+should satisfy the following specifications:
+
+\yskip\textindent{1)}It should open file |term_in| for input from the
+  terminal. (The file |term_out| will already be open for output to the
+  terminal.)
+
+\textindent{2)}If the user has given a command line, this line should be
+  considered the first line of terminal input. Otherwise the
+  user should be prompted with `\.{**}', and the first line of input
+  should be whatever is typed in response.
+
+\textindent{3)}The first line of input, which might or might not be a
+  command line, should appear in locations |first| to |last-1| of the
+  |buffer| array.
+
+\textindent{4)}The global variable |loc| should be set so that the
+  character to be read next by \TeX\ is in |buffer[loc]|. This
+  character should not be blank, and we should have |loc < last|.
+
+\yskip\noindent(It may be necessary to prompt the user several times
+before a non-blank line comes in. The prompt is `\.{**}' instead of the
+later `\.*' because the meaning is slightly different: `\.{\\input}' need
+not be typed immediately after~`\.{**}'.)
+
+ at d loc cur_input.loc_field /*location of first unread character in |buffer|*/
+
+@ The following program calls |input_command_line|
+to retrieve a possible command line.
+@^system dependencies@>
+
+ at p static bool init_terminal(void) /*gets the terminal input started*/
+{@+
+t_open_in;
+if (input_command_line()) return true; /* k\TeX\ */
+loop at +{@+wake_up_terminal;pascal_write(term_out,"**");update_terminal;
+ at .**@>
+  if (!input_ln(&term_in, true))  /*this shouldn't happen*/
+    {@+write_ln(term_out);
+    pascal_write(term_out,"! End of file on the terminal... why?");
+ at .End of file on the terminal@>
+    return false;
+    }
+  loc=first;
+  while ((loc < last)&&(buffer[loc]==' ')) incr(loc);
+  if (loc < last)
+    {@+return true;
+     /*return unless the line was all blank*/
+    }
+  write_ln(term_out,"Please type the name of your input file.");
+  }
+}
+
+@* String handling.
+Control sequence names and diagnostic messages are variable-length strings
+of eight-bit characters. Since \PASCAL\ does not have a well-developed string
+mechanism, \TeX\ does all of its string processing by homegrown methods.
+
+Elaborate facilities for dynamic strings are not needed, so all of the
+necessary operations can be handled with a simple data structure.
+The array |str_pool| contains all of the (eight-bit) ASCII codes in all
+of the strings, and the array |str_start| contains indices of the starting
+points of each string. Strings are referred to by integer numbers, so that
+string number |s| comprises the characters |str_pool[j]| for
+|str_start[s] <= j < str_start[s+1]|. Additional integer variables
+|pool_ptr| and |str_ptr| indicate the number of entries used so far
+in |str_pool| and |str_start|, respectively; locations
+|str_pool[pool_ptr]| and |str_start[str_ptr]| are
+ready for the next string to be allocated.
+
+String numbers 0 to 255 are reserved for strings that correspond to single
+ASCII characters. This is in accordance with the conventions of \.{WEB},
+ at .WEB@>
+which converts single-character strings into the ASCII code number of the
+single character involved, while it converts other strings into integers
+and builds a string pool file. Thus, when the string constant \.{"."} appears
+in the program below, \.{WEB} converts it into the integer 46, which is the
+ASCII code for a period, while \.{WEB} will convert a string like \.{"hello"}
+into some integer greater than~255. String number 46 will presumably be the
+single character `\..'; but some ASCII codes have no standard visible
+representation, and \TeX\ sometimes needs to be able to print an arbitrary
+ASCII character, so the first 256 strings are used to specify exactly what
+should be printed for each of the 256 possibilities.
+
+Elements of the |str_pool| array must be ASCII codes that can actually
+be printed; i.e., they must have an |xchr| equivalent in the local
+character set. (This restriction applies only to preloaded strings,
+not to those generated dynamically by the user.)
+
+Some \PASCAL\ compilers won't pack integers into a single byte unless the
+integers lie in the range |-128 dotdot 127|. To accommodate such systems
+we access the string pool only via macros that can easily be redefined.
+@^system dependencies@>
+
+ at d si(A) A /*convert from |ASCII_code| to |packed_ASCII_code|*/
+ at d so(A) A /*convert from |packed_ASCII_code| to |ASCII_code|*/
+
+@<Types...@>=
+typedef int32_t pool_pointer; /*for variables that point into |str_pool|*/
+typedef int32_t str_number; /*for variables that point into |str_start|*/
+typedef uint8_t packed_ASCII_code; /*elements of |str_pool| array*/
+
+@ @<Glob...@>=
+static packed_ASCII_code @!str_pool[pool_size+1]; /*the characters*/
+static pool_pointer @!str_start[max_strings+1]; /*the starting pointers*/
+static pool_pointer @!pool_ptr; /*first unused position in |str_pool|*/
+static str_number @!str_ptr; /*number of the current string being created*/
+static pool_pointer @!init_pool_ptr; /*the starting value of |pool_ptr|*/
+static str_number @!init_str_ptr; /*the starting value of |str_ptr|*/
+
+@ Several of the elementary string operations are performed using \.{WEB}
+macros instead of \PASCAL\ procedures, because many of the
+operations are done quite frequently and we want to avoid the
+overhead of procedure calls. For example, here is
+a simple macro that computes the length of a string.
+ at .WEB@>
+
+ at d length(A) (str_start[A+1]-str_start[A]) /*the number of characters
+  in string number \#*/
+
+@ The length of the current string is called |cur_length|:
+
+ at d cur_length (pool_ptr-str_start[str_ptr])
+
+@ Strings are created by appending character codes to |str_pool|.
+The |append_char| macro, defined here, does not check to see if the
+value of |pool_ptr| has gotten too high; this test is supposed to be
+made before |append_char| is used. There is also a |flush_char|
+macro, which erases the last character appended.
+
+To test if there is room to append |l| more characters to |str_pool|,
+we shall write |str_room(l)|, which aborts \TeX\ and gives an
+apologetic error message if there isn't enough room.
+
+ at d append_char(A)  /*put |ASCII_code| \# at the end of |str_pool|*/
+{@+str_pool[pool_ptr]=si(A);incr(pool_ptr);
+}
+ at d flush_char decr(pool_ptr) /*forget the last character in the pool*/
+ at d str_room(A)  /*make sure that the pool hasn't overflowed*/
+  {@+if (pool_ptr+A > pool_size)
+  overflow("pool size", pool_size-init_pool_ptr);
+@:TeX capacity exceeded pool size}{\quad pool size@>
+  }
+
+@ Once a sequence of characters has been appended to |str_pool|, it
+officially becomes a string when the function |make_string| is called.
+This function returns the identification number of the new string as its
+value.
+
+ at p static str_number make_string(void) /*current string enters the pool*/
+{@+if (str_ptr==max_strings)
+  overflow("number of strings", max_strings-init_str_ptr);
+@:TeX capacity exceeded number of strings}{\quad number of strings@>
+incr(str_ptr);str_start[str_ptr]=pool_ptr;
+return str_ptr-1;
+}
+
+@ To destroy the most recently made string, we say |flush_string|.
+
+ at d flush_string {@+decr(str_ptr);pool_ptr=str_start[str_ptr];
+  }
+
+@ The following subroutine compares string |s| with another string of the
+same length that appears in |buffer| starting at position |k|;
+the result is |true| if and only if the strings are equal.
+Empirical tests indicate that |str_eq_buf| is used in such a way that
+it tends to return |true| about 80 percent of the time.
+
+ at p static bool str_eq_buf(str_number @!s, int @!k)
+   /*test equality of strings*/
+{@+ /*loop exit*/
+pool_pointer j; /*running index*/
+bool @!result; /*result of comparison*/
+j=str_start[s];
+while (j < str_start[s+1])
+  {@+if (so(str_pool[j])!=buffer[k])
+    {@+result=false;goto not_found;
+    }
+  incr(j);incr(k);
+  }
+result=true;
+not_found: return result;
+}
+
+@ Here is a similar routine, but it compares two strings in the string pool,
+and it does not assume that they have the same length.
+
+ at p static bool strn_eq_str(str_number @!s, str_number @!t)
+   /*test equality of strings*/
+{@+ /*loop exit*/
+pool_pointer j, @!k; /*running indices*/
+bool @!result; /*result of comparison*/
+result=false;
+if (length(s)!=length(t)) goto not_found;
+j=str_start[s];k=str_start[t];
+while (j < str_start[s+1])
+  {@+if (str_pool[j]!=str_pool[k]) goto not_found;
+  incr(j);incr(k);
+  }
+result=true;
+not_found: return result;
+}
+ at t\4@>@<Declare \Prote\ procedures for strings@>@;
+
+static bool str_eq_str(str_number @!s, char *@!t)
+   /*test equality of strings*/
+{@+int j, @!k; /*running indices*/
+if (length(s)!=(int)strlen(t)) return false;
+j=str_start[s];k=0;
+while (j < str_start[s+1])
+  if (str_pool[j++]!=t[k++]) return false;
+return true;
+}
+
+@ The initial values of |str_pool|, |str_start|, |pool_ptr|,
+and |str_ptr| are computed by the \.{INITEX} program, based in part
+on the information that \.{WEB} has output while processing \TeX.
+ at .INITEX@>
+@^string pool@>
+
+ at p
+static void get_strings_started(void) /*initializes the string pool*/
+{@+
+int k, @!l; /*small indices or counters*/
+pool_ptr=0;str_ptr=0;str_start[0]=0;
+@<Make the first 256 strings@>;
+@<Add the empty string to the string pool@>;
+}
+
+@ @d app_lc_hex(A) l=A;
+  if (l < 10) append_char(l+'0')@;@+else append_char(l-10+'a')
+
+@<Make the first 256...@>=
+for (k=0; k<=255; k++)
+  {@+if ((@<Character |k| cannot be printed@>))
+    {@+append_char('^');append_char('^');
+    if (k < 0100) append_char(k+0100)@;
+    else if (k < 0200) append_char(k-0100)@;
+    else{@+app_lc_hex(k/16);app_lc_hex(k%16);
+      }
+    }
+  else append_char(k);
+  make_string();
+  }
+
+@ The first 128 strings will contain 95 standard ASCII characters, and the
+other 33 characters will be printed in three-symbol form like `\.{\^\^A}'
+unless a system-dependent change is made here. Installations that have
+an extended character set, where for example |xchr[032]==@t\.{\'^^Z\'}@>|,
+would like string 032 to be the single character 032 instead of the
+three characters 0136, 0136, 0132 (\.{\^\^Z}). On the other hand,
+even people with an extended character set will want to represent string
+015 by \.{\^\^M}, since 015 is |carriage_return|; the idea is to
+produce visible strings instead of tabs or line-feeds or carriage-returns
+or bell-rings or characters that are treated anomalously in text files.
+
+Unprintable characters of codes 128--255 are, similarly, rendered
+\.{\^\^80}--\.{\^\^ff}.
+
+The boolean expression defined here should be |true| unless \TeX\
+internal code number~|k| corresponds to a non-troublesome visible
+symbol in the local character set.  An appropriate formula for the
+extended character set recommended in {\sl The \TeX book\/} would, for
+example, be `|k in[0, 010 dotdot 012, 014, 015, 033, 0177 dotdot 0377]|'.
+If character |k| cannot be printed, and |k < 0200|, then character |k+0100| or
+|k-0100| must be printable; moreover, ASCII codes |[041 dotdot 046,
+060 dotdot 071, 0136, 0141 dotdot 0146, 0160 dotdot 0171]| must be printable.
+Thus, at least 80 printable characters are needed.
+@:TeXbook}{\sl The \TeX book@>
+@^character set dependencies@>
+@^system dependencies@>
+
+@<Character |k| cannot be printed@>=
+  (k < ' ')||(k > '~')
+
+@ The |pool_file| variable is no longer needed and has been removed.
+
+@ Instead of reading the other strings from the \.{TEX.POOL} file,
+it is sufficient here to add the empty string.
+@<Add the empty string to the string pool@>=
+make_string();
+
+@ Without a string pool file there is no need for a pool check sum either.
+But this is a convenient place to define the function |s_no| that will
+add literal strings to the string pool at runtime, thereby obtaining their
+string number.
+
+ at p static int s_no(const char *str)
+{@+
+  if (str[0]==0) return empty_string;
+  if (str[1]==0) return str[0];
+  str_room(strlen(str));
+  while (*str!=0) append_char(*str++);
+  return make_string();
+}
+
+@* On-line and off-line printing.
+Messages that are sent to a user's terminal and to the transcript-log file
+are produced by several `|print|' procedures. These procedures will
+direct their output to a variety of places, based on the setting of
+the global variable |selector|, which has the following possible
+values:
+
+\yskip
+\hang |term_and_log|, the normal setting, prints on the terminal and on the
+  transcript file.
+
+\hang |log_only|, prints only on the transcript file.
+
+\hang |term_only|, prints only on the terminal.
+
+\hang |no_print|, doesn't print at all. This is used only in rare cases
+  before the transcript file is open.
+
+\hang |pseudo|, puts output into a cyclic buffer that is used
+  by the |show_context| routine; when we get to that routine we shall discuss
+  the reasoning behind this curious mode.
+
+\hang |new_string|, appends the output to the current string in the
+  string pool.
+
+\hang 0 to 15, prints on one of the sixteen files for \.{\\write} output.
+
+\yskip
+\noindent The symbolic names `|term_and_log|', etc., have been assigned
+numeric codes that satisfy the convenient relations |no_print+1==term_only|,
+|no_print+2==log_only|, |term_only+2==log_only+1==term_and_log|.
+
+Three additional global variables, |tally| and |term_offset| and
+|file_offset|, record the number of characters that have been printed
+since they were most recently cleared to zero. We use |tally| to record
+the length of (possibly very long) stretches of printing; |term_offset|
+and |file_offset|, on the other hand, keep track of how many characters
+have appeared so far on the current line that has been output to the
+terminal or to the transcript file, respectively.
+
+ at d no_print 16 /*|selector| setting that makes data disappear*/
+ at d term_only 17 /*printing is destined for the terminal only*/
+ at d log_only 18 /*printing is destined for the transcript file only*/
+ at d term_and_log 19 /*normal |selector| setting*/
+ at d pseudo 20 /*special |selector| setting for |show_context|*/
+ at d new_string 21 /*printing is deflected to the string pool*/
+ at d max_selector 21 /*highest selector setting*/
+
+@<Glob...@>=
+static alpha_file @!log_file; /*transcript of \TeX\ session*/
+static int @!selector; /*where to print a message*/
+static int8_t @!dig[23]; /*digits in a number being output*/
+static int @!tally; /*the number of characters recently printed*/
+static int @!term_offset;
+   /*the number of characters on the current terminal line*/
+static int @!file_offset;
+   /*the number of characters on the current file line*/
+static ASCII_code @!trick_buf[error_line+1]; /*circular buffer for
+  pseudoprinting*/
+static int @!trick_count; /*threshold for pseudoprinting, explained later*/
+static int @!first_count; /*another variable for pseudoprinting*/
+
+@ @<Initialize the output routines@>=
+selector=term_only;tally=0;term_offset=0;file_offset=0;
+
+@ Macro abbreviations for output to the terminal and to the log file are
+defined here for convenience. Some systems need special conventions
+for terminal output, and it is possible to adhere to those conventions
+by changing |wterm|, |wterm_ln|, and |wterm_cr| in this section.
+@^system dependencies@>
+
+@<Basic printing procedures@>=
+#define put(F)    @[fwrite(&((F).d),sizeof((F).d),1,(F).f)@]
+#define get(F)    @[fread(&((F).d),sizeof((F).d),1,(F).f)@]
+
+#define pascal_close(F)    @[fclose((F).f)@]
+#define eof(F)    @[feof((F).f)@]
+#define eoln(F)    @[((F).d=='\n'||eof(F))@]
+#define erstat(F)   @[((F).f==NULL?-1:ferror((F).f))@]
+
+#define pascal_read(F,X) @[((X)=(F).d,get(F))@]
+#define read_ln(F)  @[do get(F); while (!eoln(F))@]
+
+#define pascal_write(F, FMT,...)    @[fprintf(F.f,FMT,## __VA_ARGS__)@]
+#define write_ln(F,...)    @[pascal_write(F,__VA_ARGS__"\n")@]
+
+#define wterm(FMT,...) @[pascal_write(term_out,FMT, ## __VA_ARGS__)@]
+#define wterm_ln(FMT,...) @[wterm(FMT "\n", ## __VA_ARGS__)@]
+#define wterm_cr         @[pascal_write(term_out,"\n")@]
+#define wlog(FMT, ...) @[pascal_write(log_file,FMT, ## __VA_ARGS__)@]
+#define wlog_ln(FMT, ...)   @[wlog(FMT "\n", ## __VA_ARGS__)@]
+#define wlog_cr         @[pascal_write(log_file,"\n")@]
+
+@ To end a line of text output, we call |print_ln|.
+
+@<Basic print...@>=
+static void print_ln(void) /*prints an end-of-line*/
+{@+switch (selector) {
+case term_and_log: {@+wterm_cr;wlog_cr;
+  term_offset=0;file_offset=0;
+  } @+break;
+case log_only: {@+wlog_cr;file_offset=0;
+  } @+break;
+case term_only: {@+wterm_cr;term_offset=0;
+  } @+break;
+case no_print: case pseudo: case new_string: do_nothing;@+break;
+default:write_ln(write_file[selector]);
+} @/
+}  /*|tally| is not affected*/
+
+@ The |print_char| procedure sends one character to the desired destination,
+using the |xchr| array to map it into an external character compatible with
+|input_ln|. All printing comes through |print_ln| or |print_char|.
+
+@<Basic printing...@>=
+static void print_char(ASCII_code @!s) /*prints a single character*/
+{@+
+if (@<Character |s| is the current new-line character@>)
+ if (selector < pseudo)
+  {@+print_ln();return;
+  }
+switch (selector) {
+case term_and_log: {@+wterm("%c",xchr[s]);wlog("%c",xchr[s]);
+  incr(term_offset);incr(file_offset);
+  if (term_offset==max_print_line)
+    {@+wterm_cr;term_offset=0;
+    }
+  if (file_offset==max_print_line)
+    {@+wlog_cr;file_offset=0;
+    }
+  } @+break;
+case log_only: {@+wlog("%c",xchr[s]);incr(file_offset);
+  if (file_offset==max_print_line) print_ln();
+  } @+break;
+case term_only: {@+wterm("%c",xchr[s]);incr(term_offset);
+  if (term_offset==max_print_line) print_ln();
+  } @+break;
+case no_print: do_nothing;@+break;
+case pseudo: if (tally < trick_count) trick_buf[tally%error_line]=s;@+break;
+case new_string: {@+if (pool_ptr < pool_size) append_char(s);
+  } @+break; /*we drop characters if the string space is full*/
+default:pascal_write(write_file[selector],"%c", xchr[s]);
+} @/
+incr(tally);
+}
+
+@ An entire string is output by calling |print|. Note that if we are outputting
+the single standard ASCII character \.c, we could call |print('c')|, since
+|'c'==99| is the number of a single-character string, as explained above. But
+|print_char('c')| is quicker, so \TeX\ goes directly to the |print_char|
+routine when it knows that this is safe. (The present implementation
+assumes that it is always safe to print a visible ASCII character.)
+@^system dependencies@>
+
+@<Basic print...@>=
+static void print(char *s) /* the simple version */
+{ while (*s!=0) print_char(*s++);@+
+}
+
+static void printn(int @!s) /*prints string |s|*/
+{@+
+pool_pointer j; /*current character code position*/
+int @!nl; /*new-line character to restore*/
+if (s >= str_ptr) {print("???"); return;}/*this can't happen*/
+ at .???@>
+else if (s < 256)
+  if (s < 0) { print("???");return; } /*can't happen*/
+  else{@+if (selector > pseudo)
+      {@+print_char(s);return; /*internal strings are not expanded*/
+      }
+    if ((@<Character |s| is the current new-line character@>))
+      if (selector < pseudo)
+        {@+print_ln();return;
+        }
+    nl=new_line_char;new_line_char=-1;
+       /*temporarily disable new-line character*/
+    j=str_start[s];
+    while (j < str_start[s+1])
+      {@+print_char(so(str_pool[j]));incr(j);
+      }
+    new_line_char=nl;return;
+    }
+j=str_start[s];
+while (j < str_start[s+1])
+  {@+print_char(so(str_pool[j]));incr(j);
+  }
+}
+
+@ Control sequence names, file names, and strings constructed with
+\.{\\string} might contain |ASCII_code| values that can't
+be printed using |print_char|. Therefore we use |slow_print| for them:
+
+@<Basic print...@>=
+static void slow_print(int @!s) /*prints string |s|*/
+{@+pool_pointer j; /*current character code position*/
+if ((s >= str_ptr)||(s < 256)) printn(s);
+else{@+j=str_start[s];
+  while (j < str_start[s+1])
+    {@+printn(so(str_pool[j]));incr(j);
+    }
+  }
+}
+
+@ Here is the very first thing that \TeX\ prints: a headline that identifies
+the version number and format package. The |term_offset| variable is temporarily
+incorrect, but the discrepancy is not serious since we assume that this
+part of the program is system dependent.
+@^system dependencies@>
+
+k\TeX, according to the conventions of \TeX\ Live,
+ prints the |dump_name| if no format identifier is known.
+@<Initialize the output...@>=
+wterm("%s",banner);
+if (format_ident==0) wterm_ln(" (preloaded format=%s)", dump_name);
+else{@+slow_print(format_ident);print_ln();
+  }
+update_terminal;
+
+@ The procedure |print_nl| is like |print|, but it makes sure that the
+string appears at the beginning of a new line.
+
+@<Basic print...@>=
+static void print_nl(char *@!s) /*prints string |s| at beginning of line*/
+{@+if (((term_offset > 0)&&(odd(selector)))||@|
+  ((file_offset > 0)&&(selector >= log_only))) print_ln();
+print(s);
+}
+
+@ The procedure |print_esc| prints a string that is preceded by
+the user's escape character (which is usually a backslash).
+
+@<Basic print...@>=
+static void printn_esc(str_number @!s) /*prints escape character, then |s|*/
+{@+int c; /*the escape character code*/
+@<Set variable |c| to the current escape character@>;
+if (c >= 0) if (c < 256) printn(c);
+slow_print(s);
+}
+
+static void print_esc(char *@!s) /*the fast way*/
+{@+int c; /*the escape character code*/
+@<Set variable |c| to the current escape character@>;
+if (c >= 0) if (c < 256) printn(c);
+print(s);
+}
+
+@ An array of digits in the range |0 dotdot 15| is printed by |print_the_digs|.
+
+@<Basic print...@>=
+static void print_the_digs(eight_bits @!k)
+   /*prints |dig[k-1]|$\,\ldots\,$|dig[0]|*/
+{@+while (k > 0)
+  {@+decr(k);
+  if (dig[k] < 10) print_char('0'+dig[k]);
+  else print_char('A'-10+dig[k]);
+  }
+}
+
+@ The following procedure, which prints out the decimal representation of a
+given integer |n|, has been written carefully so that it works properly
+if |n==0| or if |(-n)| would cause overflow. It does not apply |%| or |/|
+to negative arguments, since such operations are not implemented consistently
+by all \PASCAL\ compilers.
+
+@<Basic print...@>=
+static void print_int(int @!n) /*prints an integer in decimal form*/
+{@+int k; /*index to current digit; we assume that $\vert n\vert<10^{23}$*/
+int @!m; /*used to negate |n| in possibly dangerous cases*/
+k=0;
+if (n < 0)
+  {@+print_char('-');
+  if (n > -100000000) negate(n);
+  else{@+m=-1-n;n=m/10;m=(m%10)+1;k=1;
+    if (m < 10) dig[0]=m;
+    else{@+dig[0]=0;incr(n);
+      }
+    }
+  }
+@/do at +{dig[k]=n%10;n=n/10;incr(k);
+}@+ while (!(n==0));
+print_the_digs(k);
+}
+
+@ Here is a trivial procedure to print two digits; it is usually called with
+a parameter in the range |0 <= n <= 99|.
+
+ at p static void print_two(int @!n) /*prints two least significant digits*/
+{@+n=abs(n)%100;print_char('0'+(n/10));
+print_char('0'+(n%10));
+}
+
+@ Hexadecimal printing of nonnegative integers is accomplished by |print_hex|.
+
+ at p static void print_hex(int @!n)
+   /*prints a positive integer in hexadecimal form*/
+{@+int k; /*index to current digit; we assume that $0\le n<16^{22}$*/
+k=0;print_char('"');
+@/do at +{dig[k]=n%16;n=n/16;incr(k);
+}@+ while (!(n==0));
+print_the_digs(k);
+}
+
+@ Old versions of \TeX\ needed a procedure called |print_ASCII| whose function
+is now subsumed by |print|. We retain the old name here as a possible aid to
+future software arch\ae ologists.
+
+ at d print_ASCII printn
+
+@ Roman numerals are produced by the |print_roman_int| routine.  Readers
+who like puzzles might enjoy trying to figure out how this tricky code
+works; therefore no explanation will be given. Notice that 1990 yields
+\.{mcmxc}, not \.{mxm}.
+
+ at p static void print_roman_int(int @!n)
+{@+
+pool_pointer j, @!k; /*mysterious indices into |mystery|*/
+nonnegative_integer @!u, @!v; /*mysterious numbers*/
+const char mystery[] ="m2d5c2l5x2v5i";
+j=0;v=1000;
+loop at +{@+while (n >= v)
+    {@+print_char(so(mystery[j]));n=n-v;
+    }
+  if (n <= 0) return; /*nonpositive input produces no output*/
+  k=j+2;u=v/(so(mystery[k-1])-'0');
+  if (mystery[k-1]==si('2'))
+    {@+k=k+2;u=u/(so(mystery[k-1])-'0');
+    }
+  if (n+u >= v)
+    {@+print_char(so(mystery[k]));n=n+u;
+    }
+  else{@+j=j+2;v=v/(so(mystery[j-1])-'0');
+    }
+  }
+}
+
+@ The |print| subroutine will not print a string that is still being
+created. The following procedure will.
+
+ at p static void print_current_string(void) /*prints a yet-unmade string*/
+{@+pool_pointer j; /*points to current character code*/
+j=str_start[str_ptr];
+while (j < pool_ptr)
+  {@+print_char(so(str_pool[j]));incr(j);
+  }
+}
+
+@ Here is a procedure that asks the user to type a line of input,
+assuming that the |selector| setting is either |term_only| or |term_and_log|.
+The input is placed into locations |first| through |last-1| of the
+|buffer| array, and echoed on the transcript file if appropriate.
+
+This procedure is never called when |interaction < scroll_mode|.
+
+ at d prompt_input(A) {@+wake_up_terminal;print(A);term_input();
+    }  /*prints a string and gets a line of input*/
+
+ at p static void term_input(void) /*gets a line from the terminal*/
+{@+int k; /*index into |buffer|*/
+update_terminal; /*now the user sees the prompt for sure*/
+if (!input_ln(&term_in, true)) fatal_error("End of file on the terminal!");
+ at .End of file on the terminal@>
+term_offset=0; /*the user's line ended with \<\rm return>*/
+decr(selector); /*prepare to echo the input*/
+if (last!=first) for (k=first; k<=last-1; k++) printn(buffer[k]);
+print_ln();incr(selector); /*restore previous status*/
+}
+
+@* Reporting errors.
+When something anomalous is detected, \TeX\ typically does something like this:
+$$\vbox{\halign{#\hfil\cr
+|print_err("Something anomalous has been detected");|\cr
+|help3("This is the first line of my offer to help.")|\cr
+|("This is the second line. I'm trying to")|\cr
+|("explain the best way for you to proceed.");|\cr
+|error;|\cr}}$$
+A two-line help message would be given using |help2|, etc.; these informal
+helps should use simple vocabulary that complements the words used in the
+official error message that was printed. (Outside the U.S.A., the help
+messages should preferably be translated into the local vernacular. Each
+line of help is at most 60 characters long, in the present implementation,
+so that |max_print_line| will not be exceeded.)
+
+The |print_err| procedure supplies a `\.!' before the official message,
+and makes sure that the terminal is awake if a stop is going to occur.
+The |error| procedure supplies a `\..' after the official message, then it
+shows the location of the error; and if |interaction==error_stop_mode|,
+it also enters into a dialog with the user, during which time the help
+message may be printed.
+@^system dependencies@>
+
+@<Error handling...@>=
+void print_err(char *s)
+{@+if (interaction==error_stop_mode) wake_up_terminal;
+  if (filelineerrorstylep) print_file_line(); /* k\TeX\ */
+  else print_nl("! ");
+  print(s);
+}
+
+@ The global variable |interaction| has four settings, representing increasing
+amounts of user interaction:
+
+ at d batch_mode 0 /*omits all stops and omits terminal output*/
+ at d nonstop_mode 1 /*omits all stops*/
+ at d scroll_mode 2 /*omits error stops*/
+ at d error_stop_mode 3 /*stops at every opportunity to interact*/
+
+@<Glob...@>=
+static int @!interaction; /*current level of interaction*/
+
+@ @<Set init...@>=interaction=error_stop_mode;
+
+@ \TeX\ is careful not to call |error| when the print |selector| setting
+might be unusual. The only possible values of |selector| at the time of
+error messages are
+
+\yskip\hang|no_print| (when |interaction==batch_mode|
+  and |log_file| not yet open);
+
+\hang|term_only| (when |interaction > batch_mode| and |log_file| not yet open);
+
+\hang|log_only| (when |interaction==batch_mode| and |log_file| is open);
+
+\hang|term_and_log| (when |interaction > batch_mode| and |log_file| is open).
+
+@<Initialize the print |selector| based on |interaction|@>=
+if (interaction==batch_mode) selector=no_print;@+else selector=term_only
+
+@ A global variable |deletions_allowed| is set |false| if the |get_next|
+routine is active when |error| is called; this ensures that |get_next|
+and related routines like |get_token| will never be called recursively.
+A similar interlock is provided by |set_box_allowed|.
+@^recursion@>
+
+The global variable |history| records the worst level of error that
+has been detected. It has four possible values: |spotless|, |warning_issued|,
+|error_message_issued|, and |fatal_error_stop|.
+
+Another global variable, |error_count|, is increased by one when an
+|error| occurs without an interactive dialog, and it is reset to zero at
+the end of every paragraph.  If |error_count| reaches 100, \TeX\ decides
+that there is no point in continuing further.
+
+ at d spotless 0 /*|history| value when nothing has been amiss yet*/
+ at d warning_issued 1 /*|history| value when |begin_diagnostic| has been called*/
+ at d error_message_issued 2 /*|history| value when |error| has been called*/
+ at d fatal_error_stop 3 /*|history| value when termination was premature*/
+
+@<Glob...@>=
+static bool @!deletions_allowed; /*is it safe for |error| to call |get_token|?*/
+static bool @!set_box_allowed; /*is it safe to do a \.{\\setbox} assignment?*/
+static int @!history; /*has the source input been clean so far?*/
+static int @!error_count; /*the number of scrolled errors since the
+  last paragraph ended*/
+
+@ The value of |history| is initially |fatal_error_stop|, but it will
+be changed to |spotless| if \TeX\ survives the initialization process.
+
+@<Set init...@>=
+deletions_allowed=true;set_box_allowed=true;
+error_count=0; /*|history| is initialized elsewhere*/
+
+@ Since errors can be detected almost anywhere in \TeX, we want to declare the
+error procedures near the beginning of the program. But the error procedures
+in turn use some other procedures, which need to be declared |forward|
+before we get to |error| itself.
+
+It is possible for |error| to be called recursively if some error arises
+when |get_token| is being used to delete a token, and/or if some fatal error
+occurs while \TeX\ is trying to fix a non-fatal one. But such recursion
+@^recursion@>
+is never more than two levels deep.
+
+@<Error handling...@>=
+static void normalize_selector(void);@/
+static void get_token(void);@/
+static void term_input(void);@/
+static void show_context(void);@/
+static void begin_file_reading(void);@/
+static void open_log_file(void);@/
+static void close_files_and_terminate(void);@/
+static void clear_for_error_prompt(void);@/
+static void give_err_help(void);@/
+#ifdef @!DEBUG
+static void debug_help(void);
+#else
+#define debug_help() do_nothing
+#endif
+
+@ Individual lines of help are recorded in the array |help_line|, which
+contains entries in positions |0 dotdot(help_ptr-1)|. They should be printed
+in reverse order, i.e., with |help_line[0]| appearing last.
+
+ at d hlp1(A) help_line[0]=A;@+}
+ at d hlp2(A, B) help_line[1]=A;help_line[0]=B;@+}
+ at d hlp3(A, B, C) help_line[2]=A;help_line[1]=B;help_line[0]=C;@+}
+ at d hlp4(A, B, C, D) help_line[3]=A;help_line[2]=B;help_line[1]=C;help_line[0]=D;@+}
+ at d hlp5(A, B, C, D, E) help_line[4]=A;help_line[3]=B;help_line[2]=C;help_line[1]=D;help_line[0]=E;@+}
+ at d hlp6(A, B, C, D, E, F) help_line[5]=A;help_line[4]=B;help_line[3]=C;help_line[2]=D;help_line[1]=E;help_line[0]=F;@+}
+ at d help0 help_ptr=0 /*sometimes there might be no help*/
+ at d help1(A) @+{@+help_ptr=1;hlp1(A) /*use this with one help line*/
+ at d help2(A, B) @+{@+help_ptr=2;hlp2(A, B) /*use this with two help lines*/
+ at d help3(A, B, C) @+{@+help_ptr=3;hlp3(A, B, C) /*use this with three help lines*/
+ at d help4(A, B, C, D) @+{@+help_ptr=4;hlp4(A, B, C, D) /*use this with four help lines*/
+ at d help5(A, B, C, D, E) @+{@+help_ptr=5;hlp5(A, B, C, D, E) /*use this with five help lines*/
+ at d help6(A, B, C, D, E, F) @+{@+help_ptr=6;hlp6(A, B, C, D, E, F) /*use this with six help lines*/
+
+@<Glob...@>=
+static char *@!help_line[6]; /*helps for the next |error|*/
+static int @!help_ptr; /*the number of help lines present*/
+static bool @!use_err_help; /*should the |err_help| list be shown?*/
+
+@ @<Set init...@>=
+help_ptr=0;use_err_help=false;
+
+@ The |jump_out| procedure just cuts across all active procedure levels and
+goes to |end_of_TEX|. This is the only nontrivial |@!goto| statement in the
+whole program. It is used when there is no recovery from a particular error.
+
+Some \PASCAL\ compilers do not implement non-local |goto| statements.
+@^system dependencies@>
+In such cases the body of |jump_out| should simply be
+`|close_files_and_terminate|;\thinspace' followed by a call on some system
+procedure that quietly terminates the program.
+
+@<Error hand...@>=
+static void jump_out(void)
+{@+ close_files_and_terminate(); exit(0);
+}
+
+@ Here now is the general |error| routine.
+
+@<Error hand...@>=
+static void error(void) /*completes the job of error reporting*/
+{@+
+ASCII_code c; /*what the user types*/
+int @!s1, @!s2, @!s3, @!s4;
+   /*used to save global variables when deleting tokens*/
+if (history < error_message_issued) history=error_message_issued;
+print_char('.');show_context();
+if (interaction==error_stop_mode)
+  @<Get user's advice and |return|@>;
+incr(error_count);
+if (error_count==100)
+  {@+print_nl("(That makes 100 errors; please try again.)");
+ at .That makes 100 errors...@>
+  history=fatal_error_stop;jump_out();
+  }
+@<Put help message on the transcript file@>;
+}
+
+@ @<Get user's advice...@>=
+loop at +{@+resume: if (interaction!=error_stop_mode) return;
+  clear_for_error_prompt();prompt_input("? ");
+ at .?\relax@>
+  if (last==first) return;
+  c=buffer[first];
+  if (c >= 'a') c=c+'A'-'a'; /*convert to uppercase*/
+  @<Interpret code |c| and |return| if done@>;
+  }
+
+@ It is desirable to provide an `\.E' option here that gives the user
+an easy way to return from \TeX\ to the system editor, with the offending
+line ready to be edited. But such an extension requires some system
+wizardry, so the present implementation simply types out the name of the
+file that should be
+edited and the relevant line number.
+@^system dependencies@>
+
+There is a secret `\.D' option available when the debugging routines haven't
+been commented~out.
+@^debugging@>
+
+@<Interpret code |c| and |return| if done@>=
+switch (c) {
+case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (deletions_allowed)
+  @<Delete \(c)|c-"0"| tokens and |goto continue|@>@;@+break;
+ at t\4\4@>@;
+#ifdef @!DEBUG
+case 'D': {@+debug_help();goto resume;@+}
+#endif
+case 'E': if (base_ptr > 0) if (input_stack[base_ptr].name_field >= 256)
+  {@+print_nl("You want to edit file ");
+ at .You want to edit file x@>
+  slow_print(input_stack[base_ptr].name_field);
+  print(" at line ");print_int(line);
+  interaction=scroll_mode;jump_out();
+  } @+break;
+case 'H': @<Print the help information and |goto continue|@>@;
+case 'I': @<Introduce new material from the terminal and |return|@>@;
+case 'Q': case 'R': case 'S': @<Change the interaction level and |return|@>@;
+case 'X': {@+interaction=scroll_mode;jump_out();
+  } @+break;
+default:do_nothing;
+} @/
+@<Print the menu of available options@>@;
+
+@ @<Print the menu...@>=
+{@+print("Type <return> to proceed, S to scroll future error messages,");@/
+ at .Type <return> to proceed...@>
+print_nl("R to run without stopping, Q to run quietly,");@/
+print_nl("I to insert something, ");
+if (base_ptr > 0) if (input_stack[base_ptr].name_field >= 256)
+  print("E to edit your file,");
+if (deletions_allowed)
+  print_nl("1 or ... or 9 to ignore the next 1 to 9 tokens of input,");
+print_nl("H for help, X to quit.");
+}
+
+@ Here the author of \TeX\ apologizes for making use of the numerical
+relation between |'Q'|, |'R'|, |'S'|, and the desired interaction settings
+|batch_mode|, |nonstop_mode|, |scroll_mode|.
+@^Knuth, Donald Ervin@>
+
+@<Change the interaction...@>=
+{@+error_count=0;interaction=batch_mode+c-'Q';
+print("OK, entering ");
+switch (c) {
+case 'Q': {@+print_esc("batchmode");decr(selector);
+  } @+break;
+case 'R': print_esc("nonstopmode");@+break;
+case 'S': print_esc("scrollmode");
+}  /*there are no other cases*/
+print("...");print_ln();update_terminal;return;
+}
+
+@ When the following code is executed, |buffer[(first+1)dotdot(last-1)]| may
+contain the material inserted by the user; otherwise another prompt will
+be given. In order to understand this part of the program fully, you need
+to be familiar with \TeX's input stacks.
+
+@<Introduce new material...@>=
+{@+begin_file_reading(); /*enter a new syntactic level for terminal input*/
+ /*now |state==mid_line|, so an initial blank space will count as a blank*/
+if (last > first+1)
+  {@+loc=first+1;buffer[first]=' ';
+  }
+else{@+prompt_input("insert>");loc=first;
+ at .insert>@>
+  }
+first=last;
+cur_input.limit_field=last-1; /*no |end_line_char| ends this line*/
+return;
+}
+
+@ We allow deletion of up to 99 tokens at a time.
+
+@<Delete \(c)|c-"0"| tokens...@>=
+{@+s1=cur_tok;s2=cur_cmd;s3=cur_chr;s4=align_state;
+align_state=1000000;OK_to_interrupt=false;
+if ((last > first+1)&&(buffer[first+1] >= '0')&&(buffer[first+1] <= '9'))
+  c=c*10+buffer[first+1]-'0'*11;
+else c=c-'0';
+while (c > 0)
+  {@+get_token(); /*one-level recursive call of |error| is possible*/
+  decr(c);
+  }
+cur_tok=s1;cur_cmd=s2;cur_chr=s3;align_state=s4;OK_to_interrupt=true;
+help2("I have just deleted some text, as you asked.",@/
+"You can now delete more, or insert, or whatever.");
+show_context();goto resume;
+}
+
+@ @<Print the help info...@>=
+{@+if (use_err_help)
+  {@+give_err_help();use_err_help=false;
+  }
+else{@+if (help_ptr==0)
+    help2("Sorry, I don't know how to help in this situation.",@/
+    @t\kern1em@>"Maybe you should try asking a human?");
+  @/do at +{decr(help_ptr);print(help_line[help_ptr]);print_ln();
+  }@+ while (!(help_ptr==0));
+  }
+help4("Sorry, I already gave what help I could...",@/
+  "Maybe you should try asking a human?",@/
+  "An error might have occurred before I noticed any problems.",@/
+  "``If all else fails, read the instructions.'");@/
+goto resume;
+}
+
+@ @<Put help message on the transcript file@>=
+if (interaction > batch_mode) decr(selector); /*avoid terminal output*/
+if (use_err_help)
+  {@+print_ln();give_err_help();
+  }
+else while (help_ptr > 0)
+  {@+decr(help_ptr);print_nl(help_line[help_ptr]);
+  }
+print_ln();
+if (interaction > batch_mode) incr(selector); /*re-enable terminal output*/
+print_ln()
+
+@ A dozen or so error messages end with a parenthesized integer, so we
+save a teeny bit of program space by declaring the following procedure:
+
+ at p static void int_error(int @!n)
+{@+print(" (");print_int(n);print_char(')');error();
+}
+
+@ In anomalous cases, the print selector might be in an unknown state;
+the following subroutine is called to fix things just enough to keep
+running a bit longer.
+
+ at p static void normalize_selector(void)
+{@+if (log_opened) selector=term_and_log;
+else selector=term_only;
+if (job_name==0) open_log_file();
+if (interaction==batch_mode) decr(selector);
+}
+
+@ The following procedure prints \TeX's last words before dying.
+
+ at d succumb {@+if (interaction==error_stop_mode)
+    interaction=scroll_mode; /*no more interaction*/
+  if (log_opened) error();
+  if (interaction > batch_mode) debug_help();
+  history=fatal_error_stop;jump_out(); /*irrecoverable error*/
+  }
+
+@<Error hand...@>=
+static void fatal_error(char *@!s) /*prints |s|, and that's it*/
+{@+normalize_selector();@/
+print_err("Emergency stop");help1(s);succumb;
+ at .Emergency stop@>
+}
+
+@ Here is the most dreaded error message.
+
+@<Error hand...@>=
+static void overflow(char *@!s, int @!n) /*stop due to finiteness*/
+{@+normalize_selector();
+print_err("TeX capacity exceeded, sorry [");
+ at .TeX capacity exceeded ...@>
+print(s);print_char('=');print_int(n);print_char(']');
+help2("If you really absolutely need more capacity,",@/
+  "you can ask a wizard to enlarge me.");
+succumb;
+}
+
+@ The program might sometime run completely amok, at which point there is
+no choice but to stop. If no previous error has been detected, that's bad
+news; a message is printed that is really intended for the \TeX\
+maintenance person instead of the user (unless the user has been
+particularly diabolical).  The index entries for `this can't happen' may
+help to pinpoint the problem.
+@^dry rot@>
+
+@<Error hand...@>=
+static void confusion(char *@!s)
+   /*consistency check violated; |s| tells where*/
+{@+normalize_selector();
+if (history < error_message_issued)
+  {@+print_err("This can't happen (");print(s);print_char(')');
+ at .This can't happen@>
+  help1("I'm broken. Please show this to someone who can fix can fix");
+  }
+else{@+print_err("I can't go on meeting you like this");
+ at .I can't go on...@>
+  help2("One of your faux pas seems to have wounded me deeply...",@/
+    "in fact, I'm barely conscious. Please fix it and try again.");
+  }
+succumb;
+}
+
+@ Users occasionally want to interrupt \TeX\ while it's running.
+If the \PASCAL\ runtime system allows this, one can implement
+a routine that sets the global variable |interrupt| to some nonzero value
+when such an interrupt is signalled. Otherwise there is probably at least
+a way to make |interrupt| nonzero using the \PASCAL\ debugger.
+@^system dependencies@>
+@^debugging@>
+
+ at d check_interrupt {@+if (interrupt!=0) pause_for_instructions();
+  }
+
+@<Global...@>=
+static int @!interrupt; /*should \TeX\ pause for instructions?*/
+static bool @!OK_to_interrupt; /*should interrupts be observed?*/
+
+@ @<Set init...@>=
+interrupt=0;OK_to_interrupt=true;
+
+@ When an interrupt has been detected, the program goes into its
+highest interaction level and lets the user have nearly the full flexibility of
+the |error| routine.  \TeX\ checks for interrupts only at times when it is
+safe to do this.
+
+ at p static void pause_for_instructions(void)
+{@+if (OK_to_interrupt)
+  {@+interaction=error_stop_mode;
+  if ((selector==log_only)||(selector==no_print))
+    incr(selector);
+  print_err("Interruption");
+ at .Interruption@>
+  help3("You rang?",@/
+  "Try to insert an instruction for me (e.g., `I\\showlists'),",@/
+  "unless you just want to quit by typing `X'.");
+  deletions_allowed=false;error();deletions_allowed=true;
+  interrupt=0;
+  }
+}
+
+@* Arithmetic with scaled dimensions.
+The principal computations performed by \TeX\ are done entirely in terms of
+integers less than $2^{31}$ in magnitude; and divisions are done only when both
+dividend and divisor are nonnegative. Thus, the arithmetic specified in this
+program can be carried out in exactly the same way on a wide variety of
+computers, including some small ones. Why? Because the arithmetic
+calculations need to be spelled out precisely in order to guarantee that
+\TeX\ will produce identical output on different machines. If some
+quantities were rounded differently in different implementations, we would
+find that line breaks and even page breaks might occur in different places.
+Hence the arithmetic of \TeX\ has been designed with care, and systems that
+claim to be implementations of \TeX82 should follow precisely the
+@:TeX82}{\TeX82@>
+calculations as they appear in the present program.
+
+(Actually there are three places where \TeX\ uses |/| with a possibly negative
+numerator. These are harmless; see |/| in the index. Also if the user
+sets the \.{\\time} or the \.{\\year} to a negative value, some diagnostic
+information will involve negative-numerator division. The same remarks
+apply for |%| as well as for |/|.)
+
+@ Here is a routine that calculates half of an integer, using an
+unambiguous convention with respect to signed odd numbers.
+
+ at p static int half(int @!x)
+{@+if (odd(x)) return(x+1)/2;
+else return x/2;
+}
+
+@ Fixed-point arithmetic is done on {\sl scaled integers\/} that are multiples
+of $2^{-16}$. In other words, a binary point is assumed to be sixteen bit
+positions from the right end of a binary computer word.
+
+ at d unity 0200000 /*$2^{16}$, represents 1.00000*/
+ at d two 0400000 /*$2^{17}$, represents 2.00000*/
+
+@<Types...@>=
+typedef int scaled; /*this type is used for scaled integers*/
+typedef int32_t nonnegative_integer; /*$0\le x<2^{31}$*/
+typedef int8_t small_number; /*this type is self-explanatory*/
+
+@ The following function is used to create a scaled integer from a given decimal
+fraction $(.d_0d_1\ldots d_{k-1})$, where |0 <= k <= 17|. The digit $d_i$ is
+given in |dig[i]|, and the calculation produces a correctly rounded result.
+
+ at p static scaled round_decimals(small_number @!k)
+   /*converts a decimal fraction*/
+{@+int a; /*the accumulator*/
+a=0;
+while (k > 0)
+  {@+decr(k);a=(a+dig[k]*two)/10;
+  }
+return(a+1)/2;
+}
+
+@ Conversely, here is a procedure analogous to |print_int|. If the output
+of this procedure is subsequently read by \TeX\ and converted by the
+|round_decimals| routine above, it turns out that the original value will
+be reproduced exactly; the ``simplest'' such decimal number is output,
+but there is always at least one digit following the decimal point.
+
+The invariant relation in the \&{repeat} loop is that a sequence of
+decimal digits yet to be printed will yield the original number if and only if
+they form a fraction~$f$ in the range $s-\delta\le 10\cdot2^{16}f<s$.
+We can stop if and only if $f=0$ satisfies this condition; the loop will
+terminate before $s$ can possibly become zero.
+
+ at p static void print_scaled(scaled @!s) /*prints scaled real, rounded to five
+  digits*/
+{@+scaled delta; /*amount of allowable inaccuracy*/
+if (s < 0)
+  {@+print_char('-');negate(s); /*print the sign, if negative*/
+  }
+print_int(s/unity); /*print the integer part*/
+print_char('.');
+s=10*(s%unity)+5;delta=10;
+@/do at +{if (delta > unity) s=s+0100000-50000; /*round the last digit*/
+print_char('0'+(s/unity));s=10*(s%unity);delta=delta*10;
+}@+ while (!(s <= delta));
+}
+
+@ Physical sizes that a \TeX\ user specifies for portions of documents are
+represented internally as scaled points. Thus, if we define an `sp' (scaled
+@^sp@>
+point) as a unit equal to $2^{-16}$ printer's points, every dimension
+inside of \TeX\ is an integer number of sp. There are exactly
+4,736,286.72 sp per inch.  Users are not allowed to specify dimensions
+larger than $2^{30}-1$ sp, which is a distance of about 18.892 feet (5.7583
+meters); two such quantities can be added without overflow on a 32-bit
+computer.
+
+The present implementation of \TeX\ does not check for overflow when
+@^overflow in arithmetic@>
+dimensions are added or subtracted. This could be done by inserting a
+few dozen tests of the form `\ignorespaces|if (x >= 010000000000)|
+\\{report\_overflow}', but the chance of overflow is so remote that
+such tests do not seem worthwhile.
+
+\TeX\ needs to do only a few arithmetic operations on scaled quantities,
+other than addition and subtraction, and the following subroutines do most of
+the work. A single computation might use several subroutine calls, and it is
+desirable to avoid producing multiple error messages in case of arithmetic
+overflow; so the routines set the global variable |arith_error| to |true|
+instead of reporting errors directly to the user. Another global variable,
+|rem|, holds the remainder after a division.
+
+@<Glob...@>=
+static bool @!arith_error; /*has arithmetic overflow occurred recently?*/
+static scaled @!rem; /*amount subtracted to get an exact division*/
+
+@ The first arithmetical subroutine we need computes $nx+y$, where |x|
+and~|y| are |scaled| and |n| is an integer. We will also use it to
+multiply integers.
+
+ at d nx_plus_y(A, B, C) mult_and_add(A, B, C, 07777777777)
+ at d mult_integers(A, B) mult_and_add(A, B, 0, 017777777777)
+
+ at p static scaled mult_and_add(int @!n, scaled @!x, scaled @!y, scaled @!max_answer)
+{@+if (n < 0)
+  {@+negate(x);negate(n);
+  }
+if (n==0) return y;
+else if (((x <= (max_answer-y)/n)&&(-x <= (max_answer+y)/n)))
+  return n*x+y;
+else{@+arith_error=true;return 0;
+  }
+}
+
+@ We also need to divide scaled dimensions by integers.
+
+ at p static scaled x_over_n(scaled @!x, int @!n)
+{@+bool negative; /*should |rem| be negated?*/
+scaled x_over_n;
+negative=false;
+if (n==0)
+  {@+arith_error=true;x_over_n=0;rem=x;
+  }
+else{@+if (n < 0)
+    {@+negate(x);negate(n);negative=true;
+    }
+  if (x >= 0)
+    {@+x_over_n=x/n;rem=x%n;
+    }
+  else{@+x_over_n=-((-x)/n);rem=-((-x)%n);
+    }
+  }
+if (negative) negate(rem);
+return x_over_n;}
+
+@ Then comes the multiplication of a scaled number by a fraction |n/(double)d|,
+where |n| and |d| are nonnegative integers | <= @t$2^{16}$@>| and |d| is
+positive. It would be too dangerous to multiply by~|n| and then divide
+by~|d|, in separate operations, since overflow might well occur; and it
+would be too inaccurate to divide by |d| and then multiply by |n|. Hence
+this subroutine simulates 1.5-precision arithmetic.
+
+ at p static scaled xn_over_d(scaled @!x, int @!n, int @!d)
+{@+bool positive; /*was |x >= 0|?*/
+nonnegative_integer @!t, @!u, @!v; /*intermediate quantities*/
+scaled xn_over_d;
+if (x >= 0) positive=true;
+else{@+negate(x);positive=false;
+  }
+t=(x%0100000)*n;
+u=(x/0100000)*n+(t/0100000);
+v=(u%d)*0100000+(t%0100000);
+if (u/d >= 0100000) arith_error=true;
+else u=0100000*(u/d)+(v/d);
+if (positive)
+  {@+xn_over_d=u;rem=v%d;
+  }
+else{@+xn_over_d=-u;rem=-(v%d);
+  }
+return xn_over_d;}
+
+@ The next subroutine is used to compute the ``badness'' of glue, when a
+total~|t| is supposed to be made from amounts that sum to~|s|.  According
+to {\sl The \TeX book}, the badness of this situation is $100(t/s)^3$;
+however, badness is simply a heuristic, so we need not squeeze out the
+last drop of accuracy when computing it. All we really want is an
+approximation that has similar properties.
+@:TeXbook}{\sl The \TeX book@>
+
+The actual method used to compute the badness is easier to read from the
+program than to describe in words. It produces an integer value that is a
+reasonably close approximation to $100(t/s)^3$, and all implementations
+of \TeX\ should use precisely this method. Any badness of $2^{13}$ or more is
+treated as infinitely bad, and represented by 10000.
+
+It is not difficult to prove that $$\hbox{|badness(t+1, s) >= badness(t, s)
+ >= badness(t, s+1)|}.$$ The badness function defined here is capable of
+computing at most 1095 distinct values, but that is plenty.
+
+ at d inf_bad 10000 /*infinitely bad value*/
+
+ at p @<Declare \Prote\ arithmetic routines@>@/
+static halfword badness(scaled @!t, scaled @!s) /*compute badness, given |t >= 0|*/
+{@+int r; /*approximation to $\alpha t/s$, where $\alpha^3\approx
+  100\cdot2^{18}$*/
+if (t==0) return 0;
+else if (s <= 0) return inf_bad;
+else{@+if (t <= 7230584) r=(t*297)/s; /*$297^3=99.94\times2^{18}$*/
+  else if (s >= 1663497) r=t/(s/297);
+  else r=t;
+  if (r > 1290) return inf_bad; /*$1290^3<2^{31}<1291^3$*/
+  else return(r*r*r+0400000)/01000000;
+  }  /*that was $r^3/2^{18}$, rounded to the nearest integer*/
+}
+
+@ When \TeX\ ``packages'' a list into a box, it needs to calculate the
+proportionality ratio by which the glue inside the box should stretch
+or shrink. This calculation does not affect \TeX's decision making,
+so the precise details of rounding, etc., in the glue calculation are not
+of critical importance for the consistency of results on different computers.
+
+We shall use the type |glue_ratio| for such proportionality ratios.
+A glue ratio should take the same amount of memory as an
+|int| (usually 32 bits) if it is to blend smoothly with \TeX's
+other data structures. Thus |glue_ratio| should be equivalent to
+|short_real| in some implementations of \PASCAL. Alternatively,
+it is possible to deal with glue ratios using nothing but fixed-point
+arithmetic; see {\sl TUGboat \bf3},1 (March 1982), 10--27. (But the
+routines cited there must be modified to allow negative glue ratios.)
+@^system dependencies@>
+
+ at d set_glue_ratio_zero(A) A=0.0 /*store the representation of zero ratio*/
+ at d set_glue_ratio_one(A) A=1.0 /*store the representation of unit ratio*/
+ at d float(A) ((double)(A)) /*convert from |glue_ratio| to type |double|*/
+ at d unfloat(A) ((glue_ratio)(A)) /*convert from |double| to type |glue_ratio|*/
+ at d float_constant(A) ((double)(A)) /*convert |int| constant to |double|*/
+
+@<Types...@>=
+#if __SIZEOF_FLOAT__==4
+typedef float float32_t;
+#else
+#error  float type must have size 4
+#endif
+typedef float @!glue_ratio; /*one-word representation of a glue expansion factor*/
+
+@* Packed data.
+In order to make efficient use of storage space, \TeX\ bases its major data
+structures on a |memory_word|, which contains either a (signed) integer,
+possibly scaled, or a (signed) |glue_ratio|, or a small number of
+fields that are one half or one quarter of the size used for storing
+integers.
+
+If |x| is a variable of type |memory_word|, it contains up to four
+fields that can be referred to as follows:
+$$\vbox{\halign{\hfil#&#\hfil&#\hfil\cr
+|x|&.|i|&(an |int|)\cr
+|x|&.|sc|\qquad&(a |scaled| integer)\cr
+|x|&.|gr|&(a |glue_ratio|)\cr
+|x.hh.lh|, |x.hh|&.|rh|&(two halfword fields)\cr
+|x.hh.b0|, |x.hh.b1|, |x.hh|&.|rh|&(two quarterword fields, one halfword
+  field)\cr
+|x.qqqq.b0|, |x.qqqq.b1|, |x.qqqq|&.|b2|, |x.qqqq.b3|\hskip-100pt
+  &\qquad\qquad\qquad(four quarterword fields)\cr}}$$
+This is somewhat cumbersome to write, and not very readable either, but
+macros will be used to make the notation shorter and more transparent.
+The \PASCAL\ code below gives a formal definition of |memory_word| and
+its subsidiary types, using packed variant records. \TeX\ makes no
+assumptions about the relative positions of the fields within a word.
+
+Since we are assuming 32-bit integers, a halfword must contain at least
+16 bits, and a quarterword must contain at least 8 bits.
+@^system dependencies@>
+But it doesn't hurt to have more bits; for example, with enough 36-bit
+words you might be able to have |mem_max| as large as 262142, which is
+eight times as much memory as anybody had during the first four years of
+\TeX's existence.
+
+N.B.: Valuable memory space will be dreadfully wasted unless \TeX\ is compiled
+by a \PASCAL\ that packs all of the |memory_word| variants into
+the space of a single integer. This means, for example, that |glue_ratio|
+words should be |short_real| instead of |double| on some computers. Some
+\PASCAL\ compilers will pack an integer whose subrange is `|0 dotdot 255|' into
+an eight-bit field, but others insist on allocating space for an additional
+sign bit; on such systems you can get 256 values into a quarterword only
+if the subrange is `|-128 dotdot 127|'.
+
+The present implementation tries to accommodate as many variations as possible,
+so it makes few assumptions. If integers having the subrange
+`|min_quarterword dotdot max_quarterword|' can be packed into a quarterword,
+and if integers having the subrange `|min_halfword dotdot max_halfword|'
+can be packed into a halfword, everything should work satisfactorily.
+
+It is usually most efficient to have |min_quarterword==min_halfword==0|,
+so one should try to achieve this unless it causes a severe problem.
+The values defined here are recommended for most 32-bit computers.
+
+ at d min_quarterword 0 /*smallest allowable value in a |quarterword|*/
+ at d max_quarterword 65535 /*largest allowable value in a |quarterword|*/
+ at d min_halfword 0 /*smallest allowable value in a |halfword|*/
+ at d max_halfword 0x3FFFFFFF /*largest allowable value in a |halfword|*/
+
+@ Here are the inequalities that the quarterword and halfword values
+must satisfy (or rather, the inequalities that they mustn't satisfy):
+
+@<Check the ``constant''...@>=
+#ifdef @!INIT
+if ((mem_min!=mem_bot)||(mem_max!=mem_top)) bad=10;
+#endif
+@;@/
+if ((mem_min > mem_bot)||(mem_max < mem_top)) bad=10;
+if ((min_quarterword > 0)||(max_quarterword < 127)) bad=11;
+if ((min_halfword > 0)||(max_halfword < 32767)) bad=12;
+if ((min_quarterword < min_halfword)||@|
+  (max_quarterword > max_halfword)) bad=13;
+if ((mem_min < min_halfword)||(mem_max >= max_halfword)||@|
+  (mem_bot-mem_min > max_halfword+1)) bad=14;
+if ((font_base < min_quarterword)||(font_max > max_quarterword)) bad=15;
+if (font_max > font_base+256) bad=16;
+if ((save_size > max_halfword)||(max_strings > max_halfword)) bad=17;
+if (buf_size > max_halfword) bad=18;
+if (max_quarterword-min_quarterword < 255) bad=19;
+
+@ The operation of adding or subtracting |min_quarterword| occurs quite
+frequently in \TeX, so it is convenient to abbreviate this operation
+by using the macros |qi| and |qo| for input and output to and from
+quarterword format.
+
+The inner loop of \TeX\ will run faster with respect to compilers
+that don't optimize expressions like `|x+0|' and `|x-0|', if these
+macros are simplified in the obvious way when |min_quarterword==0|.
+@^inner loop@>@^system dependencies@>
+
+ at d qi(A) A+min_quarterword
+   /*to put an |eight_bits| item into a quarterword*/
+ at d qo(A) A-min_quarterword
+   /*to take an |eight_bits| item out of a quarterword*/
+ at d hi(A) A+min_halfword
+   /*to put a sixteen-bit item into a halfword*/
+ at d ho(A) A-min_halfword
+   /*to take a sixteen-bit item from a halfword*/
+
+@ The reader should study the following definitions closely:
+@^system dependencies@>
+
+ at d sc i /*|scaled| data is equivalent to |int|*/
+
+@<Types...@>=
+typedef uint16_t quarterword; /*1/4 of a word*/
+typedef int32_t halfword; /*1/2 of a word*/
+typedef int8_t two_choices; /*used when there are two variants in a record*/
+typedef int8_t four_choices; /*used when there are four variants in a record*/
+typedef struct { @;@/
+  halfword @!rh;
+  union {
+  halfword @!lh;
+  struct { quarterword @!b0;quarterword @!b1;} ;
+  };} two_halves;
+typedef struct { @;@/
+  quarterword @!b0;
+  quarterword @!b1;
+  quarterword @!b2;
+  quarterword @!b3;
+  } four_quarters;
+typedef struct { @;@/
+  union {
+  int @!i;
+  glue_ratio @!gr;
+  two_halves @!hh;
+  four_quarters @!qqqq;
+  };} memory_word;
+typedef struct {@+FILE *f;@+memory_word@,d;@+} word_file;
+
+@ When debugging, we may want to print a |memory_word| without knowing
+what type it is; so we print it in all modes.
+@^dirty \PASCAL@>@^debugging@>
+
+ at p
+#ifdef @!DEBUG
+static void print_word(memory_word @!w)
+   /*prints |w| in all ways*/
+{@+print_int(w.i);print_char(' ');@/
+print_scaled(w.sc);print_char(' ');@/
+print_scaled(round(unity*float(w.gr)));print_ln();@/
+@^real multiplication@>
+print_int(w.hh.lh);print_char('=');print_int(w.hh.b0);print_char(':');
+print_int(w.hh.b1);print_char(';');print_int(w.hh.rh);print_char(' ');@/
+print_int(w.qqqq.b0);print_char(':');print_int(w.qqqq.b1);print_char(':');
+print_int(w.qqqq.b2);print_char(':');print_int(w.qqqq.b3);
+}
+#endif
+
+@* Dynamic memory allocation.
+The \TeX\ system does nearly all of its own memory allocation, so that it
+can readily be transported into environments that do not have automatic
+facilities for strings, garbage collection, etc., and so that it can be in
+control of what error messages the user receives. The dynamic storage
+requirements of \TeX\ are handled by providing a large array |mem| in
+which consecutive blocks of words are used as nodes by the \TeX\ routines.
+
+Pointer variables are indices into this array, or into another array
+called |eqtb| that will be explained later. A pointer variable might
+also be a special flag that lies outside the bounds of |mem|, so we
+allow pointers to assume any |halfword| value. The minimum halfword
+value represents a null pointer. \TeX\ does not assume that |mem[null]| exists.
+
 @s pointer int
- at s memory_word int
- at s ASCII_code int
- at s small_number int
- at s info_t int
- at s lig_t int
- at s disc_t int
- at s math_t int
- at s glyph_t int
- at s glue_t int
- at s rule_t int
- at s list_t int
- at s kind_t int
- at s image_t int
- at s glue_ord int
- at s four_quarters int
- at s eight_bits int
- at s internal_font_number int
- at s explicit normal
- at s str_number int
- at s dimen_t int
- at s loop else
- at s kpse_file_format_type int
- at s font_t int
+ at d pointer halfword /*a flag or a location in |mem| or |eqtb|*/
+ at d null min_halfword /*the null pointer*/
 
+@<Glob...@>=
+static pointer @!temp_ptr; /*a pointer variable for occasional emergency use*/
 
-\makeindex
-\maketoc
+@ The |mem| array is divided into two regions that are allocated separately,
+but the dividing line between these two regions is not fixed; they grow
+together until finding their ``natural'' size in a particular job.
+Locations less than or equal to |lo_mem_max| are used for storing
+variable-length records consisting of two or more words each. This region
+is maintained using an algorithm similar to the one described in exercise
+2.5--19 of {\sl The Art of Computer Programming}. However, no size field
+appears in the allocated nodes; the program is responsible for knowing the
+relevant size when a node is freed. Locations greater than or equal to
+|hi_mem_min| are used for storing one-word records; a conventional
+\.{AVAIL} stack is used for allocation in this region.
 
-%\makefigindex
-\titletrue
+Locations of |mem| between |mem_bot| and |mem_top| may be dumped as part
+of preloaded format files, by the \.{INITEX} preprocessor.
+ at .INITEX@>
+Production versions of \TeX\ may extend the memory at both ends in order to
+provide more space; locations between |mem_min| and |mem_bot| are always
+used for variable-size nodes, and locations between |mem_top| and |mem_max|
+are always used for single-word nodes.
 
-\def\lastrevision{${}$Revision: 2515 ${}$}
-\def\lastdate{${}$Date: 2021-09-23 17:59:58 +0200 (Thu, 23 Sep 2021) ${}$}
-\eject
-\input titlepage.tex
+The key pointers that govern |mem| allocation have a prescribed order:
+$$\advance\thickmuskip-2mu
+\hbox{|null <= mem_min <= mem_bot < lo_mem_max <
+  hi_mem_min < mem_top <= mem_end <= mem_max|.}$$
 
+Empirical tests show that the present implementation of \TeX\ tends to
+spend about 9\pct! of its running time allocating nodes, and about 6\pct!
+deallocating them after their use.
 
-\frontmatter
+@<Glob...@>=
+static memory_word @!mem0[mem_max-mem_min+1], *const @!mem = @!mem0-mem_min; /*the big dynamic storage area*/
+static pointer @!lo_mem_max; /*the largest location of variable-size memory in use*/
+static pointer @!hi_mem_min; /*the smallest location of one-word memory in use*/
 
-@
+@ In order to study the memory requirements of particular applications, it
+is possible to prepare a version of \TeX\ that keeps track of current and
+maximum memory usage. When code between the delimiters |
+#ifdef @!STAT
+| $\ldots$
+|tats| is not ``commented out,'' \TeX\ will run a bit slower but it will
+report these statistics when |tracing_stats| is sufficiently large.
 
+@<Glob...@>=
+static int @!var_used, @!dyn_used; /*how much memory is in use*/
+#ifdef @!STAT
+#define incr_dyn_used @[incr(dyn_used)@]
+#define decr_dyn_used @[decr(dyn_used)@]
+#else
+#define incr_dyn_used
+#define decr_dyn_used
+#endif
 
-\plainsection{Preface}
-To be written
+@ Let's consider the one-word memory region first, since it's the
+simplest. The pointer variable |mem_end| holds the highest-numbered location
+of |mem| that has ever been used. The free locations of |mem| that
+occur between |hi_mem_min| and |mem_end|, inclusive, are of type
+|two_halves|, and we write |info(p)| and |link(p)| for the |lh|
+and |rh| fields of |mem[p]| when it is of this type. The single-word
+free locations form a linked list
+$$|avail|,\;\hbox{|link(avail)|},\;\hbox{|link(link(avail))|},\;\ldots$$
+terminated by |null|.
 
-\vskip 1cm
-\noindent {\it M\"unchen\hfil\break
-August 20, 2018 \hfill Martin Ruckert}
+ at d link(A) mem[A].hh.rh /*the |link| field of a memory word*/
+ at d info(A) mem[A].hh.lh /*the |info| field of a memory word*/
 
+@<Glob...@>=
+static pointer @!avail; /*head of the list of available one-word nodes*/
+static pointer @!mem_end; /*the last one-word node used in |mem|*/
 
-\tableofcontent
-%\thefigindex
+@ If memory is exhausted, it might mean that the user has forgotten
+a right brace. We will define some procedures later that try to help
+pinpoint the trouble.
 
+ at p @<Declare the procedure called |show_token_list|@>@/
+@<Declare the procedure called |runaway|@>@;
 
-\mainmatter
+@ The function |get_avail| returns a pointer to a new one-word node whose
+|link| field is null. However, \TeX\ will halt if there is no more room left.
+@^inner loop@>
 
-\section{Introduction}\label{intro}
-Hi\TeX\ is a modified version of \TeX\ that replaces the \.{DVI}
-(device independent) output format by the \HINT\ format.  The \HINT\ 
-format, described in \cite{MR:format}, was designed with two
-objectives: being able to support reflowing pages using the \TeX\
-typesetting engine and making it simple to use it as output format of
-the \TeX\ programm.  The present book tries to convince its readers
-that the latter claim is true.  To this end, this book implements a
-version of \TeX\ that produces \HINT\ output---to be precise: a short
-format \HINT\ file.
+If the available-space list is empty, i.e., if |avail==null|,
+we try first to increase |mem_end|. If that cannot be done, i.e., if
+|mem_end==mem_max|, we try to decrease |hi_mem_min|. If that cannot be
+done, i.e., if |hi_mem_min==lo_mem_max+1|, we have to quit.
 
-The book is written as a literate program\cite{Knuth:lp} using ``The
-\.{CWEB} System of Structured Documentation''\cite{Knuth:cweb}.  The
-largest part of this program is, of course, \TeX\cite{Knuth:tex}
-itself.  Therefore a significant part of Hi\TeX\ consists of
-modifications of the \TeX\ source code, which itself is written as a
-literate program using ``The \.{WEB} System of Structured
-Documentation''\cite{Knuth:WEB}.  The tiny, but significant,
-difference between \.{WEB}\index{WEB+{\tt WEB}}
-and \.{CWEB}\index{CWEB+{\tt CWEB}} is the transition from
-\Pascal\ to \CEE/ as target language. To bridge the gap between
-\.{WEB} and \.{CWEB}, Hi\TeX\ is not based on the original \.{WEB}
-implementation of \TeX\ but on the \.{CWEB} implementation of \TeX\
-as described in~\cite{MR:webtocweb} and~\cite{MR:web2w}. 
-Further, it does not use the plain {\tt ctex.w} translation of {\tt tex.web}
-but the {\tt ktex.w} file which extends \TeX\ with
- the features of $\epsilon$-\TeX, the file searching
-mechanisms of the {\tt kpathsearch} library, and the command line
-conventions of \TeX\ Live.
+ at p static pointer get_avail(void) /*single-word node allocation*/
+{@+pointer p; /*the new node being got*/
+p=avail; /*get top location in the |avail| stack*/
+if (p!=null) avail=link(avail); /*and pop it off*/
+else if (mem_end < mem_max)  /*or go into virgin territory*/
+  {@+incr(mem_end);p=mem_end;
+  }
+else{@+decr(hi_mem_min);p=hi_mem_min;
+  if (hi_mem_min <= lo_mem_max)
+    {@+runaway(); /*if memory is exhausted, display possible runaway text*/
+    overflow("main memory size", mem_max+1-mem_min);
+       /*quit; all one-word nodes are busy*/
+@:TeX capacity exceeded main memory size}{\quad main memory size@>
+    }
+  }
+link(p)=null; /*provide an oft-desired initialization of the new node*/
+#ifdef @!STAT
+incr(dyn_used);
+#endif
+@; /*maintain statistics*/
+return p;
+}
 
-To accomplish modifications of a \.{CWEB} file, the \.{CWEB} tools
-support the use of ``change files''.  These change files are lists of
-code changes optionally embellished with explanatory text.  Each code
-change consists of two parts: a literal copy of the original source
-code followed by the replacement text.  When a \.{CWEB} tool applies
-such a change file to a cweb file, it will read both files
-sequentially and applies the code changes in the order given: Whenever
-it finds a section in the \.{CWEB} file that matches the first part of
-the current code change, it will replace it by the second part of the
-code change, and advance to the next code change.
+@ Conversely, a one-word node is recycled by calling |free_avail|.
+This routine is part of \TeX's ``inner loop,'' so we want it to be fast.
+@^inner loop@>
 
-The present book makes an attempt to present these code changes in
-``literate programming style'' and had to overcome two obstacles:
-First, in a literate program, the exposition determines the order of
-appearance of the code sections; and second, the tools that generate
-the documentation from a \.{CWEB} file are not able to generate
-documentation for a change file.
+ at d free_avail(A)  /*single-word node liberation*/
+  {@+link(A)=avail;avail=A;
+  decr_dyn_used;
+  }
 
-The first problem can be solved by using the program {\tt
-tie}\cite{kg:tie}\cite{jg:ctie}.  It allows splitting a single change
-file into multiple change files, and while within each change file,
-the order of changes is still determined by the original cweb file,
-changes that belong together can be grouped into separate files.
+@ There's also a |fast_get_avail| routine, which saves the procedure-call
+overhead at the expense of extra programming. This routine is used in
+the places that would otherwise account for the most calls of |get_avail|.
+@^inner loop@>
 
-The second problem is solved by a simple preprocessor, that converts
-change files into cweb files which then can be converted into
-\TeX. With the help of some modifications of the macros in {\tt
-cwebmac.tex} these \TeX\ files are used to present change files in
-this book.
+ at d fast_get_avail(A) @t@>@;@/
+  {@+A=avail; /*avoid |get_avail| if possible, to save time*/
+  if (A==null) A=get_avail();
+  else{@+avail=link(A);link(A)=null;
+        incr_dyn_used;
+    }
+  }
 
-Let's look at an examples to explain and illustrate the presentation
-of code changes in this book: the {\tt display\_node.ch} change file.
+@ The procedure |flush_list(p)| frees an entire linked list of
+one-word nodes that starts at position |p|.
+@^inner loop@>
 
-\subsection{The Function |display_node|}
-It is the purpose of the {\tt display\_node.ch} change file to make
-the \TeX\ code contained in the section ``\<Display node |p|>''
-available to other parts of Hi\TeX\ as a function. 
-The function is then used to display debugging output.
+ at p static void flush_list(pointer @!p) /*makes list of single-word nodes
+  available*/
+{@+pointer @!q, @!r; /*list traversers*/
+if (p!=null)
+  {@+r=p;
+  @/do at +{q=r;r=link(r);
+#ifdef @!STAT
+decr(dyn_used);
+#endif
+  }@+ while (!(r==null)); /*now |q| is the last node on the list*/
+  link(q)=avail;avail=p;
+  }
+}
 
-This requires the following changes:
+@ The available-space list that keeps track of the variable-size portion
+of |mem| is a nonempty, doubly-linked circular list of empty nodes,
+pointed to by the roving pointer |rover|.
 
-\changestyle{displaynode.tex}
+Each empty node has size 2 or more; the first word contains the special
+value |max_halfword| in its |link| field and the size in its |info| field;
+the second word contains the two pointers for double linking.
 
-As you can see, the two parts of a code change are enclosed in square brackets
-where the opening top bracket is labeled {\it old\/} or {\it new\/}.
-While a full understanding of these code changes requires a look at the original \TeX\ code,
-at least they document what was done and why.
+Each nonempty node also has size 2 or more. Its first word is of type
+|two_halves|\kern-1pt, and its |link| field is never equal to |max_halfword|.
+Otherwise there is complete flexibility with respect to the contents
+of its other fields and its other words.
 
-There is still one thing missing before we can use the |display_node| 
-function in the {\tt hitex.c} file we are about to generate: 
-we need an |extern| declaration of |display_node|.
-In fact, the Hi\TeX\ program contains a whole bunch of functions 
-that will need access to \TeX's internals and the most readable 
-and convenient way to gain this access is a header file.
+(We require |mem_max < max_halfword| because terrible things can happen
+when |max_halfword| appears in the |link| field of a nonempty node.)
 
-Generating such a header file can be accomplished by using the {\tt -h}
-and {\tt -e} options of the {\tt web2w} program when converting the {\tt WEB}
-source of \TeX\ to its {\tt cweb} source. We just need to modify the 
-process slightly for our purposes.
+ at d empty_flag max_halfword /*the |link| of an empty variable-size node*/
+ at d is_empty(A) (link(A)==empty_flag) /*tests for empty node*/
+ at d node_size(A) info(A) /*the size field in empty variable-size nodes*/
+ at d llink(A) info(A+1) /*left link in doubly-linked list of empty nodes*/
+ at d rlink(A) link(A+1) /*right link in doubly-linked list of empty nodes*/
 
-{
-\changestyle{types.tex}
+@<Glob...@>=
+static pointer @!rover; /*points to some node in the list of empties*/
+
+@ A call to |get_node| with argument |s| returns a pointer to a new node
+of size~|s|, which must be 2~or more. The |link| field of the first word
+of this new node is set to null. An overflow stop occurs if no suitable
+space exists.
+
+If |get_node| is called with $s=2^{30}$, it simply merges adjacent free
+areas and returns the value |max_halfword|.
+
+ at p static pointer get_node(int @!s) /*variable-size node allocation*/
+{@+
+pointer p; /*the node currently under inspection*/
+pointer @!q; /*the node physically after node |p|*/
+int @!r; /*the newly allocated node, or a candidate for this honor*/
+int @!t; /*temporary register*/
+restart: p=rover; /*start at some free node in the ring*/
+@/do at +{@<Try to allocate within node |p| and its physical successors, and |goto found|
+if allocation was possible@>;
+@^inner loop@>
+p=rlink(p); /*move to the next node in the ring*/
+}@+ while (!(p==rover)); /*repeat until the whole list has been traversed*/
+if (s==010000000000)
+  {@+return max_halfword;
+  }
+if (lo_mem_max+2 < hi_mem_min) if (lo_mem_max+2 <= mem_bot+max_halfword)
+  @<Grow more variable-size memory and |goto restart|@>;
+overflow("main memory size", mem_max+1-mem_min);
+   /*sorry, nothing satisfactory is left*/
+@:TeX capacity exceeded main memory size}{\quad main memory size@>
+found: link(r)=null; /*this node is now nonempty*/
+#ifdef @!STAT
+var_used=var_used+s; /*maintain usage statistics*/
+#endif
+@;@/
+return r;
 }
 
+@ The lower part of |mem| grows by 1000 words at a time, unless
+we are very close to going under. When it grows, we simply link
+a new node into the available-space list. This method of controlled
+growth helps to keep the |mem| usage consecutive when \TeX\ is
+implemented on ``virtual memory'' systems.
+@^virtual memory@>
 
-\section{Modifying \TeX}\label{modifyingTeX}
-In this section, we explain the different change files that modify \TeX.
-Larger changes are accomplished by replacing entire functions.
+@<Grow more variable-size memory and |goto restart|@>=
+{@+if (hi_mem_min-lo_mem_max >= 1998) t=lo_mem_max+1000;
+else t=lo_mem_max+1+(hi_mem_min-lo_mem_max)/2;
+   /*|lo_mem_max+2 <= t < hi_mem_min|*/
+p=llink(rover);q=lo_mem_max;rlink(p)=q;llink(rover)=q;@/
+if (t > mem_bot+max_halfword) t=mem_bot+max_halfword;
+rlink(q)=rover;llink(q)=p;link(q)=empty_flag;node_size(q)=t-lo_mem_max;@/
+lo_mem_max=t;link(lo_mem_max)=null;info(lo_mem_max)=null;
+rover=q;goto restart;
+}
 
-\subsection{The |banner|}
-Now that we are about to change the behaviour of \TeX\ significantly,
-we have to give the program a new banner.
+@ Empirical tests show that the routine in this section performs a
+node-merging operation about 0.75 times per allocation, on the average,
+after which it finds that |r > p+1| about 95\pct! of the time.
 
-{
-\changestyle{banner.tex}
+@<Try to allocate...@>=
+q=p+node_size(p); /*find the physical successor*/
+@^inner loop@>
+while (is_empty(q))  /*merge node |p| with node |q|*/
+  {@+t=rlink(q);
+  if (q==rover) rover=t;
+  llink(t)=llink(q);rlink(llink(q))=t;@/
+  q=q+node_size(q);
+  }
+r=q-s;
+if (r > p+1) @<Allocate from the top of node |p| and |goto found|@>;
+if (r==p) if (rlink(p)!=p)
+  @<Allocate entire node |p| and |goto found|@>;
+node_size(p)=q-p /*reset the size in case it grew*/
+
+@ @<Allocate from the top...@>=
+{@+node_size(p)=r-p; /*store the remaining size*/
+@^inner loop@>
+rover=p; /*start searching here next time*/
+goto found;
 }
 
-\subsection{The |main| Program}
-We add two function calls to \TeX's |main| program: 
-|hint_open|, and |hint_close|.
+@ Here we delete node |p| from the ring, and let |rover| rove around.
 
-{
-\changestyle{main.tex}
+@<Allocate entire...@>=
+{@+rover=rlink(p);t=llink(p);
+llink(rover)=t;rlink(t)=rover;
+goto found;
 }
-The functions to open and close the \HINT\ file follow in 
-section~\secref{output}. 
 
+@ Conversely, when some variable-size node |p| of size |s| is no longer needed,
+the operation |free_node(p, s)| will make its words available, by inserting
+|p| as a new empty node just before where |rover| now points.
+@^inner loop@>
 
-\subsection{The Command Line}
-Hi\TeX\ has a few additional command line options that we define next.
+ at p static void free_node(pointer @!p, halfword @!s) /*variable-size node
+  liberation*/
+{@+pointer q; /*|llink(rover)|*/
+node_size(p)=s;link(p)=empty_flag;
+q=llink(rover);llink(p)=q;rlink(p)=rover; /*set both links*/
+llink(rover)=p;rlink(q)=p; /*insert |p| into the ring*/
+#ifdef @!STAT
+var_used=var_used-s;
+#endif
+@; /*maintain statistics*/
+}
 
+@ Just before \.{INITEX} writes out the memory, it sorts the doubly linked
+available space list. The list is probably very short at such times, so a
+simple insertion sort is used. The smallest available location will be
+pointed to by |rover|, the next-smallest by |rlink(rover)|, etc.
+
+ at p
+#ifdef @!INIT
+static void sort_avail(void) /*sorts the available variable-size nodes
+  by location*/
+{@+pointer p, @!q, @!r; /*indices into |mem|*/
+pointer @!old_rover; /*initial |rover| setting*/
+p=get_node(010000000000); /*merge adjacent free areas*/
+p=rlink(rover);rlink(rover)=max_halfword;old_rover=rover;
+while (p!=old_rover) @<Sort \(p)|p| into the list starting at |rover| and advance
+|p| to |rlink(p)|@>;
+p=rover;
+while (rlink(p)!=max_halfword)
+  {@+llink(rlink(p))=p;p=rlink(p);
+  }
+rlink(p)=rover;llink(rover)=p;
+}
+#endif
+
+@ The following |while | loop is guaranteed to
+terminate, since the list that starts at
+|rover| ends with |max_halfword| during the sorting procedure.
+
+@<Sort \(p)|p|...@>=
+if (p < rover)
+  {@+q=p;p=rlink(q);rlink(q)=rover;rover=q;
+  }
+else{@+q=rover;
+  while (rlink(q) < p) q=rlink(q);
+  r=rlink(p);rlink(p)=rlink(q);rlink(q)=p;p=r;
+  }
+
+@* Data structures for boxes and their friends.
+From the computer's standpoint, \TeX's chief mission is to create
+horizontal and vertical lists. We shall now investigate how the elements
+of these lists are represented internally as nodes in the dynamic memory.
+
+A horizontal or vertical list is linked together by |link| fields in
+the first word of each node. Individual nodes represent boxes, glue,
+penalties, or special things like discretionary hyphens; because of this
+variety, some nodes are longer than others, and we must distinguish different
+kinds of nodes. We do this by putting a `|type|' field in the first word,
+together with the link and an optional `|subtype|'.
+
+ at d type(A) mem[A].hh.b0 /*identifies what kind of node this is*/
+ at d subtype(A) mem[A].hh.b1 /*secondary identification in some cases*/
+
+@ A |@!char_node|, which represents a single character, is the most important
+kind of node because it accounts for the vast majority of all boxes.
+Special precautions are therefore taken to ensure that a |char_node| does
+not take up much memory space. Every such node is one word long, and in fact
+it is identifiable by this property, since other kinds of nodes have at least
+two words, and they appear in |mem| locations less than |hi_mem_min|.
+This makes it possible to omit the |type| field in a |char_node|, leaving
+us room for two bytes that identify a |font| and a |character| within
+that font.
+
+Note that the format of a |char_node| allows for up to 256 different
+fonts and up to 256 characters per font; but most implementations will
+probably limit the total number of fonts to fewer than 75 per job,
+and most fonts will stick to characters whose codes are
+less than 128 (since higher codes
+are more difficult to access on most keyboards).
+
+Extensions of \TeX\ intended for oriental languages will need even more
+than $256\times256$ possible characters, when we consider different sizes
+@^oriental characters@>@^Chinese characters@>@^Japanese characters@>
+and styles of type.  It is suggested that Chinese and Japanese fonts be
+handled by representing such characters in two consecutive |char_node|
+entries: The first of these has |font==font_base|, and its |link| points
+to the second;
+the second identifies the font and the character dimensions.
+The saving feature about oriental characters is that most of them have
+the same box dimensions. The |character| field of the first |char_node|
+is a ``\\{charext}'' that distinguishes between graphic symbols whose
+dimensions are identical for typesetting purposes. (See the \MF\ manual.)
+Such an extension of \TeX\ would not be difficult; further details are
+left to the reader.
+
+In order to make sure that the |character| code fits in a quarterword,
+\TeX\ adds the quantity |min_quarterword| to the actual code.
+
+Character nodes appear only in horizontal lists, never in vertical lists.
+
+ at d is_char_node(A) (A >= hi_mem_min)
+   /*does the argument point to a |char_node|?*/
+ at d font(A) type(A) /*the font code in a |char_node|*/
+ at d character(A) subtype(A) /*the character code in a |char_node|*/
+
+@ An |hlist_node| stands for a box that was made from a horizontal list.
+Each |hlist_node| is seven words long, and contains the following fields
+(in addition to the mandatory |type| and |link|, which we shall not
+mention explicitly when discussing the other node types): The |height| and
+|width| and |depth| are scaled integers denoting the dimensions of the
+box.  There is also a |shift_amount| field, a scaled integer indicating
+how much this box should be lowered (if it appears in a horizontal list),
+or how much it should be moved to the right (if it appears in a vertical
+list). There is a |list_ptr| field, which points to the beginning of the
+list from which this box was fabricated; if |list_ptr| is |null|, the box
+is empty. Finally, there are three fields that represent the setting of
+the glue:  |glue_set(p)| is a word of type |glue_ratio| that represents
+the proportionality constant for glue setting; |glue_sign(p)| is
+|stretching| or |shrinking| or |normal| depending on whether or not the
+glue should stretch or shrink or remain rigid; and |glue_order(p)|
+specifies the order of infinity to which glue setting applies (|normal|,
+|fil|, |fill|, or |filll|). The |subtype| field is not used.
+
+ at d hlist_node 0 /*|type| of hlist nodes*/
+ at d box_node_size 9 /*number of words to allocate for a box, set, or pack node*/
+ at d width_offset 1 /*position of |width| field in a box node*/
+ at d depth_offset 2 /*position of |depth| field in a box node*/
+ at d height_offset 3 /*position of |height| field in a box node*/
+ at d width(A) mem[A+width_offset].sc /*width of the box, in sp*/
+ at d depth(A) mem[A+depth_offset].sc /*depth of the box, in sp*/
+ at d height(A) mem[A+height_offset].sc /*height of the box, in sp*/
+ at d shift_amount(A) mem[A+4].sc /*repositioning distance, in sp*/
+ at d list_offset 5 /*position of |list_ptr| field in a box node*/
+ at d list_ptr(A) link(A+list_offset) /*beginning of the list inside the box*/
+ at d glue_order(A) subtype(A+list_offset) /*applicable order of infinity*/
+ at d glue_sign(A) type(A+list_offset) /*stretching or shrinking*/
+ at d normal 0 /*the most common case when several cases are named*/
+ at d stretching 1 /*glue setting applies to the stretch components*/
+ at d shrinking 2 /*glue setting applies to the shrink components*/
+ at d glue_offset 6 /*position of |glue_set| in a box node*/
+ at d glue_set(A) mem[A+glue_offset].gr
+   /*a word of type |glue_ratio| for glue setting*/
+
+@ The |new_null_box| function returns a pointer to an |hlist_node| in
+which all subfields have the values corresponding to `\.{\\hbox\{\}}'.
+(The |subtype| field is set to |min_quarterword|, for historic reasons
+that are no longer relevant.)
+
+ at p static pointer new_null_box(void) /*creates a new box node*/
+{@+pointer p; /*the new node*/
+p=get_node(box_node_size);type(p)=hlist_node;
+subtype(p)=min_quarterword;
+width(p)=0;depth(p)=0;height(p)=0;shift_amount(p)=0;list_ptr(p)=null;
+glue_sign(p)=normal;glue_order(p)=normal;set_glue_ratio_zero(glue_set(p));
+return p;
+}
+
+@ A |vlist_node| is like an |hlist_node| in all respects except that it
+contains a vertical list.
+
+ at d vlist_node 1 /*|type| of vlist nodes*/
+
+@ A |rule_node| stands for a solid black rectangle; it has |width|,
+|depth|, and |height| fields just as in an |hlist_node|. However, if
+any of these dimensions is $-2^{30}$, the actual value will be determined
+by running the rule up to the boundary of the innermost enclosing box.
+This is called a ``running dimension.'' The |width| is never running in
+an hlist; the |height| and |depth| are never running in a~vlist.
+
+ at d rule_node 2 /*|type| of rule nodes*/
+ at d rule_node_size 4 /*number of words to allocate for a rule node*/
+ at d null_flag -010000000000 /*$-2^{30}$, signifies a missing item*/
+ at d is_running(A) (A==null_flag) /*tests for a running dimension*/
+
+@ A new rule node is delivered by the |new_rule| function. It
+makes all the dimensions ``running,'' so you have to change the
+ones that are not allowed to run.
+
+ at p static pointer new_rule(void)
+{@+pointer p; /*the new node*/
+p=get_node(rule_node_size);type(p)=rule_node;
+subtype(p)=0; /*the |subtype| is not used*/
+width(p)=null_flag;depth(p)=null_flag;height(p)=null_flag;
+return p;
+}
+
+@ Insertions are represented by |ins_node| records, where the |subtype|
+indicates the corresponding box number. For example, `\.{\\insert 250}'
+leads to an |ins_node| whose |subtype| is |250+min_quarterword|.
+The |height| field of an |ins_node| is slightly misnamed; it actually holds
+the natural height plus depth of the vertical list being inserted.
+The |depth| field holds the |split_max_depth| to be used in case this
+insertion is split, and the |split_top_ptr| points to the corresponding
+|split_top_skip|. The |float_cost| field holds the |floating_penalty| that
+will be used if this insertion floats to a subsequent page after a
+split insertion of the same class.  There is one more field, the
+|ins_ptr|, which points to the beginning of the vlist for the insertion.
+
+ at d ins_node 3 /*|type| of insertion nodes*/
+ at d ins_node_size 5 /*number of words to allocate for an insertion*/
+ at d float_cost(A) mem[A+1].i /*the |floating_penalty| to be used*/
+ at d ins_ptr(A) info(A+4) /*the vertical list to be inserted*/
+ at d split_top_ptr(A) link(A+4) /*the |split_top_skip| to be used*/
+
+@ A |mark_node| has a |mark_ptr| field that points to the reference count
+of a token list that contains the user's \.{\\mark} text.
+This field occupies a full word instead of a halfword, because
+there's nothing to put in the other halfword; it is easier in \PASCAL\ to
+use the full word than to risk leaving garbage in the unused half.
+
+ at d mark_node 4 /*|type| of a mark node*/
+ at d small_node_size 2 /*number of words to allocate for most node types*/
+ at d mark_ptr(A) mem[A+1].i /*head of the token list for a mark*/
+
+@ An |adjust_node|, which occurs only in horizontal lists,
+specifies material that will be moved out into the surrounding
+vertical list; i.e., it is used to implement \TeX's `\.{\\vadjust}'
+operation.  The |adjust_ptr| field points to the vlist containing this
+material.
+
+ at d adjust_node 5 /*|type| of an adjust node*/
+ at d adjust_ptr(A) mark_ptr(A) /*vertical list to be moved out of horizontal list*/
+
+@ A |ligature_node|, which occurs only in horizontal lists, specifies
+a character that was fabricated from the interaction of two or more
+actual characters.  The second word of the node, which is called the
+|lig_char| word, contains |font| and |character| fields just as in a
+|char_node|. The characters that generated the ligature have not been
+forgotten, since they are needed for diagnostic messages and for
+hyphenation; the |lig_ptr| field points to a linked list of character
+nodes for all original characters that have been deleted. (This list
+might be empty if the characters that generated the ligature were
+retained in other nodes.)
+
+The |subtype| field is 0, plus 2 and/or 1 if the original source of the
+ligature included implicit left and/or right boundaries.
+
+ at d ligature_node 6 /*|type| of a ligature node*/
+ at d lig_char(A) A+1 /*the word where the ligature is to be found*/
+ at d lig_ptr(A) link(lig_char(A)) /*the list of characters*/
+
+@ The |new_ligature| function creates a ligature node having given
+contents of the |font|, |character|, and |lig_ptr| fields. We also have
+a |new_lig_item| function, which returns a two-word node having a given
+|character| field. Such nodes are used for temporary processing as ligatures
+are being created.
+
+ at p static pointer new_ligature(quarterword @!f, quarterword @!c, pointer @!q)
+{@+pointer p; /*the new node*/
+p=get_node(small_node_size);type(p)=ligature_node;
+font(lig_char(p))=f;character(lig_char(p))=c;lig_ptr(p)=q;
+subtype(p)=0;return p;
+}
+@#
+static pointer new_lig_item(quarterword @!c)
+{@+pointer p; /*the new node*/
+p=get_node(small_node_size);character(p)=c;lig_ptr(p)=null;
+return p;
+}
+
+@ A |disc_node|, which occurs only in horizontal lists, specifies a
+``dis\-cretion\-ary'' line break. If such a break occurs at node |p|, the text
+that starts at |pre_break(p)| will precede the break, the text that starts at
+|post_break(p)| will follow the break, and text that appears in the next
+|replace_count(p)| nodes will be ignored. For example, an ordinary
+discretionary hyphen, indicated by `\.{\\-}', yields a |disc_node| with
+|pre_break| pointing to a |char_node| containing a hyphen, |post_break==null|,
+and |replace_count==0|. All three of the discretionary texts must be
+lists that consist entirely of character, kern, box, rule, and ligature nodes.
+
+If |pre_break(p)==null|, the |ex_hyphen_penalty| will be charged for this
+break.  Otherwise the |hyphen_penalty| will be charged.  The texts will
+actually be substituted into the list by the line-breaking algorithm if it
+decides to make the break, and the discretionary node will disappear at
+that time; thus, the output routine sees only discretionaries that were
+not chosen.
+
+ at d disc_node 7 /*|type| of a discretionary node*/
+ at d replace_count(A) (subtype(A)&0x7F) /*how many subsequent nodes to replace*/
+ at d set_replace_count(A,B) (subtype(A)=(B)&0x7F)
+ at d set_auto_disc(A) (subtype(A)|=0x80)
+ at d is_auto_disc(A) (subtype(A)&0x80)
+ at d pre_break(A) llink(A) /*text that precedes a discretionary break*/
+ at d post_break(A) rlink(A) /*text that follows a discretionary break*/
+
+ at p static pointer new_disc(void) /*creates an empty |disc_node|*/
+{@+pointer p; /*the new node*/
+p=get_node(small_node_size);type(p)=disc_node;
+set_replace_count(p,0);pre_break(p)=null;post_break(p)=null;
+return p;
+}
+
+@ A |whatsit_node| is a wild card reserved for extensions to \TeX. The
+|subtype| field in its first word says what `\\{whatsit}' it is, and
+implicitly determines the node size (which must be 2 or more) and the
+format of the remaining words. When a |whatsit_node| is encountered
+in a list, special actions are invoked; knowledgeable people who are
+careful not to mess up the rest of \TeX\ are able to make \TeX\ do new
+things by adding code at the end of the program. For example, there
+might be a `\TeX nicolor' extension to specify different colors of ink,
+@^extensions to \TeX@>
+and the whatsit node might contain the desired parameters.
+
+The present implementation of \TeX\ treats the features associated with
+`\.{\\write}' and `\.{\\special}' as if they were extensions, in order to
+illustrate how such routines might be coded. We shall defer further
+discussion of extensions until the end of this program.
+
+ at d whatsit_node 8 /*|type| of special extension nodes*/
+
+@ A |math_node|, which occurs only in horizontal lists, appears before and
+after mathematical formulas. The |subtype| field is |before| before the
+formula and |after| after it. There is a |width| field, which represents
+the amount of surrounding space inserted by \.{\\mathsurround}.
+
+ at d math_node 9 /*|type| of a math node*/
+ at d before 0 /*|subtype| for math node that introduces a formula*/
+ at d after 1 /*|subtype| for math node that winds up a formula*/
+
+ at p static pointer new_math(scaled @!w, small_number @!s)
+{@+pointer p; /*the new node*/
+p=get_node(small_node_size);type(p)=math_node;
+subtype(p)=s;width(p)=w;return p;
+}
+
+@ \TeX\ makes use of the fact that |hlist_node|, |vlist_node|,
+|rule_node|, |ins_node|, |mark_node|, |adjust_node|, |ligature_node|,
+|disc_node|, |whatsit_node|, and |math_node| are at the low end of the
+type codes, by permitting a break at glue in a list if and only if the
+|type| of the previous node is less than |math_node|. Furthermore, a
+node is discarded after a break if its type is |math_node| or~more.
+
+ at d precedes_break(A) (type(A) < math_node)
+ at d non_discardable(A) (type(A) < math_node)
+
+@ A |glue_node| represents glue in a list. However, it is really only
+a pointer to a separate glue specification, since \TeX\ makes use of the
+fact that many essentially identical nodes of glue are usually present.
+If |p| points to a |glue_node|, |glue_ptr(p)| points to
+another packet of words that specify the stretch and shrink components, etc.
+
+Glue nodes also serve to represent leaders; the |subtype| is used to
+distinguish between ordinary glue (which is called |normal|) and the three
+kinds of leaders (which are called |a_leaders|, |c_leaders|, and |x_leaders|).
+The |leader_ptr| field points to a rule node or to a box node containing the
+leaders; it is set to |null| in ordinary glue nodes.
+
+Many kinds of glue are computed from \TeX's ``skip'' parameters, and
+it is helpful to know which parameter has led to a particular glue node.
+Therefore the |subtype| is set to indicate the source of glue, whenever
+it originated as a parameter. We will be defining symbolic names for the
+parameter numbers later (e.g., |line_skip_code==0|, |baseline_skip_code==1|,
+etc.); it suffices for now to say that the |subtype| of parametric glue
+will be the same as the parameter number, plus~one.
+
+In math formulas there are two more possibilities for the |subtype| in a
+glue node: |mu_glue| denotes an \.{\\mskip} (where the units are scaled \.{mu}
+instead of scaled \.{pt}); and |cond_math_glue| denotes the `\.{\\nonscript}'
+feature that cancels the glue node immediately following if it appears
+in a subscript.
+
+ at d glue_node 10 /*|type| of node that points to a glue specification*/
+ at d cond_math_glue 98 /*special |subtype| to suppress glue in the next node*/
+ at d mu_glue 99 /*|subtype| for math glue*/
+ at d a_leaders 100 /*|subtype| for aligned leaders*/
+ at d c_leaders 101 /*|subtype| for centered leaders*/
+ at d x_leaders 102 /*|subtype| for expanded leaders*/
+ at d glue_ptr(A) llink(A) /*pointer to a glue specification*/
+ at d leader_ptr(A) rlink(A) /*pointer to box or rule node for leaders*/
+
+@ A glue specification has a halfword reference count in its first word,
+@^reference counts@>
+representing |null| plus the number of glue nodes that point to it (less one).
+Note that the reference count appears in the same position as
+the |link| field in list nodes; this is the field that is initialized
+to |null| when a node is allocated, and it is also the field that is flagged
+by |empty_flag| in empty nodes.
+
+Glue specifications also contain three |scaled| fields, for the |width|,
+|stretch|, and |shrink| dimensions. Finally, there are two one-byte
+fields called |stretch_order| and |shrink_order|; these contain the
+orders of infinity (|normal|, |fil|, |fill|, or |filll|)
+corresponding to the stretch and shrink values.
+
+ at d glue_spec_size 4 /*number of words to allocate for a glue specification*/
+ at d glue_ref_count(A) link(A) /*reference count of a glue specification*/
+ at d stretch(A) mem[A+2].sc /*the stretchability of this glob of glue*/
+ at d shrink(A) mem[A+3].sc /*the shrinkability of this glob of glue*/
+ at d stretch_order(A) type(A) /*order of infinity for stretching*/
+ at d shrink_order(A) subtype(A) /*order of infinity for shrinking*/
+ at d fil 1 /*first-order infinity*/
+ at d fill 2 /*second-order infinity*/
+ at d filll 3 /*third-order infinity*/
+
+@<Types...@>=
+typedef int8_t glue_ord; /*infinity to the 0, 1, 2, or 3 power*/
+
+@ Here is a function that returns a pointer to a copy of a glue spec.
+The reference count in the copy is |null|, because there is assumed
+to be exactly one reference to the new specification.
+
+ at p static pointer new_spec(pointer @!p) /*duplicates a glue specification*/
+{@+pointer q; /*the new spec*/
+q=get_node(glue_spec_size);@/
+mem[q]=mem[p];glue_ref_count(q)=null;@/
+width(q)=width(p);stretch(q)=stretch(p);shrink(q)=shrink(p);
+return q;
+}
+
+@ And here's a function that creates a glue node for a given parameter
+identified by its code number; for example,
+|new_param_glue(line_skip_code)| returns a pointer to a glue node for the
+current \.{\\lineskip}.
+
+ at p static pointer new_param_glue(small_number @!n)
+{@+pointer p; /*the new node*/
+pointer @!q; /*the glue specification*/
+p=get_node(small_node_size);type(p)=glue_node;subtype(p)=n+1;
+leader_ptr(p)=null;@/
+q=@<Current |mem| equivalent of glue parameter number |n|@>@t@>;
+glue_ptr(p)=q;incr(glue_ref_count(q));
+return p;
+}
+
+@ Glue nodes that are more or less anonymous are created by |new_glue|,
+whose argument points to a glue specification.
+
+ at p static pointer new_glue(pointer @!q)
+{@+pointer p; /*the new node*/
+p=get_node(small_node_size);type(p)=glue_node;subtype(p)=normal;
+leader_ptr(p)=null;glue_ptr(p)=q;incr(glue_ref_count(q));
+return p;
+}
+
+@ Still another subroutine is needed: This one is sort of a combination
+of |new_param_glue| and |new_glue|. It creates a glue node for one of
+the current glue parameters, but it makes a fresh copy of the glue
+specification, since that specification will probably be subject to change,
+while the parameter will stay put. The global variable |temp_ptr| is
+set to the address of the new spec.
+
+ at p static pointer new_skip_param(small_number @!n)
+{@+pointer p; /*the new node*/
+temp_ptr=new_spec(@<Current |mem| equivalent of glue parameter...@>);
+p=new_glue(temp_ptr);glue_ref_count(temp_ptr)=null;subtype(p)=n+1;
+return p;
+}
+
+@ A |kern_node| has a |width| field to specify a (normally negative)
+amount of spacing. This spacing correction appears in horizontal lists
+between letters like A and V when the font designer said that it looks
+better to move them closer together or further apart. A kern node can
+also appear in a vertical list, when its `|width|' denotes additional
+spacing in the vertical direction. The |subtype| is either |normal| (for
+kerns inserted from font information or math mode calculations) or |explicit|
+(for kerns inserted from \.{\\kern} and \.{\\/} commands) or |acc_kern|
+(for kerns inserted from non-math accents) or |mu_glue| (for kerns
+inserted from \.{\\mkern} specifications in math formulas).
+
+ at d kern_node 11 /*|type| of a kern node*/
+ at d explicit 1 /*|subtype| of kern nodes from \.{\\kern} and \.{\\/}*/
+ at d acc_kern 2 /*|subtype| of kern nodes from accents*/
+
+@ The |new_kern| function creates a kern node having a given width.
+
+ at p static pointer new_kern(scaled @!w)
+{@+pointer p; /*the new node*/
+p=get_node(small_node_size);type(p)=kern_node;
+subtype(p)=normal;
+width(p)=w;
+return p;
+}
+
+@ A |penalty_node| specifies the penalty associated with line or page
+breaking, in its |penalty| field. This field is a fullword integer, but
+the full range of integer values is not used: Any penalty | >= 10000| is
+treated as infinity, and no break will be allowed for such high values.
+Similarly, any penalty | <= -10000| is treated as negative infinity, and a
+break will be forced.
+
+ at d penalty_node 12 /*|type| of a penalty node*/
+ at d inf_penalty inf_bad /*``infinite'' penalty value*/
+ at d eject_penalty (-inf_penalty) /*``negatively infinite'' penalty value*/
+ at d penalty(A) mem[A+1].i /*the added cost of breaking a list here*/
+
+@ Anyone who has been reading the last few sections of the program will
+be able to guess what comes next.
+
+ at p static pointer new_penalty(int @!m)
+{@+pointer p; /*the new node*/
+p=get_node(small_node_size);type(p)=penalty_node;
+subtype(p)=0; /*the |subtype| is not used*/
+penalty(p)=m;return p;
+}
+
+@ You might think that we have introduced enough node types by now. Well,
+almost, but there is one more: An |unset_node| has nearly the same format
+as an |hlist_node| or |vlist_node|; it is used for entries in \.{\\halign}
+or \.{\\valign} that are not yet in their final form, since the box
+dimensions are their ``natural'' sizes before any glue adjustment has been
+made. The |glue_set| word is not present; instead, we have a |glue_stretch|
+field, which contains the total stretch of order |glue_order| that is
+present in the hlist or vlist being boxed.
+Similarly, the |shift_amount| field is replaced by a |glue_shrink| field,
+containing the total shrink of order |glue_sign| that is present.
+The |subtype| field is called |span_count|; an unset box typically
+contains the data for |qo(span_count)+1| columns.
+Unset nodes will be changed to box nodes when alignment is completed.
+
+ at d unset_node 13 /*|type| for an unset node*/
+ at d unset_set_node 32 /*|type| for an unset |set_node|*/
+ at d unset_pack_node 33 /*|type| for an unset |pack_node|*/
+ at d glue_stretch(A) mem[A+glue_offset].sc /*total stretch in an unset node*/
+ at d glue_shrink(A) shift_amount(A) /*total shrink in an unset node*/
+ at d span_count(A) subtype(A) /*indicates the number of spanned columns*/
+
+@ In fact, there are still more types coming. When we get to math formula
+processing we will see that a |style_node| has |type==14|; and a number
+of larger type codes will also be defined, for use in math mode only.
+
+@ Warning: If any changes are made to these data structure layouts, such as
+changing any of the node sizes or even reordering the words of nodes,
+the |copy_node_list| procedure and the memory initialization code
+below may have to be changed. Such potentially dangerous parts of the
+program are listed in the index under `data structure assumptions'.
+@!@^data structure assumptions@>
+However, other references to the nodes are made symbolically in terms of
+the \.{WEB} macro definitions above, so that format changes will leave
+\TeX's other algorithms intact.
+@^system dependencies@>
+
+@* Memory layout.
+Some areas of |mem| are dedicated to fixed usage, since static allocation is
+more efficient than dynamic allocation when we can get away with it. For
+example, locations |mem_bot| to |mem_bot+3| are always used to store the
+specification for glue that is `\.{0pt plus 0pt minus 0pt}'. The
+following macro definitions accomplish the static allocation by giving
+symbolic names to the fixed positions. Static variable-size nodes appear
+in locations |mem_bot| through |lo_mem_stat_max|, and static single-word nodes
+appear in locations |hi_mem_stat_min| through |mem_top|, inclusive. It is
+harmless to let |lig_trick| and |garbage| share the same location of |mem|.
+
+ at d zero_glue mem_bot /*specification for \.{0pt plus 0pt minus 0pt}*/
+ at d fil_glue zero_glue+glue_spec_size /*\.{0pt plus 1fil minus 0pt}*/
+ at d fill_glue fil_glue+glue_spec_size /*\.{0pt plus 1fill minus 0pt}*/
+ at d ss_glue fill_glue+glue_spec_size /*\.{0pt plus 1fil minus 1fil}*/
+ at d fil_neg_glue ss_glue+glue_spec_size /*\.{0pt plus -1fil minus 0pt}*/
+ at d lo_mem_stat_max fil_neg_glue+glue_spec_size-1 /*largest statically
+  allocated word in the variable-size |mem|*/
+@#
+ at d page_ins_head mem_top /*list of insertion data for current page*/
+ at d contrib_head mem_top-1 /*vlist of items not yet on current page*/
+ at d page_head mem_top-2 /*vlist for current page*/
+ at d temp_head mem_top-3 /*head of a temporary list of some kind*/
+ at d hold_head mem_top-4 /*head of a temporary list of another kind*/
+ at d adjust_head mem_top-5 /*head of adjustment list returned by |hpack|*/
+ at d active mem_top-7 /*head of active list in |line_break|, needs two words*/
+ at d align_head mem_top-8 /*head of preamble list for alignments*/
+ at d end_span mem_top-9 /*tail of spanned-width lists*/
+ at d omit_template mem_top-10 /*a constant token list*/
+ at d null_list mem_top-11 /*permanently empty list*/
+ at d lig_trick mem_top-12 /*a ligature masquerading as a |char_node|*/
+ at d garbage mem_top-12 /*used for scrap information*/
+ at d backup_head mem_top-13 /*head of token list built by |scan_keyword|*/
+ at d setpage_head mem_top-14 /*head of page template list build by |new_setpage_node|*/
+ at d max_page type(setpage_head) /* maximum page template number */
+ at d max_stream subtype(setpage_head) /* maximum stream number */
+ at d hi_mem_stat_min mem_top-14 /*smallest statically allocated word in
+  the one-word |mem|*/
+ at d hi_mem_stat_usage 15 /*the number of one-word nodes always present*/
+
+@ The following code gets |mem| off to a good start, when \TeX\ is
+initializing itself the slow~way.
+
+@<Local variables for init...@>=
+int @!k; /*index into |mem|, |eqtb|, etc.*/
+
+@ @<Initialize table entries...@>=
+for (k=mem_bot+1; k<=lo_mem_stat_max; k++) mem[k].sc=0;
+   /*all glue dimensions are zeroed*/
+@^data structure assumptions@>
+k=mem_bot;@+while (k <= lo_mem_stat_max)
+     /*set first words of glue specifications*/
+  {@+glue_ref_count(k)=null+1;
+  stretch_order(k)=normal;shrink_order(k)=normal;
+  k=k+glue_spec_size;
+  }
+stretch(fil_glue)=unity;stretch_order(fil_glue)=fil;@/
+stretch(fill_glue)=unity;stretch_order(fill_glue)=fill;@/
+stretch(ss_glue)=unity;stretch_order(ss_glue)=fil;@/
+shrink(ss_glue)=unity;shrink_order(ss_glue)=fil;@/
+stretch(fil_neg_glue)=-unity;stretch_order(fil_neg_glue)=fil;@/
+rover=lo_mem_stat_max+1;
+link(rover)=empty_flag; /*now initialize the dynamic memory*/
+node_size(rover)=1000; /*which is a 1000-word available node*/
+llink(rover)=rover;rlink(rover)=rover;@/
+lo_mem_max=rover+1000;link(lo_mem_max)=null;info(lo_mem_max)=null;@/
+for (k=hi_mem_stat_min; k<=mem_top; k++)
+  mem[k]=mem[lo_mem_max]; /*clear list heads*/
+@<Initialize the special list heads and constant nodes@>;
+avail=null;mem_end=mem_top;
+hi_mem_min=hi_mem_stat_min; /*initialize the one-word memory*/
+var_used=lo_mem_stat_max+1-mem_bot;dyn_used=hi_mem_stat_usage;
+   /*initialize statistics*/
+
+@ If \TeX\ is extended improperly, the |mem| array might get screwed up.
+For example, some pointers might be wrong, or some ``dead'' nodes might not
+have been freed when the last reference to them disappeared. Procedures
+|check_mem| and |search_mem| are available to help diagnose such
+problems. These procedures make use of two arrays called |is_free| and
+|was_free| that are present only if \TeX's debugging routines have
+been included. (You may want to decrease the size of |mem| while you
+@^debugging@>
+are debugging.)
+
+@<Glob...@>=
+#ifdef @!DEBUG
+static bool @!is_free0[mem_max-mem_min+1], *const @!is_free = @!is_free0-mem_min; /*free cells*/
+ at t\hskip10pt@>static bool @!was_free0[mem_max-mem_min+1], *const @!was_free = @!was_free0-mem_min;
+   /*previously free cells*/
+ at t\hskip10pt@>static pointer @!was_mem_end, @!was_lo_max, @!was_hi_min;
+   /*previous |mem_end|, |lo_mem_max|, and |hi_mem_min|*/
+ at t\hskip10pt@>static bool @!panicking; /*do we want to check memory constantly?*/
+#endif
+
+@ @<Set initial...@>=
+#ifdef @!DEBUG
+was_mem_end=mem_min; /*indicate that everything was previously free*/
+was_lo_max=mem_min;was_hi_min=mem_max;
+panicking=false;
+#endif
+
+@ Procedure |check_mem| makes sure that the available space lists of
+|mem| are well formed, and it optionally prints out all locations
+that are reserved now but were free the last time this procedure was called.
+
+ at p
+#ifdef @!DEBUG
+static void check_mem(bool @!print_locs)
+{@+ /*loop exits*/
+int p, @!q; /*current locations of interest in |mem|*/
+bool @!clobbered; /*is something amiss?*/
+for (p=mem_min; p<=lo_mem_max; p++) is_free[p]=false; /*you can probably
+  do this faster*/
+for (p=hi_mem_min; p<=mem_end; p++) is_free[p]=false; /*ditto*/
+@<Check single-word |avail| list@>;
+@<Check variable-size |avail| list@>;
+@<Check flags of unavailable nodes@>;
+if (print_locs) @<Print newly busy locations@>;
+for (p=mem_min; p<=lo_mem_max; p++) was_free[p]=is_free[p];
+for (p=hi_mem_min; p<=mem_end; p++) was_free[p]=is_free[p];
+   /*|was_free=is_free| might be faster*/
+was_mem_end=mem_end;was_lo_max=lo_mem_max;was_hi_min=hi_mem_min;
+}
+#endif
+
+@ @<Check single-word...@>=
+p=avail;q=null;clobbered=false;
+while (p!=null)
+  {@+if ((p > mem_end)||(p < hi_mem_min)) clobbered=true;
+  else if (is_free[p]) clobbered=true;
+  if (clobbered)
+    {@+print_nl("AVAIL list clobbered at ");
+ at .AVAIL list clobbered...@>
+    print_int(q);goto done1;
+    }
+  is_free[p]=true;q=p;p=link(q);
+  }
+done1:
+
+@ @<Check variable-size...@>=
+p=rover;q=null;clobbered=false;
+@/do at +{if ((p >= lo_mem_max)||(p < mem_min)) clobbered=true;
+  else if ((rlink(p) >= lo_mem_max)||(rlink(p) < mem_min)) clobbered=true;
+  else if (!(is_empty(p))||(node_size(p) < 2)||@|
+   (p+node_size(p) > lo_mem_max)||@|(llink(rlink(p))!=p)) clobbered=true;
+  if (clobbered)
+  {@+print_nl("Double-AVAIL list clobbered at ");
+  print_int(q);goto done2;
+  }
+for (q=p; q<=p+node_size(p)-1; q++)  /*mark all locations free*/
+  {@+if (is_free[q])
+    {@+print_nl("Doubly free location at ");
+ at .Doubly free location...@>
+    print_int(q);goto done2;
+    }
+  is_free[q]=true;
+  }
+q=p;p=rlink(p);
+}@+ while (!(p==rover));
+done2:
+
+@ @<Check flags...@>=
+p=mem_min;
+while (p <= lo_mem_max)  /*node |p| should not be empty*/
+  {@+if (is_empty(p))
+    {@+print_nl("Bad flag at ");print_int(p);
+ at .Bad flag...@>
+    }
+  while ((p <= lo_mem_max)&&!is_free[p]) incr(p);
+  while ((p <= lo_mem_max)&&is_free[p]) incr(p);
+  }
+
+@ @<Print newly busy...@>=
+{@+print_nl("New busy locs:");
+for (p=mem_min; p<=lo_mem_max; p++)
+  if (!is_free[p]&&((p > was_lo_max)||was_free[p]))
+    {@+print_char(' ');print_int(p);
+    }
+for (p=hi_mem_min; p<=mem_end; p++)
+  if (!is_free[p]&&
+   ((p < was_hi_min)||(p > was_mem_end)||was_free[p]))
+    {@+print_char(' ');print_int(p);
+    }
+}
+
+@ The |search_mem| procedure attempts to answer the question ``Who points
+to node~|p|?'' In doing so, it fetches |link| and |info| fields of |mem|
+that might not be of type |two_halves|. Strictly speaking, this is
+@^dirty \PASCAL@>
+undefined in \PASCAL, and it can lead to ``false drops'' (words that seem to
+point to |p| purely by coincidence). But for debugging purposes, we want
+to rule out the places that do {\sl not\/} point to |p|, so a few false
+drops are tolerable.
+
+ at p
+#ifdef @!DEBUG
+static void search_mem(pointer @!p) /*look for pointers to |p|*/
+{@+int q; /*current position being searched*/
+for (q=mem_min; q<=lo_mem_max; q++)
+  {@+if (link(q)==p)
+    {@+print_nl("LINK(");print_int(q);print_char(')');
+    }
+  if (info(q)==p)
+    {@+print_nl("INFO(");print_int(q);print_char(')');
+    }
+  }
+for (q=hi_mem_min; q<=mem_end; q++)
+  {@+if (link(q)==p)
+    {@+print_nl("LINK(");print_int(q);print_char(')');
+    }
+  if (info(q)==p)
+    {@+print_nl("INFO(");print_int(q);print_char(')');
+    }
+  }
+@<Search |eqtb| for equivalents equal to |p|@>;
+@<Search |save_stack| for equivalents that point to |p|@>;
+@<Search |hyph_list| for pointers to |p|@>;
+}
+#endif
+
+@* Displaying boxes.
+We can reinforce our knowledge of the data structures just introduced
+by considering two procedures that display a list in symbolic form.
+The first of these, called |short_display|, is used in ``overfull box''
+messages to give the top-level description of a list. The other one,
+called |show_node_list|, prints a detailed description of exactly what
+is in the data structure.
+
+The philosophy of |short_display| is to ignore the fine points about exactly
+what is inside boxes, except that ligatures and discretionary breaks are
+expanded. As a result, |short_display| is a recursive procedure, but the
+recursion is never more than one level deep.
+@^recursion@>
+
+A global variable |font_in_short_display| keeps track of the font code that
+is assumed to be present when |short_display| begins; deviations from this
+font will be printed.
+
+@<Glob...@>=
+static int @!font_in_short_display; /*an internal font number*/
+
+@ Boxes, rules, inserts, whatsits, marks, and things in general that are
+sort of ``complicated'' are indicated only by printing `\.{[]}'.
+
+ at p static void short_display(int @!p) /*prints highlights of list |p|*/
+{@+int n; /*for replacement counts*/
+while (p > mem_min)
+  {@+if (is_char_node(p))
+    {@+if (p <= mem_end)
+      {@+if (font(p)!=font_in_short_display)
+        {@+if ((font(p) < font_base)||(font(p) > font_max))
+          print_char('*');
+ at .*\relax@>
+        else@<Print the font identifier for |font(p)|@>;
+        print_char(' ');font_in_short_display=font(p);
+        }
+      print_ASCII(qo(character(p)));
+      }
+    }
+  else@<Print a short indication of the contents of node |p|@>;
+  p=link(p);
+  }
+}
+
+@ @<Print a short indication of the contents of node |p|@>=
+switch (type(p)) {
+case hlist_node: case vlist_node: case ins_node: case whatsit_node: case mark_node: case adjust_node:
+  case unset_node: case unset_set_node: case unset_pack_node: print("[]");@+break;
+case rule_node: print_char('|');@+break;
+case glue_node: if (glue_ptr(p)!=zero_glue) print_char(' ');@+break;
+case math_node: print_char('$');@+break;
+case ligature_node: short_display(lig_ptr(p));@+break;
+case disc_node: {@+short_display(pre_break(p));
+  short_display(post_break(p));@/
+  n=replace_count(p);
+  while (n > 0)
+    {@+if (link(p)!=null) p=link(p);
+    decr(n);
+    }
+  } @+break;
+default:do_nothing;
+}
+
+@ The |show_node_list| routine requires some auxiliary subroutines: one to
+print a font-and-character combination, one to print a token list without
+its reference count, and one to print a rule dimension.
+
+ at p static void print_font_and_char(int @!p) /*prints |char_node| data*/
+{@+if (p > mem_end) print_esc("CLOBBERED.");
+else{@+if ((font(p) < font_base)||(font(p) > font_max)) print_char('*');
+ at .*\relax@>
+  else@<Print the font identifier for |font(p)|@>;
+  print_char(' ');print_ASCII(qo(character(p)));
+  }
+}
+@#
+static void print_mark(int @!p) /*prints token list data in braces*/
+{@+print_char('{');
+if ((p < hi_mem_min)||(p > mem_end)) print_esc("CLOBBERED.");
+else show_token_list(link(p), null, max_print_line-10);
+print_char('}');
+}
+@#
+static void print_rule_dimen(scaled @!d) /*prints dimension in rule node*/
+{@+if (is_running(d)) print_char('*');else print_scaled(d);
+ at .*\relax@>
+}
+
+@ Then there is a subroutine that prints glue stretch and shrink, possibly
+followed by the name of finite units:
+
+ at p static void print_glue(scaled @!d, int @!order, char *@!s)
+   /*prints a glue component*/
+{@+print_scaled(d);
+if ((order < normal)||(order > filll)) print("foul");
+else if (order > normal)
+  {@+print("fil");
+  while (order > fil)
+    {@+print_char('l');decr(order);
+    }
+  }
+else if (s!=0) print(s);
+}
+
+@ The next subroutine prints a whole glue specification.
+
+ at p static void print_spec(int @!p, char *@!s)
+   /*prints a glue specification*/
+{@+if ((p < mem_min)||(p >= lo_mem_max)) print_char('*');
+ at .*\relax@>
+else{@+print_scaled(width(p));
+  if (s!=0) print(s);
+  if (stretch(p)!=0)
+    {@+print(" plus ");print_glue(stretch(p), stretch_order(p), s);
+    }
+  if (shrink(p)!=0)
+    {@+print(" minus ");print_glue(shrink(p), shrink_order(p), s);
+    }
+  }
+}
+
+@ We also need to declare some procedures that appear later in this
+documentation.
+
+ at p @<Declare procedures needed for displaying the elements of mlists@>@;
+@<Declare the procedure called |print_skip_param|@>@;
+static void print_xdimen(pointer p)
+{ print_scaled(xdimen_width(p));
+  if (xdimen_hfactor(p)!=0)
+  { print_char('+');print_scaled(xdimen_hfactor(p));print("*hsize");}
+  if (xdimen_vfactor(p)!=0)
+  { print_char('+');print_scaled(xdimen_vfactor(p));print("*vsize");}
+}
+
+@ Since boxes can be inside of boxes, |show_node_list| is inherently recursive,
+@^recursion@>
+up to a given maximum number of levels.  The history of nesting is indicated
+by the current string, which will be printed at the beginning of each line;
+the length of this string, namely |cur_length|, is the depth of nesting.
+
+Recursive calls on |show_node_list| therefore use the following pattern:
+
+ at d node_list_display(A)
+  {@+append_char('.');show_node_list(A);flush_char;
+  }  /*|str_room| need not be checked; see |show_box| below*/
+
+@ A global variable called |depth_threshold| is used to record the maximum
+depth of nesting for which |show_node_list| will show information.  If we
+have |depth_threshold==0|, for example, only the top level information will
+be given and no sublists will be traversed. Another global variable, called
+|breadth_max|, tells the maximum number of items to show at each level;
+|breadth_max| had better be positive, or you won't see anything.
+
+@<Glob...@>=
+static int @!depth_threshold; /*maximum nesting depth in box displays*/
+static int @!breadth_max; /*maximum number of items shown at the same list level*/
+
+@ Now we are ready for |show_node_list| itself. This procedure has been
+written to be ``extra robust'' in the sense that it should not crash or get
+into a loop even if the data structures have been messed up by bugs in
+the rest of the program. You can safely call its parent routine
+|show_box(p)| for arbitrary values of |p| when you are debugging \TeX.
+However, in the presence of bad data, the procedure may
+@^dirty \PASCAL@>@^debugging@>
+fetch a |memory_word| whose variant is different from the way it was stored;
+for example, it might try to read |mem[p].hh| when |mem[p]|
+contains a scaled integer, if |p| is a pointer that has been
+clobbered or chosen at random.
+
+ at p static void show_node_list(int @!p) /*prints a node list symbolically*/
+{@+
+int n; /*the number of items already printed at this level*/
+double @!g; /*a glue ratio, as a floating point number*/
+if (cur_length > depth_threshold)
+  {@+if (p > null) print(" []");
+     /*indicate that there's been some truncation*/
+  return;
+  }
+n=0;
+while (p > mem_min)
+  {@+print_ln();print_current_string(); /*display the nesting history*/
+  if (p > mem_end)  /*pointer out of range*/
+    {@+print("Bad link, display aborted.");return;
+ at .Bad link...@>
+    }
+  incr(n);if (n > breadth_max)  /*time to stop*/
+    {@+print("etc.");return;
+ at .etc@>
+    }
+  @<Display node |p|@>;
+  p=link(p);
+  }
+
+}
+
+@ @<Display node |p|@>=
+if (is_char_node(p)) print_font_and_char(p);
+else switch (type(p)) {
+  case hlist_node: case vlist_node: case unset_node: case unset_set_node: case unset_pack_node: @<Display box |p|@>@;@+break;
+  case rule_node: @<Display rule |p|@>@;@+break;
+  case ins_node: @<Display insertion |p|@>@;@+break;
+  case whatsit_node: @<Display the whatsit node |p|@>@;@+break;
+  case glue_node: @<Display glue |p|@>@;@+break;
+  case kern_node: @<Display kern |p|@>@;@+break;
+  case math_node: @<Display math node |p|@>@;@+break;
+  case ligature_node: @<Display ligature |p|@>@;@+break;
+  case penalty_node: @<Display penalty |p|@>@;@+break;
+  case disc_node: @<Display discretionary |p|@>@;@+break;
+  case mark_node: @<Display mark |p|@>@;@+break;
+  case adjust_node: @<Display adjustment |p|@>@;@+break;
+  @t\4@>@<Cases of |show_node_list| that arise in mlists only@>@;
+  default:print("Unknown node type!");
+  }
+
+@ @<Display box |p|@>=
+{@+if (type(p)==hlist_node) print_esc("h");
+else if (type(p)==vlist_node) print_esc("v");
+else print_esc("unset");
+print("box(");print_scaled(height(p));print_char('+');
+print_scaled(depth(p));print(")x");print_scaled(width(p));
+if (type(p)==unset_set_node)  print("set");
+else if (type(p)==unset_pack_node) print("pack");
+else if (type(p)==unset_node)
+  @<Display special fields of the unset node |p|@>@;
+else{@+@<Display the value of |glue_set(p)|@>;
+  if (shift_amount(p)!=0)
+    {@+print(", shifted ");print_scaled(shift_amount(p));
+    }
+  }
+node_list_display(list_ptr(p)); /*recursive call*/
+}
+
+@ @<Display special fields of the unset node |p|@>=
+{@+if (span_count(p)!=min_quarterword)
+  {@+print(" (");print_int(qo(span_count(p))+1);
+  print(" columns)");
+  }
+if (glue_stretch(p)!=0)
+  {@+print(", stretch ");print_glue(glue_stretch(p), glue_order(p), 0);
+  }
+if (glue_shrink(p)!=0)
+  {@+print(", shrink ");print_glue(glue_shrink(p), glue_sign(p), 0);
+  }
+}
+
+@ The code will have to change in this place if |glue_ratio| is
+a structured type instead of an ordinary |double|. Note that this routine
+should avoid arithmetic errors even if the |glue_set| field holds an
+arbitrary random value. The following code assumes that a properly
+formed nonzero |double| number has absolute value $2^{20}$ or more when
+it is regarded as an integer; this precaution was adequate to prevent
+floating point underflow on the author's computer.
+@^system dependencies@>
+@^dirty \PASCAL@>
+
+@<Display the value of |glue_set(p)|@>=
+g=float(glue_set(p));
+if ((g!=float_constant(0))&&(glue_sign(p)!=normal))
+  {@+print(", glue set ");
+  if (glue_sign(p)==shrinking) print("- ");
+  if (abs(mem[p+glue_offset].i) < 04000000) print("?.?");
+  else if (abs(g) > float_constant(20000))
+    {@+if (g > float_constant(0)) print_char('>');
+    else print("< -");
+    print_glue(20000*unity, glue_order(p), 0);
+    }
+  else print_glue(round(unity*g), glue_order(p), 0);
+@^real multiplication@>
+  }
+
+@ @<Display rule |p|@>=
+{@+print_esc("rule(");print_rule_dimen(height(p));print_char('+');
+print_rule_dimen(depth(p));print(")x");print_rule_dimen(width(p));
+}
+
+@ @<Display insertion |p|@>=
+{@+print_esc("insert");print_int(qo(subtype(p)));
+print("; split(");print_spec(split_top_ptr(p), 0);
+print_char(',');print_scaled(depth(p));
+print("); float cost ");print_int(float_cost(p));
+node_list_display(ins_ptr(p)); /*recursive call*/
+}
+
+@ @<Display glue |p|@>=
+if (subtype(p) >= a_leaders) @<Display leaders |p|@>@;
+else{@+print_esc("glue");
+  if (subtype(p)!=normal)
+    {@+print_char('(');
+    if (subtype(p) < cond_math_glue)
+      print_skip_param(subtype(p)-1);
+    else if (subtype(p)==cond_math_glue) print_esc("nonscript");
+    else print_esc("mskip");
+    print_char(')');
+    }
+  if (subtype(p)!=cond_math_glue)
+    {@+print_char(' ');
+    if (subtype(p) < cond_math_glue) print_spec(glue_ptr(p), 0);
+    else print_spec(glue_ptr(p),"mu");
+    }
+  }
+
+@ @<Display leaders |p|@>=
+{@+print_esc("");
+if (subtype(p)==c_leaders) print_char('c');
+else if (subtype(p)==x_leaders) print_char('x');
+print("leaders ");print_spec(glue_ptr(p), 0);
+node_list_display(leader_ptr(p)); /*recursive call*/
+}
+
+@ An ``explicit'' kern value is indicated implicitly by an explicit space.
+
+@<Display kern |p|@>=
+if (subtype(p)!=mu_glue)
+  {@+print_esc("kern");
+  if (subtype(p)!=normal) print_char(' ');
+  print_scaled(width(p));
+  if (subtype(p)==acc_kern) print(" (for accent)");
+ at .for accent@>
+  }
+else{@+print_esc("mkern");print_scaled(width(p));print("mu");
+  }
+
+@ @<Display math node |p|@>=
+{@+print_esc("math");
+if (subtype(p)==before) print("on");
+else print("off");
+if (width(p)!=0)
+  {@+print(", surrounded ");print_scaled(width(p));
+  }
+}
+
+@ @<Display ligature |p|@>=
+{@+print_font_and_char(lig_char(p));print(" (ligature ");
+if (subtype(p) > 1) print_char('|');
+font_in_short_display=font(lig_char(p));short_display(lig_ptr(p));
+if (odd(subtype(p))) print_char('|');
+print_char(')');
+}
+
+@ @<Display penalty |p|@>=
+{@+print_esc("penalty ");print_int(penalty(p));
+}
+
+@ The |post_break| list of a discretionary node is indicated by a prefixed
+`\.{\char'174}' instead of the `\..' before the |pre_break| list.
+
+@<Display discretionary |p|@>=
+{@+print_esc("discretionary");
+if (replace_count(p) > 0)
+  {@+print(" replacing ");print_int(replace_count(p));
+  }
+node_list_display(pre_break(p)); /*recursive call*/
+append_char('|');show_node_list(post_break(p));flush_char; /*recursive call*/
+}
+
+@ @<Display mark |p|@>=
+{@+print_esc("mark");print_mark(mark_ptr(p));
+}
+
+@ @<Display adjustment |p|@>=
+{@+print_esc("vadjust");node_list_display(adjust_ptr(p)); /*recursive call*/
+}
+
+@ The recursive machinery is started by calling |show_box|.
+@^recursion@>
+
+ at p static void show_box(pointer @!p)
+{@+@<Assign the values |depth_threshold:=show_box_depth| and |breadth_max:=show_box_breadth|@>;
+if (breadth_max <= 0) breadth_max=5;
+if (pool_ptr+depth_threshold >= pool_size)
+  depth_threshold=pool_size-pool_ptr-1;
+   /*now there's enough room for prefix string*/
+show_node_list(p); /*the show starts at |p|*/
+print_ln();
+}
+
+@* Destroying boxes.
+When we are done with a node list, we are obliged to return it to free
+storage, including all of its sublists. The recursive procedure
+|flush_node_list| does this for us.
+
+@ First, however, we shall consider two non-recursive procedures that do
+simpler tasks. The first of these, |delete_token_ref|, is called when
+a pointer to a token list's reference count is being removed. This means
+that the token list should disappear if the reference count was |null|,
+otherwise the count should be decreased by one.
+@^reference counts@>
+
+ at d token_ref_count(A) info(A) /*reference count preceding a token list*/
+
+ at p static void delete_token_ref(pointer @!p) /*|p| points to the reference count
+  of a token list that is losing one reference*/
+{@+if (token_ref_count(p)==null) flush_list(p);
+else decr(token_ref_count(p));
+}
+
+@ Similarly, |delete_glue_ref| is called when a pointer to a glue
+specification is being withdrawn.
+@^reference counts@>
+ at d fast_delete_glue_ref(A) @t@>@;@/
+  {@+if (glue_ref_count(A)==null) free_node(A, glue_spec_size);
+  else decr(glue_ref_count(A));
+  }
+
+ at p static void delete_glue_ref(pointer @!p) /*|p| points to a glue specification*/
+fast_delete_glue_ref(p)
+static void delete_xdimen_ref(pointer @!p) /*|p| points to a xdimen specification*/
+{@+if (xdimen_ref_count(p)==null) free_node(p, xdimen_node_size);
+  else decr(xdimen_ref_count(p));
+}
+
+@ Now we are ready to delete any node list, recursively.
+In practice, the nodes deleted are usually charnodes (about 2/3 of the time),
+and they are glue nodes in about half of the remaining cases.
+@^recursion@>
+
+ at p static void flush_node_list(pointer @!p) /*erase list of nodes starting at |p|*/
+{@+ /*go here when node |p| has been freed*/
+pointer q; /*successor to node |p|*/
+while (p!=null)
+@^inner loop@>
+  {@+q=link(p);
+  if (is_char_node(p)) free_avail(p)@;
+  else{@+switch (type(p)) {
+    case hlist_node: case vlist_node: case unset_node: case unset_set_node: case unset_pack_node: {@+flush_node_list(list_ptr(p));
+      free_node(p, box_node_size);goto done;
+      }
+    case rule_node: {@+free_node(p, rule_node_size);goto done;
+      }
+    case ins_node: {@+flush_node_list(ins_ptr(p));
+      delete_glue_ref(split_top_ptr(p));
+      free_node(p, ins_node_size);goto done;
+      }
+    case whatsit_node: @<Wipe out the whatsit node |p| and |goto done|@>@;
+    case glue_node: {@+fast_delete_glue_ref(glue_ptr(p));
+      if (leader_ptr(p)!=null) flush_node_list(leader_ptr(p));
+      } @+break;
+    case kern_node: case math_node: case penalty_node: do_nothing;@+break;
+    case ligature_node: flush_node_list(lig_ptr(p));@+break;
+    case mark_node: delete_token_ref(mark_ptr(p));@+break;
+    case disc_node: {@+flush_node_list(pre_break(p));
+      flush_node_list(post_break(p));
+      } @+break;
+    case adjust_node: flush_node_list(adjust_ptr(p));@+break;
+    @t\4@>@<Cases of |flush_node_list| that arise in mlists only@>@;
+    default:confusion("flushing");
+@:this can't happen flushing}{\quad flushing@>
+    } @/
+    free_node(p, small_node_size);
+    done: ;}
+  p=q;
+  }
+}
+
+@* Copying boxes.
+Another recursive operation that acts on boxes is sometimes needed: The
+procedure |copy_node_list| returns a pointer to another node list that has
+the same structure and meaning as the original. Note that since glue
+specifications and token lists have reference counts, we need not make
+copies of them. Reference counts can never get too large to fit in a
+halfword, since each pointer to a node is in a different memory address,
+and the total number of memory addresses fits in a halfword.
+@^recursion@>
+@^reference counts@>
+
+(Well, there actually are also references from outside |mem|; if the
+|save_stack| is made arbitrarily large, it would theoretically be possible
+to break \TeX\ by overflowing a reference count. But who would want to do that?)
+
+ at d add_token_ref(A) incr(token_ref_count(A)) /*new reference to a token list*/
+ at d add_glue_ref(A) incr(glue_ref_count(A)) /*new reference to a glue spec*/
+ at d add_xdimen_ref(A) incr(xdimen_ref_count(A)) /*new reference to an xdimen*/
+
+@ The copying procedure copies words en masse without bothering
+to look at their individual fields. If the node format changes---for
+example, if the size is altered, or if some link field is moved to another
+relative position---then this code may need to be changed too.
+@^data structure assumptions@>
+
+ at p static pointer copy_node_list(pointer @!p) /*makes a duplicate of the
+  node list that starts at |p| and returns a pointer to the new list*/
+{@+pointer h; /*temporary head of copied list*/
+pointer @!q; /*previous position in new list*/
+pointer @!r; /*current node being fabricated for new list*/
+int @!words; /*number of words remaining to be copied*/
+h=get_avail();q=h;
+while (p!=null)
+  {@+@<Make a copy of node |p| in node |r|@>;
+  link(q)=r;q=r;p=link(p);
+  }
+link(q)=null;q=link(h);free_avail(h);
+return q;
+}
+
+@ @<Make a copy of node |p|...@>=
+words=1; /*this setting occurs in more branches than any other*/
+if (is_char_node(p)) r=get_avail();
+else@<Case statement to copy different types and set |words| to the number of initial
+words not yet copied@>;
+while (words > 0)
+  {@+decr(words);mem[r+words]=mem[p+words];
+  }
+
+@ @<Case statement to copy...@>=
+switch (type(p)) {
+case hlist_node: case vlist_node: case unset_node: case unset_set_node: case unset_pack_node: {@+r=get_node(box_node_size);
+  mem[r+6]=mem[p+6];mem[r+5]=mem[p+5]; /*copy the last two words*/
+  list_ptr(r)=copy_node_list(list_ptr(p)); /*this affects |mem[r+5]|*/
+  words=5;
+  } @+break;
+case rule_node: {@+r=get_node(rule_node_size);words=rule_node_size;
+  } @+break;
+case ins_node: {@+r=get_node(ins_node_size);mem[r+4]=mem[p+4];
+  add_glue_ref(split_top_ptr(p));
+  ins_ptr(r)=copy_node_list(ins_ptr(p)); /*this affects |mem[r+4]|*/
+  words=ins_node_size-1;
+  } @+break;
+case whatsit_node: @<Make a partial copy of the whatsit node |p| and make |r| point
+to it; set |words| to the number of initial words not yet copied@>@;@+break;
+case glue_node: {@+r=get_node(small_node_size);add_glue_ref(glue_ptr(p));
+  glue_ptr(r)=glue_ptr(p);leader_ptr(r)=copy_node_list(leader_ptr(p));
+  } @+break;
+case kern_node: case math_node: case penalty_node: {@+r=get_node(small_node_size);
+  words=small_node_size;
+  } @+break;
+case ligature_node: {@+r=get_node(small_node_size);
+  mem[lig_char(r)]=mem[lig_char(p)]; /*copy |font| and |character|*/
+  lig_ptr(r)=copy_node_list(lig_ptr(p));
+  } @+break;
+case disc_node: {@+r=get_node(small_node_size);
+  pre_break(r)=copy_node_list(pre_break(p));
+  post_break(r)=copy_node_list(post_break(p));
+  } @+break;
+case mark_node: {@+r=get_node(small_node_size);add_token_ref(mark_ptr(p));
+  words=small_node_size;
+  } @+break;
+case adjust_node: {@+r=get_node(small_node_size);
+  adjust_ptr(r)=copy_node_list(adjust_ptr(p));
+  } @+break; /*|words==1==small_node_size-1|*/
+default:confusion("copying");
+@:this can't happen copying}{\quad copying@>
+}
+
+@* The command codes.
+Before we can go any further, we need to define symbolic names for the internal
+code numbers that represent the various commands obeyed by \TeX. These codes
+are somewhat arbitrary, but not completely so. For example, the command
+codes for character types are fixed by the language, since a user says,
+e.g., `\.{\\catcode \`\\\${} = 3}' to make \.{\char'44} a math delimiter,
+and the command code |math_shift| is equal to~3. Some other codes have
+been made adjacent so that |case| statements in the program need not consider
+cases that are widely spaced, or so that |case| statements can be replaced
+by |if (| statements.
+
+At any rate, here is the list, for future reference. First come the
+``catcode'' commands, several of which share their numeric codes with
+ordinary commands when the catcode cannot emerge from \TeX's scanning routine.
+
+ at d escape 0 /*escape delimiter (called \.\\ in {\sl The \TeX book\/})*/
+@:TeXbook}{\sl The \TeX book@>
+ at d relax 0 /*do nothing ( \.{\\relax} )*/
+ at d left_brace 1 /*beginning of a group ( \.\{ )*/
+ at d right_brace 2 /*ending of a group ( \.\} )*/
+ at d math_shift 3 /*mathematics shift character ( \.\$ )*/
+ at d tab_mark 4 /*alignment delimiter ( \.\&, \.{\\span} )*/
+ at d car_ret 5 /*end of line ( |carriage_return|, \.{\\cr}, \.{\\crcr} )*/
+ at d out_param 5 /*output a macro parameter*/
+ at d mac_param 6 /*macro parameter symbol ( \.\# )*/
+ at d sup_mark 7 /*superscript ( \.{\char'136} )*/
+ at d sub_mark 8 /*subscript ( \.{\char'137} )*/
+ at d ignore 9 /*characters to ignore ( \.{\^\^@@} )*/
+ at d endv 9 /*end of \<v_j> list in alignment template*/
+ at d spacer 10 /*characters equivalent to blank space ( \.{\ } )*/
+ at d letter 11 /*characters regarded as letters ( \.{A..Z}, \.{a..z} )*/
+ at d other_char 12 /*none of the special character types*/
+ at d active_char 13 /*characters that invoke macros ( \.{\char`\~} )*/
+ at d par_end 13 /*end of paragraph ( \.{\\par} )*/
+ at d match 13 /*match a macro parameter*/
+ at d comment 14 /*characters that introduce comments ( \.\% )*/
+ at d end_match 14 /*end of parameters to macro*/
+ at d stop 14 /*end of job ( \.{\\end}, \.{\\dump} )*/
+ at d invalid_char 15 /*characters that shouldn't appear ( \.{\^\^?} )*/
+ at d delim_num 15 /*specify delimiter numerically ( \.{\\delimiter} )*/
+ at d max_char_code 15 /*largest catcode for individual characters*/
+
+@ Next are the ordinary run-of-the-mill command codes.  Codes that are
+|min_internal| or more represent internal quantities that might be
+expanded by `\.{\\the}'.
+
+ at d char_num 16 /*character specified numerically ( \.{\\char} )*/
+ at d math_char_num 17 /*explicit math code ( \.{\\mathchar} )*/
+ at d mark 18 /*mark definition ( \.{\\mark} )*/
+ at d xray 19 /*peek inside of \TeX\ ( \.{\\show}, \.{\\showbox}, etc.~)*/
+ at d make_box 20 /*make a box ( \.{\\box}, \.{\\copy}, \.{\\hbox}, etc.~)*/
+ at d hmove 21 /*horizontal motion ( \.{\\moveleft}, \.{\\moveright} )*/
+ at d vmove 22 /*vertical motion ( \.{\\raise}, \.{\\lower} )*/
+ at d un_hbox 23 /*unglue a box ( \.{\\unhbox}, \.{\\unhcopy} )*/
+ at d un_vbox 24 /*unglue a box ( \.{\\unvbox}, \.{\\unvcopy} )*/
+ at d remove_item 25 /*nullify last item ( \.{\\unpenalty},
+  \.{\\unkern}, \.{\\unskip} )*/
+ at d hskip 26 /*horizontal glue ( \.{\\hskip}, \.{\\hfil}, etc.~)*/
+ at d vskip 27 /*vertical glue ( \.{\\vskip}, \.{\\vfil}, etc.~)*/
+ at d mskip 28 /*math glue ( \.{\\mskip} )*/
+ at d kern 29 /*fixed space ( \.{\\kern} )*/
+ at d mkern 30 /*math kern ( \.{\\mkern} )*/
+ at d leader_ship 31 /*use a box ( \.{\\shipout}, \.{\\leaders}, etc.~)*/
+ at d halign 32 /*horizontal table alignment ( \.{\\halign} )*/
+ at d valign 33 /*vertical table alignment ( \.{\\valign} )*/
+ at d no_align 34 /*temporary escape from alignment ( \.{\\noalign} )*/
+ at d vrule 35 /*vertical rule ( \.{\\vrule} )*/
+ at d hrule 36 /*horizontal rule ( \.{\\hrule} )*/
+ at d insert 37 /*vlist inserted in box ( \.{\\insert} )*/
+ at d vadjust 38 /*vlist inserted in enclosing paragraph ( \.{\\vadjust} )*/
+ at d ignore_spaces 39 /*gobble |spacer| tokens ( \.{\\ignorespaces} )*/
+ at d after_assignment 40 /*save till assignment is done ( \.{\\afterassignment} )*/
+ at d after_group 41 /*save till group is done ( \.{\\aftergroup} )*/
+ at d break_penalty 42 /*additional badness ( \.{\\penalty} )*/
+ at d start_par 43 /*begin paragraph ( \.{\\indent}, \.{\\noindent} )*/
+ at d ital_corr 44 /*italic correction ( \.{\\/} )*/
+ at d accent 45 /*attach accent in text ( \.{\\accent} )*/
+ at d math_accent 46 /*attach accent in math ( \.{\\mathaccent} )*/
+ at d discretionary 47 /*discretionary texts ( \.{\\-}, \.{\\discretionary} )*/
+ at d eq_no 48 /*equation number ( \.{\\eqno}, \.{\\leqno} )*/
+ at d left_right 49 /*variable delimiter ( \.{\\left}, \.{\\right} )*/
+   /*( or \.{\\middle} )*/
+ at d math_comp 50 /*component of formula ( \.{\\mathbin}, etc.~)*/
+ at d limit_switch 51 /*diddle limit conventions ( \.{\\displaylimits}, etc.~)*/
+ at d above 52 /*generalized fraction ( \.{\\above}, \.{\\atop}, etc.~)*/
+ at d math_style 53 /*style specification ( \.{\\displaystyle}, etc.~)*/
+ at d math_choice 54 /*choice specification ( \.{\\mathchoice} )*/
+ at d non_script 55 /*conditional math glue ( \.{\\nonscript} )*/
+ at d vcenter 56 /*vertically center a vbox ( \.{\\vcenter} )*/
+ at d case_shift 57 /*force specific case ( \.{\\lowercase}, \.{\\uppercase}~)*/
+ at d message 58 /*send to user ( \.{\\message}, \.{\\errmessage} )*/
+ at d extension 59 /*extensions to \TeX\ ( \.{\\write}, \.{\\special}, etc.~)*/
+ at d in_stream 60 /*files for reading ( \.{\\openin}, \.{\\closein} )*/
+ at d begin_group 61 /*begin local grouping ( \.{\\begingroup} )*/
+ at d end_group 62 /*end local grouping ( \.{\\endgroup} )*/
+ at d omit 63 /*omit alignment template ( \.{\\omit} )*/
+ at d ex_space 64 /*explicit space ( \.{\\\ } )*/
+ at d no_boundary 65 /*suppress boundary ligatures ( \.{\\noboundary} )*/
+ at d radical 66 /*square root and similar signs ( \.{\\radical} )*/
+ at d end_cs_name 67 /*end control sequence ( \.{\\endcsname} )*/
+ at d min_internal 68 /*the smallest code that can follow \.{\\the}*/
+ at d char_given 68 /*character code defined by \.{\\chardef}*/
+ at d math_given 69 /*math code defined by \.{\\mathchardef}*/
+ at d last_item 70 /*most recent item ( \.{\\lastpenalty},
+  \.{\\lastkern}, \.{\\lastskip} )*/
+ at d max_non_prefixed_command 70 /*largest command code that can't be \.{\\global}*/
+
+@ The next codes are special; they all relate to mode-independent
+assignment of values to \TeX's internal registers or tables.
+Codes that are |max_internal| or less represent internal quantities
+that might be expanded by `\.{\\the}'.
+
+ at d toks_register 71 /*token list register ( \.{\\toks} )*/
+ at d assign_toks 72 /*special token list ( \.{\\output}, \.{\\everypar}, etc.~)*/
+ at d assign_int 73 /*user-defined integer ( \.{\\tolerance}, \.{\\day}, etc.~)*/
+ at d assign_dimen 74 /*user-defined length ( \.{\\hsize}, etc.~)*/
+ at d assign_glue 75 /*user-defined glue ( \.{\\baselineskip}, etc.~)*/
+ at d assign_mu_glue 76 /*user-defined muglue ( \.{\\thinmuskip}, etc.~)*/
+ at d assign_font_dimen 77 /*user-defined font dimension ( \.{\\fontdimen} )*/
+ at d assign_font_int 78 /*user-defined font integer ( \.{\\hyphenchar},
+  \.{\\skewchar} )*/
+ at d set_aux 79 /*specify state info ( \.{\\spacefactor}, \.{\\prevdepth} )*/
+ at d set_prev_graf 80 /*specify state info ( \.{\\prevgraf} )*/
+ at d set_page_dimen 81 /*specify state info ( \.{\\pagegoal}, etc.~)*/
+ at d set_page_int 82 /*specify state info ( \.{\\deadcycles},
+  \.{\\insertpenalties} )*/
+   /*( or \.{\\interactionmode} )*/
+ at d set_box_dimen 83 /*change dimension of box ( \.{\\wd}, \.{\\ht}, \.{\\dp} )*/
+ at d set_shape 84 /*specify fancy paragraph shape ( \.{\\parshape} )*/
+   /*(or \.{\\interlinepenalties}, etc.~)*/
+ at d def_code 85 /*define a character code ( \.{\\catcode}, etc.~)*/
+ at d def_family 86 /*declare math fonts ( \.{\\textfont}, etc.~)*/
+ at d set_font 87 /*set current font ( font identifiers )*/
+ at d def_font 88 /*define a font file ( \.{\\font} )*/
+ at d internal_register 89 /*internal register ( \.{\\count}, \.{\\dimen}, etc.~)*/
+ at d max_internal 89 /*the largest code that can follow \.{\\the}*/
+ at d advance 90 /*advance a register or parameter ( \.{\\advance} )*/
+ at d multiply 91 /*multiply a register or parameter ( \.{\\multiply} )*/
+ at d divide 92 /*divide a register or parameter ( \.{\\divide} )*/
+ at d prefix 93 /*qualify a definition ( \.{\\global}, \.{\\long}, \.{\\outer} )*/
+   /*( or \.{\\protected} )*/
+ at d let 94 /*assign a command code ( \.{\\let}, \.{\\futurelet} )*/
+ at d shorthand_def 95 /*code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)*/
+ at d read_to_cs 96 /*read into a control sequence ( \.{\\read} )*/
+   /*( or \.{\\readline} )*/
+ at d def 97 /*macro definition ( \.{\\def}, \.{\\gdef}, \.{\\xdef}, \.{\\edef} )*/
+ at d set_box 98 /*set a box ( \.{\\setbox} )*/
+ at d hyph_data 99 /*hyphenation data ( \.{\\hyphenation}, \.{\\patterns} )*/
+ at d set_interaction 100 /*define level of interaction ( \.{\\batchmode}, etc.~)*/
+ at d max_command 100 /*the largest command code seen at |big_switch|*/
+
+@ The remaining command codes are extra special, since they cannot get through
+\TeX's scanner to the main control routine. They have been given values higher
+than |max_command| so that their special nature is easily discernible.
+The ``expandable'' commands come first.
+
+ at d undefined_cs (max_command+1) /*initial state of most |eq_type| fields*/
+ at d expand_after (max_command+2) /*special expansion ( \.{\\expandafter} )*/
+ at d no_expand (max_command+3) /*special nonexpansion ( \.{\\noexpand} )*/
+ at d input (max_command+4) /*input a source file ( \.{\\input}, \.{\\endinput} )*/
+   /*( or \.{\\scantokens} )*/
+ at d if_test (max_command+5) /*conditional text ( \.{\\if}, \.{\\ifcase}, etc.~)*/
+ at d fi_or_else (max_command+6) /*delimiters for conditionals ( \.{\\else}, etc.~)*/
+ at d cs_name (max_command+7) /*make a control sequence from tokens ( \.{\\csname} )*/
+ at d convert (max_command+8) /*convert to text ( \.{\\number}, \.{\\string}, etc.~)*/
+ at d the (max_command+9) /*expand an internal quantity ( \.{\\the} )*/
+   /*( or \.{\\unexpanded}, \.{\\detokenize} )*/
+ at d top_bot_mark (max_command+10) /*inserted mark ( \.{\\topmark}, etc.~)*/
+ at d call (max_command+11) /*non-long, non-outer control sequence*/
+ at d long_call (max_command+12) /*long, non-outer control sequence*/
+ at d outer_call (max_command+13) /*non-long, outer control sequence*/
+ at d long_outer_call (max_command+14) /*long, outer control sequence*/
+ at d end_template (max_command+15) /*end of an alignment template*/
+ at d dont_expand (max_command+16) /*the following token was marked by \.{\\noexpand}*/
+ at d glue_ref (max_command+17) /*the equivalent points to a glue specification*/
+ at d shape_ref (max_command+18) /*the equivalent points to a parshape specification*/
+ at d box_ref (max_command+19) /*the equivalent points to a box node, or is |null|*/
+ at d data (max_command+20) /*the equivalent is simply a halfword number*/
+
+@* The semantic nest.
+\TeX\ is typically in the midst of building many lists at once. For example,
+when a math formula is being processed, \TeX\ is in math mode and
+working on an mlist; this formula has temporarily interrupted \TeX\ from
+being in horizontal mode and building the hlist of a paragraph; and this
+paragraph has temporarily interrupted \TeX\ from being in vertical mode
+and building the vlist for the next page of a document. Similarly, when a
+\.{\\vbox} occurs inside of an \.{\\hbox}, \TeX\ is temporarily
+interrupted from working in restricted horizontal mode, and it enters
+internal vertical mode.  The ``semantic nest'' is a stack that
+keeps track of what lists and modes are currently suspended.
+
+At each level of processing we are in one of six modes:
+
+\yskip\hang|vmode| stands for vertical mode (the page builder);
+
+\hang|hmode| stands for horizontal mode (the paragraph builder);
+
+\hang|mmode| stands for displayed formula mode;
+
+\hang|-vmode| stands for internal vertical mode (e.g., in a \.{\\vbox});
+
+\hang|-hmode| stands for restricted horizontal mode (e.g., in an \.{\\hbox});
+
+\hang|-mmode| stands for math formula mode (not displayed).
+
+\yskip\noindent The mode is temporarily set to zero while processing \.{\\write}
+texts.
+
+Numeric values are assigned to |vmode|, |hmode|, and |mmode| so that
+\TeX's ``big semantic switch'' can select the appropriate thing to
+do by computing the value |abs(mode)+cur_cmd|, where |mode| is the current
+mode and |cur_cmd| is the current command code.
+
+ at d vmode 1 /*vertical mode*/
+ at d hmode (vmode+max_command+1) /*horizontal mode*/
+ at d mmode (hmode+max_command+1) /*math mode*/
+
+ at p static void print_mode(int @!m) /*prints the mode represented by |m|*/
+{@+if (m > 0)
+  switch (m/(max_command+1)) {
+  case 0: print("vertical");@+break;
+  case 1: print("horizontal");@+break;
+  case 2: print("display math");
+  }
+else if (m==0) print("no");
+else switch ((-m)/(max_command+1)) {
+  case 0: print("internal vertical");@+break;
+  case 1: print("restricted horizontal");@+break;
+  case 2: print("math");
+  }
+print(" mode");
+}
+
+@ The state of affairs at any semantic level can be represented by
+five values:
+
+\yskip\hang|mode| is the number representing the semantic mode, as
+just explained.
+
+\yskip\hang|head| is a |pointer| to a list head for the list being built;
+|link(head)| therefore points to the first element of the list, or
+to |null| if the list is empty.
+
+\yskip\hang|tail| is a |pointer| to the final node of the list being
+built; thus, |tail==head| if and only if the list is empty.
+
+\yskip\hang|prev_graf| is the number of lines of the current paragraph that
+have already been put into the present vertical list.
+
+\yskip\hang|aux| is an auxiliary |memory_word| that gives further information
+that is needed to characterize the situation.
+
+\yskip\noindent
+In vertical mode, |aux| is also known as |prev_depth|; it is the scaled
+value representing the depth of the previous box, for use in baseline
+calculations, or it is | <= -1000|pt if the next box on the vertical list is to
+be exempt from baseline calculations.  In horizontal mode, |aux| is also
+known as |space_factor| and |clang|; it holds the current space factor used in
+spacing calculations, and the current language used for hyphenation.
+(The value of |clang| is undefined in restricted horizontal mode.)
+In math mode, |aux| is also known as |incompleat_noad|; if
+not |null|, it points to a record that represents the numerator of a
+generalized fraction for which the denominator is currently being formed
+in the current list.
+
+There is also a sixth quantity, |mode_line|, which correlates
+the semantic nest with the user's input; |mode_line| contains the source
+line number at which the current level of nesting was entered. The negative
+of this line number is the |mode_line| at the level of the
+user's output routine.
+
+A seventh quantity, |eTeX_aux|, is used by the extended features \eTeX.
+In vertical modes it is known as |LR_save| and holds the LR stack when a
+paragraph is interrupted by a displayed formula.  In display math mode
+it is known as |LR_box| and holds a pointer to a prototype box for the
+display.  In math mode it is known as |delim_ptr| and points to the most
+recent |left_noad| or |middle_noad| of a |math_left_group|.
+
+In horizontal mode, the |prev_graf| field is used for initial language data.
+
+The semantic nest is an array called |nest| that holds the |mode|, |head|,
+|tail|, |prev_graf|, |aux|, and |mode_line| values for all semantic levels
+below the currently active one. Information about the currently active
+level is kept in the global quantities |mode|, |head|, |tail|, |prev_graf|,
+|aux|, and |mode_line|, which live in a \PASCAL\ record that is ready to
+be pushed onto |nest| if necessary.
+
+ at d ignore_depth (-1000*unity) /*|prev_depth| value that is ignored*/
+ at d unknown_depth (-2000*unity) /*|prev_depth| value that is unknown*/
+
+@<Types...@>=
+typedef struct { int16_t @!mode_field;@+
+  pointer @!head_field, @!tail_field;
+  pointer @!eTeX_aux_field;
+  int @!pg_field, @!ml_field;@+
+  memory_word @!aux_field;
+  } list_state_record;
+
+@ @d mode cur_list.mode_field /*current mode*/
+ at d head cur_list.head_field /*header node of current list*/
+ at d tail cur_list.tail_field /*final node on current list*/
+ at d eTeX_aux cur_list.eTeX_aux_field /*auxiliary data for \eTeX*/
+ at d LR_save eTeX_aux /*LR stack when a paragraph is interrupted*/
+ at d LR_box eTeX_aux /*prototype box for display*/
+ at d delim_ptr eTeX_aux /*most recent left or right noad of a math left group*/
+ at d prev_graf cur_list.pg_field /*number of paragraph lines accumulated*/
+ at d aux cur_list.aux_field /*auxiliary data about the current list*/
+ at d prev_depth aux.sc /*the name of |aux| in vertical mode*/
+ at d space_factor aux.hh.lh /*part of |aux| in horizontal mode*/
+ at d clang aux.hh.rh /*the other part of |aux| in horizontal mode*/
+ at d incompleat_noad aux.i /*the name of |aux| in math mode*/
+ at d mode_line cur_list.ml_field /*source file line number at beginning of list*/
+
+@<Glob...@>=
+static list_state_record @!nest[nest_size+1];
+static int @!nest_ptr; /*first unused location of |nest|*/
+static int @!max_nest_stack; /*maximum of |nest_ptr| when pushing*/
+static list_state_record @!cur_list; /*the ``top'' semantic state*/
+static int @!shown_mode; /*most recent mode shown by \.{\\tracingcommands}*/
+
+@ Here is a common way to make the current list grow:
+
+ at d tail_append(A) {@+link(tail)=A;tail=link(tail);
+  }
+
+@ We will see later that the vertical list at the bottom semantic level is split
+into two parts; the ``current page'' runs from |page_head| to |page_tail|,
+and the ``contribution list'' runs from |contrib_head| to |tail| of
+semantic level zero. The idea is that contributions are first formed in
+vertical mode, then ``contributed'' to the current page (during which time
+the page-breaking decisions are made). For now, we don't need to know
+any more details about the page-building process.
+
+@<Set init...@>=
+nest_ptr=0;max_nest_stack=0;
+mode=vmode;head=contrib_head;tail=contrib_head;
+eTeX_aux=null;
+prev_depth=ignore_depth;mode_line=0;
+prev_graf=0;shown_mode=0;
+@<Start a new current page@>;
+
+@ When \TeX's work on one level is interrupted, the state is saved by
+calling |push_nest|. This routine changes |head| and |tail| so that
+a new (empty) list is begun; it does not change |mode| or |aux|.
+
+ at p static void push_nest(void) /*enter a new semantic level, save the old*/
+{@+if (nest_ptr > max_nest_stack)
+  {@+max_nest_stack=nest_ptr;
+  if (nest_ptr==nest_size) overflow("semantic nest size", nest_size);
+@:TeX capacity exceeded semantic nest size}{\quad semantic nest size@>
+  }
+nest[nest_ptr]=cur_list; /*stack the record*/
+incr(nest_ptr);head=get_avail();tail=head;prev_graf=0;mode_line=line;
+eTeX_aux=null;
+}
+
+@ Conversely, when \TeX\ is finished on the current level, the former
+state is restored by calling |pop_nest|. This routine will never be
+called at the lowest semantic level, nor will it be called unless |head|
+is a node that should be returned to free memory.
+
+ at p static void pop_nest(void) /*leave a semantic level, re-enter the old*/
+{@+free_avail(head);decr(nest_ptr);cur_list=nest[nest_ptr];
+}
+
+@ Here is a procedure that displays what \TeX\ is working on, at all levels.
+
+ at p static void print_totals(void);
+static void show_activities(void)
+{@+int p; /*index into |nest|*/
+int @!m; /*mode*/
+memory_word @!a; /*auxiliary*/
+pointer @!q, @!r; /*for showing the current page*/
+int @!t; /*ditto*/
+nest[nest_ptr]=cur_list; /*put the top level into the array*/
+print_nl("");print_ln();
+for (p=nest_ptr; p>=0; p--)
+  {@+m=nest[p].mode_field;a=nest[p].aux_field;
+  print_nl("### ");print_mode(m);
+  print(" entered at line ");print_int(abs(nest[p].ml_field));
+  if (m==hmode) if (nest[p].pg_field!=040600000)
+    {@+print(" (language");print_int(nest[p].pg_field%0200000);
+    print(":hyphenmin");print_int(nest[p].pg_field/020000000);
+    print_char(',');print_int((nest[p].pg_field/0200000)%0100);
+    print_char(')');
+    }
+  if (nest[p].ml_field < 0) print(" (\\output routine)");
+  if (p==0)
+    {@+@<Show the status of the current page@>;
+    if (link(contrib_head)!=null)
+      print_nl("### recent contributions:");
+    }
+  show_box(link(nest[p].head_field));
+  @<Show the auxiliary field, |a|@>;
+  }
+}
+
+@ @<Show the auxiliary...@>=
+switch (abs(m)/(max_command+1)) {
+case 0: {@+print_nl("prevdepth ");
+  if (a.sc <= ignore_depth)
+  { if (a.sc <= unknown_depth) print("unknown"); else print("ignored"); }
+  else print_scaled(a.sc);
+  if (nest[p].pg_field!=0)
+    {@+print(", prevgraf ");
+    print_int(nest[p].pg_field);print(" line");
+    if (nest[p].pg_field!=1) print_char('s');
+    }
+  } @+break;
+case 1: {@+print_nl("spacefactor ");print_int(a.hh.lh);
+  if (m > 0) @+if (a.hh.rh > 0)
+    {@+print(", current language ");print_int(a.hh.rh);@+
+    }
+  } @+break;
+case 2: if (a.i!=null)
+  {@+print("this will begin denominator of:");show_box(a.i);@+
+  }
+}  /*there are no other cases*/
+
+@* The table of equivalents.
+Now that we have studied the data structures for \TeX's semantic routines,
+we ought to consider the data structures used by its syntactic routines. In
+other words, our next concern will be
+the tables that \TeX\ looks at when it is scanning
+what the user has written.
+
+The biggest and most important such table is called |eqtb|. It holds the
+current ``equivalents'' of things; i.e., it explains what things mean
+or what their current values are, for all quantities that are subject to
+the nesting structure provided by \TeX's grouping mechanism. There are six
+parts to |eqtb|:
+
+\yskip\hangg 1) |eqtb[active_base dotdot(hash_base-1)]| holds the current
+equivalents of single-character control sequences.
+
+\yskip\hangg 2) |eqtb[hash_base dotdot(glue_base-1)]| holds the current
+equivalents of multiletter control sequences.
+
+\yskip\hangg 3) |eqtb[glue_base dotdot(local_base-1)]| holds the current
+equivalents of glue parameters like the current baselineskip.
+
+\yskip\hangg 4) |eqtb[local_base dotdot(int_base-1)]| holds the current
+equivalents of local halfword quantities like the current box registers,
+the current ``catcodes,'' the current font, and a pointer to the current
+paragraph shape.
+
+\yskip\hangg 5) |eqtb[int_base dotdot(dimen_base-1)]| holds the current
+equivalents of fullword integer parameters like the current hyphenation
+penalty.
+
+\yskip\hangg 6) |eqtb[dimen_base dotdot eqtb_size]| holds the current equivalents
+of fullword dimension parameters like the current hsize or amount of
+hanging indentation.
+
+\yskip\noindent Note that, for example, the current amount of
+baselineskip glue is determined by the setting of a particular location
+in region~3 of |eqtb|, while the current meaning of the control sequence
+`\.{\\baselineskip}' (which might have been changed by \.{\\def} or
+\.{\\let}) appears in region~2.
+
+@ Each entry in |eqtb| is a |memory_word|. Most of these words are of type
+|two_halves|, and subdivided into three fields:
+
+\yskip\hangg 1) The |eq_level| (a quarterword) is the level of grouping at
+which this equivalent was defined. If the level is |level_zero|, the
+equivalent has never been defined; |level_one| refers to the outer level
+(outside of all groups), and this level is also used for global
+definitions that never go away. Higher levels are for equivalents that
+will disappear at the end of their group.  @^global definitions@>
+
+\yskip\hangg 2) The |eq_type| (another quarterword) specifies what kind of
+entry this is. There are many types, since each \TeX\ primitive like
+\.{\\hbox}, \.{\\def}, etc., has its own special code. The list of
+command codes above includes all possible settings of the |eq_type| field.
+
+\yskip\hangg 3) The |equiv| (a halfword) is the current equivalent value.
+This may be a font number, a pointer into |mem|, or a variety of other
+things.
+
+ at d eq_level_field(A) A.hh.b1
+ at d eq_type_field(A) A.hh.b0
+ at d equiv_field(A) A.hh.rh
+ at d eq_level(A) eq_level_field(eqtb[A]) /*level of definition*/
+ at d eq_type(A) eq_type_field(eqtb[A]) /*command code for equivalent*/
+ at d equiv(A) equiv_field(eqtb[A]) /*equivalent value*/
+ at d level_zero min_quarterword /*level for undefined quantities*/
+ at d level_one (level_zero+1) /*outermost level for defined quantities*/
+
+@ Many locations in |eqtb| have symbolic names. The purpose of the next
+paragraphs is to define these names, and to set up the initial values of the
+equivalents.
+
+In the first region we have 256 equivalents for ``active characters'' that
+act as control sequences, followed by 256 equivalents for single-character
+control sequences.
+
+Then comes region~2, which corresponds to the hash table that we will
+define later.  The maximum address in this region is used for a dummy
+control sequence that is perpetually undefined. There also are several
+locations for control sequences that are perpetually defined
+(since they are used in error recovery).
+
+ at d active_base 1 /*beginning of region 1, for active character equivalents*/
+ at d single_base (active_base+256) /*equivalents of one-character control sequences*/
+ at d null_cs (single_base+256) /*equivalent of \.{\\csname\\endcsname}*/
+ at d hash_base (null_cs+1) /*beginning of region 2, for the hash table*/
+ at d frozen_control_sequence (hash_base+hash_size) /*for error recovery*/
+ at d frozen_protection frozen_control_sequence /*inaccessible but definable*/
+ at d frozen_cr (frozen_control_sequence+1) /*permanent `\.{\\cr}'*/
+ at d frozen_end_group (frozen_control_sequence+2) /*permanent `\.{\\endgroup}'*/
+ at d frozen_right (frozen_control_sequence+3) /*permanent `\.{\\right}'*/
+ at d frozen_fi (frozen_control_sequence+4) /*permanent `\.{\\fi}'*/
+ at d frozen_end_template (frozen_control_sequence+5) /*permanent `\.{\\endtemplate}'*/
+ at d frozen_endv (frozen_control_sequence+6) /*second permanent `\.{\\endtemplate}'*/
+ at d frozen_relax (frozen_control_sequence+7) /*permanent `\.{\\relax}'*/
+ at d end_write (frozen_control_sequence+8) /*permanent `\.{\\endwrite}'*/
+ at d frozen_dont_expand (frozen_control_sequence+9)
+   /*permanent `\.{\\notexpanded:}'*/
+ at d frozen_primitive (frozen_control_sequence+10)
+   /*permanent `\.{\\primitive:}'*/
+ at d frozen_null_font (frozen_control_sequence+11)
+   /*permanent `\.{\\nullfont}'*/
+ at d font_id_base (frozen_null_font-font_base)
+   /*begins table of 257 permanent font identifiers*/
+ at d undefined_control_sequence (frozen_null_font+257) /*dummy location*/
+ at d glue_base (undefined_control_sequence+1) /*beginning of region 3*/
+
+@<Initialize table entries...@>=
+eq_type(undefined_control_sequence)=undefined_cs;
+equiv(undefined_control_sequence)=null;
+eq_level(undefined_control_sequence)=level_zero;
+for (k=active_base; k<=undefined_control_sequence-1; k++)
+  eqtb[k]=eqtb[undefined_control_sequence];
+
+@ Here is a routine that displays the current meaning of an |eqtb| entry
+in region 1 or~2. (Similar routines for the other regions will appear
+below.)
+
+@<Show equivalent |n|, in region 1 or 2@>=
+{@+sprint_cs(n);print_char('=');print_cmd_chr(eq_type(n), equiv(n));
+if (eq_type(n) >= call)
+  {@+print_char(':');show_token_list(link(equiv(n)), null, 32);
+  }
+}
+
+@ Region 3 of |eqtb| contains the 256 \.{\\skip} registers, as well as the
+glue parameters defined here. It is important that the ``muskip''
+parameters have larger numbers than the others.
+
+ at d line_skip_code 0 /*interline glue if |baseline_skip| is infeasible*/
+ at d baseline_skip_code 1 /*desired glue between baselines*/
+ at d par_skip_code 2 /*extra glue just above a paragraph*/
+ at d above_display_skip_code 3 /*extra glue just above displayed math*/
+ at d below_display_skip_code 4 /*extra glue just below displayed math*/
+ at d above_display_short_skip_code 5
+   /*glue above displayed math following short lines*/
+ at d below_display_short_skip_code 6
+   /*glue below displayed math following short lines*/
+ at d left_skip_code 7 /*glue at left of justified lines*/
+ at d right_skip_code 8 /*glue at right of justified lines*/
+ at d top_skip_code 9 /*glue at top of main pages*/
+ at d split_top_skip_code 10 /*glue at top of split pages*/
+ at d tab_skip_code 11 /*glue between aligned entries*/
+ at d space_skip_code 12 /*glue between words (if not |zero_glue|)*/
+ at d xspace_skip_code 13 /*glue after sentences (if not |zero_glue|)*/
+ at d par_fill_skip_code 14 /*glue on last line of paragraph*/
+ at d thin_mu_skip_code 15 /*thin space in math formula*/
+ at d med_mu_skip_code 16 /*medium space in math formula*/
+ at d thick_mu_skip_code 17 /*thick space in math formula*/
+ at d glue_pars 18 /*total number of glue parameters*/
+ at d skip_base (glue_base+glue_pars) /*table of 256 ``skip'' registers*/
+ at d mu_skip_base (skip_base+256) /*table of 256 ``muskip'' registers*/
+ at d local_base (mu_skip_base+256) /*beginning of region 4*/
+@#
+ at d skip(A) equiv(skip_base+A) /*|mem| location of glue specification*/
+ at d mu_skip(A) equiv(mu_skip_base+A) /*|mem| location of math glue spec*/
+ at d glue_par(A) equiv(glue_base+A) /*|mem| location of glue specification*/
+ at d line_skip glue_par(line_skip_code)
+ at d baseline_skip glue_par(baseline_skip_code)
+ at d par_skip glue_par(par_skip_code)
+ at d above_display_skip glue_par(above_display_skip_code)
+ at d below_display_skip glue_par(below_display_skip_code)
+ at d above_display_short_skip glue_par(above_display_short_skip_code)
+ at d below_display_short_skip glue_par(below_display_short_skip_code)
+ at d left_skip glue_par(left_skip_code)
+ at d right_skip glue_par(right_skip_code)
+ at d top_skip glue_par(top_skip_code)
+ at d split_top_skip glue_par(split_top_skip_code)
+ at d tab_skip glue_par(tab_skip_code)
+ at d space_skip glue_par(space_skip_code)
+ at d xspace_skip glue_par(xspace_skip_code)
+ at d par_fill_skip glue_par(par_fill_skip_code)
+ at d thin_mu_skip glue_par(thin_mu_skip_code)
+ at d med_mu_skip glue_par(med_mu_skip_code)
+ at d thick_mu_skip glue_par(thick_mu_skip_code)
+
+@<Current |mem| equivalent of glue parameter number |n|@>=glue_par(n)
+
+@ Sometimes we need to convert \TeX's internal code numbers into symbolic
+form. The |print_skip_param| routine gives the symbolic name of a glue
+parameter.
+
+@<Declare the procedure called |print_skip_param|@>=
+static void print_skip_param(int @!n)
+{@+switch (n) {
+case line_skip_code: print_esc("lineskip");@+break;
+case baseline_skip_code: print_esc("baselineskip");@+break;
+case par_skip_code: print_esc("parskip");@+break;
+case above_display_skip_code: print_esc("abovedisplayskip");@+break;
+case below_display_skip_code: print_esc("belowdisplayskip");@+break;
+case above_display_short_skip_code: print_esc("abovedisplayshortskip");@+break;
+case below_display_short_skip_code: print_esc("belowdisplayshortskip");@+break;
+case left_skip_code: print_esc("leftskip");@+break;
+case right_skip_code: print_esc("rightskip");@+break;
+case top_skip_code: print_esc("topskip");@+break;
+case split_top_skip_code: print_esc("splittopskip");@+break;
+case tab_skip_code: print_esc("tabskip");@+break;
+case space_skip_code: print_esc("spaceskip");@+break;
+case xspace_skip_code: print_esc("xspaceskip");@+break;
+case par_fill_skip_code: print_esc("parfillskip");@+break;
+case thin_mu_skip_code: print_esc("thinmuskip");@+break;
+case med_mu_skip_code: print_esc("medmuskip");@+break;
+case thick_mu_skip_code: print_esc("thickmuskip");@+break;
+default:print("[unknown glue parameter!]");
+}
+}
+
+@ The symbolic names for glue parameters are put into \TeX's hash table
+by using the routine called |primitive|, defined below. Let us enter them
+now, so that we don't have to list all those parameter names anywhere else.
+
+@<Put each of \TeX's primitives into the hash table@>=
+primitive("lineskip", assign_glue, glue_base+line_skip_code);@/
+@!@:line\_skip\_}{\.{\\lineskip} primitive@>
+primitive("baselineskip", assign_glue, glue_base+baseline_skip_code);@/
+@!@:baseline\_skip\_}{\.{\\baselineskip} primitive@>
+primitive("parskip", assign_glue, glue_base+par_skip_code);@/
+@!@:par\_skip\_}{\.{\\parskip} primitive@>
+primitive("abovedisplayskip", assign_glue, glue_base+above_display_skip_code);@/
+@!@:above\_display\_skip\_}{\.{\\abovedisplayskip} primitive@>
+primitive("belowdisplayskip", assign_glue, glue_base+below_display_skip_code);@/
+@!@:below\_display\_skip\_}{\.{\\belowdisplayskip} primitive@>
+primitive("abovedisplayshortskip",
+  assign_glue, glue_base+above_display_short_skip_code);@/
+@!@:above\_display\_short\_skip\_}{\.{\\abovedisplayshortskip} primitive@>
+primitive("belowdisplayshortskip",
+  assign_glue, glue_base+below_display_short_skip_code);@/
+@!@:below\_display\_short\_skip\_}{\.{\\belowdisplayshortskip} primitive@>
+primitive("leftskip", assign_glue, glue_base+left_skip_code);@/
+@!@:left\_skip\_}{\.{\\leftskip} primitive@>
+primitive("rightskip", assign_glue, glue_base+right_skip_code);@/
+@!@:right\_skip\_}{\.{\\rightskip} primitive@>
+primitive("topskip", assign_glue, glue_base+top_skip_code);@/
+@!@:top\_skip\_}{\.{\\topskip} primitive@>
+primitive("splittopskip", assign_glue, glue_base+split_top_skip_code);@/
+@!@:split\_top\_skip\_}{\.{\\splittopskip} primitive@>
+primitive("tabskip", assign_glue, glue_base+tab_skip_code);@/
+@!@:tab\_skip\_}{\.{\\tabskip} primitive@>
+primitive("spaceskip", assign_glue, glue_base+space_skip_code);@/
+@!@:space\_skip\_}{\.{\\spaceskip} primitive@>
+primitive("xspaceskip", assign_glue, glue_base+xspace_skip_code);@/
+@!@:xspace\_skip\_}{\.{\\xspaceskip} primitive@>
+primitive("parfillskip", assign_glue, glue_base+par_fill_skip_code);@/
+@!@:par\_fill\_skip\_}{\.{\\parfillskip} primitive@>
+primitive("thinmuskip", assign_mu_glue, glue_base+thin_mu_skip_code);@/
+@!@:thin\_mu\_skip\_}{\.{\\thinmuskip} primitive@>
+primitive("medmuskip", assign_mu_glue, glue_base+med_mu_skip_code);@/
+@!@:med\_mu\_skip\_}{\.{\\medmuskip} primitive@>
+primitive("thickmuskip", assign_mu_glue, glue_base+thick_mu_skip_code);@/
+@!@:thick\_mu\_skip\_}{\.{\\thickmuskip} primitive@>
+
+@ @<Cases of |print_cmd_chr| for symbolic printing of primitives@>=
+case assign_glue: case assign_mu_glue: if (chr_code < skip_base)
+    print_skip_param(chr_code-glue_base);
+  else if (chr_code < mu_skip_base)
+    {@+print_esc("skip");print_int(chr_code-skip_base);
+    }
+  else{@+print_esc("muskip");print_int(chr_code-mu_skip_base);
+    } @+break;
+
+@ All glue parameters and registers are initially `\.{0pt plus0pt minus0pt}'.
+
+@<Initialize table entries...@>=
+equiv(glue_base)=zero_glue;eq_level(glue_base)=level_one;
+eq_type(glue_base)=glue_ref;
+for (k=glue_base+1; k<=local_base-1; k++) eqtb[k]=eqtb[glue_base];
+glue_ref_count(zero_glue)=glue_ref_count(zero_glue)+local_base-glue_base;
+
+@ @<Show equivalent |n|, in region 3@>=
+if (n < skip_base)
+  {@+print_skip_param(n-glue_base);print_char('=');
+  if (n < glue_base+thin_mu_skip_code) print_spec(equiv(n),"pt");
+  else print_spec(equiv(n),"mu");
+  }
+else if (n < mu_skip_base)
+  {@+print_esc("skip");print_int(n-skip_base);print_char('=');
+  print_spec(equiv(n),"pt");
+  }
+else{@+print_esc("muskip");print_int(n-mu_skip_base);print_char('=');
+  print_spec(equiv(n),"mu");
+  }
+
+@ Region 4 of |eqtb| contains the local quantities defined here. The
+bulk of this region is taken up by five tables that are indexed by eight-bit
+characters; these tables are important to both the syntactic and semantic
+portions of \TeX. There are also a bunch of special things like font and
+token parameters, as well as the tables of \.{\\toks} and \.{\\box}
+registers.
+
+ at d par_shape_loc local_base /*specifies paragraph shape*/
+ at d output_routine_loc (local_base+1) /*points to token list for \.{\\output}*/
+ at d every_par_loc (local_base+2) /*points to token list for \.{\\everypar}*/
+ at d every_math_loc (local_base+3) /*points to token list for \.{\\everymath}*/
+ at d every_display_loc (local_base+4) /*points to token list for \.{\\everydisplay}*/
+ at d every_hbox_loc (local_base+5) /*points to token list for \.{\\everyhbox}*/
+ at d every_vbox_loc (local_base+6) /*points to token list for \.{\\everyvbox}*/
+ at d every_job_loc (local_base+7) /*points to token list for \.{\\everyjob}*/
+ at d every_cr_loc (local_base+8) /*points to token list for \.{\\everycr}*/
+ at d err_help_loc (local_base+9) /*points to token list for \.{\\errhelp}*/
+ at d tex_toks (local_base+10) /*end of \TeX's token list parameters*/
+@#
+ at d etex_toks_base tex_toks /*base for \eTeX's token list parameters*/
+ at d every_eof_loc etex_toks_base /*points to token list for \.{\\everyeof}*/
+ at d etex_toks (etex_toks_base+1) /*end of \eTeX's token list parameters*/
+@#
+ at d toks_base etex_toks /*table of 256 token list registers*/
+@#
+ at d etex_pen_base (toks_base+256) /*start of table of \eTeX's penalties*/
+ at d inter_line_penalties_loc etex_pen_base /*additional penalties between lines*/
+ at d club_penalties_loc (etex_pen_base+1) /*penalties for creating club lines*/
+ at d widow_penalties_loc (etex_pen_base+2) /*penalties for creating widow lines*/
+ at d display_widow_penalties_loc (etex_pen_base+3) /*ditto, just before a display*/
+ at d etex_pens (etex_pen_base+4) /*end of table of \eTeX's penalties*/
+@#
+ at d box_base etex_pens /*table of 256 box registers*/
+ at d cur_font_loc (box_base+256) /*internal font number outside math mode*/
+ at d math_font_base (cur_font_loc+1) /*table of 48 math font numbers*/
+ at d cat_code_base (math_font_base+48)
+   /*table of 256 command codes (the ``catcodes'')*/
+ at d lc_code_base (cat_code_base+256) /*table of 256 lowercase mappings*/
+ at d uc_code_base (lc_code_base+256) /*table of 256 uppercase mappings*/
+ at d sf_code_base (uc_code_base+256) /*table of 256 spacefactor mappings*/
+ at d math_code_base (sf_code_base+256) /*table of 256 math mode mappings*/
+ at d int_base (math_code_base+256) /*beginning of region 5*/
+@#
+ at d par_shape_ptr equiv(par_shape_loc)
+ at d output_routine equiv(output_routine_loc)
+ at d every_par equiv(every_par_loc)
+ at d every_math equiv(every_math_loc)
+ at d every_display equiv(every_display_loc)
+ at d every_hbox equiv(every_hbox_loc)
+ at d every_vbox equiv(every_vbox_loc)
+ at d every_job equiv(every_job_loc)
+ at d every_cr equiv(every_cr_loc)
+ at d err_help equiv(err_help_loc)
+ at d toks(X) equiv(toks_base+X)
+ at d box(A) equiv(box_base+A)
+ at d cur_font equiv(cur_font_loc)
+ at d fam_fnt(A) equiv(math_font_base+A)
+ at d cat_code(A) equiv(cat_code_base+A)
+ at d lc_code(A) equiv(lc_code_base+A)
+ at d uc_code(A) equiv(uc_code_base+A)
+ at d sf_code(A) equiv(sf_code_base+A)
+ at d math_code(A) equiv(math_code_base+A)
+   /*Note: |math_code(c)| is the true math code plus |min_halfword|*/
+
+@<Put each...@>=
+primitive("output", assign_toks, output_routine_loc);
+@!@:output\_}{\.{\\output} primitive@>
+primitive("everypar", assign_toks, every_par_loc);
+@!@:every\_par\_}{\.{\\everypar} primitive@>
+primitive("everymath", assign_toks, every_math_loc);
+@!@:every\_math\_}{\.{\\everymath} primitive@>
+primitive("everydisplay", assign_toks, every_display_loc);
+@!@:every\_display\_}{\.{\\everydisplay} primitive@>
+primitive("everyhbox", assign_toks, every_hbox_loc);
+@!@:every\_hbox\_}{\.{\\everyhbox} primitive@>
+primitive("everyvbox", assign_toks, every_vbox_loc);
+@!@:every\_vbox\_}{\.{\\everyvbox} primitive@>
+primitive("everyjob", assign_toks, every_job_loc);
+@!@:every\_job\_}{\.{\\everyjob} primitive@>
+primitive("everycr", assign_toks, every_cr_loc);
+@!@:every\_cr\_}{\.{\\everycr} primitive@>
+primitive("errhelp", assign_toks, err_help_loc);
+@!@:err\_help\_}{\.{\\errhelp} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case assign_toks: if (chr_code >= toks_base)
+  {@+print_esc("toks");print_int(chr_code-toks_base);
+  }
+else switch (chr_code) {
+  case output_routine_loc: print_esc("output");@+break;
+  case every_par_loc: print_esc("everypar");@+break;
+  case every_math_loc: print_esc("everymath");@+break;
+  case every_display_loc: print_esc("everydisplay");@+break;
+  case every_hbox_loc: print_esc("everyhbox");@+break;
+  case every_vbox_loc: print_esc("everyvbox");@+break;
+  case every_job_loc: print_esc("everyjob");@+break;
+  case every_cr_loc: print_esc("everycr");@+break;
+  @/@<Cases of |assign_toks| for |print_cmd_chr|@>@/
+  default:print_esc("errhelp");
+  } @+break;
+
+@ We initialize most things to null or undefined values. An undefined font
+is represented by the internal code |font_base|.
+
+However, the character code tables are given initial values based on the
+conventional interpretation of ASCII code. These initial values should
+not be changed when \TeX\ is adapted for use with non-English languages;
+all changes to the initialization conventions should be made in format
+packages, not in \TeX\ itself, so that global interchange of formats is
+possible.
+
+ at d null_font font_base
+ at d var_code 070000 /*math code meaning ``use the current family''*/
+
+@<Initialize table entries...@>=
+par_shape_ptr=null;eq_type(par_shape_loc)=shape_ref;
+eq_level(par_shape_loc)=level_one;@/
+for (k=etex_pen_base; k<=etex_pens-1; k++)
+  eqtb[k]=eqtb[par_shape_loc];
+for (k=output_routine_loc; k<=toks_base+255; k++)
+  eqtb[k]=eqtb[undefined_control_sequence];
+box(0)=null;eq_type(box_base)=box_ref;eq_level(box_base)=level_one;
+for (k=box_base+1; k<=box_base+255; k++) eqtb[k]=eqtb[box_base];
+cur_font=null_font;eq_type(cur_font_loc)=data;
+eq_level(cur_font_loc)=level_one;@/
+for (k=math_font_base; k<=math_font_base+47; k++) eqtb[k]=eqtb[cur_font_loc];
+equiv(cat_code_base)=0;eq_type(cat_code_base)=data;
+eq_level(cat_code_base)=level_one;@/
+for (k=cat_code_base+1; k<=int_base-1; k++) eqtb[k]=eqtb[cat_code_base];
+for (k=0; k<=255; k++)
+  {@+cat_code(k)=other_char;math_code(k)=hi(k);sf_code(k)=1000;
+  }
+cat_code(carriage_return)=car_ret;cat_code(' ')=spacer;
+cat_code('\\')=escape;cat_code('%')=comment;
+cat_code(invalid_code)=invalid_char;cat_code(null_code)=ignore;
+for (k='0'; k<='9'; k++) math_code(k)=hi(k+var_code);
+for (k='A'; k<='Z'; k++)
+  {@+cat_code(k)=letter;cat_code(k+'a'-'A')=letter;@/
+  math_code(k)=hi(k+var_code+0x100);
+  math_code(k+'a'-'A')=hi(k+'a'-'A'+var_code+0x100);@/
+  lc_code(k)=k+'a'-'A';lc_code(k+'a'-'A')=k+'a'-'A';@/
+  uc_code(k)=k;uc_code(k+'a'-'A')=k;@/
+  sf_code(k)=999;
+  }
+
+@ @<Show equivalent |n|, in region 4@>=
+if ((n==par_shape_loc)||((n >= etex_pen_base)&&(n < etex_pens)))
+  {@+print_cmd_chr(set_shape, n);print_char('=');
+  if (equiv(n)==null) print_char('0');
+  else if (n > par_shape_loc)
+    {@+print_int(penalty(equiv(n)));print_char(' ');
+    print_int(penalty(equiv(n)+1));
+    if (penalty(equiv(n)) > 1) print_esc("ETC.");
+    }
+  else print_int(info(par_shape_ptr));
+  }
+else if (n < toks_base)
+  {@+print_cmd_chr(assign_toks, n);print_char('=');
+  if (equiv(n)!=null) show_token_list(link(equiv(n)), null, 32);
+  }
+else if (n < box_base)
+  {@+print_esc("toks");print_int(n-toks_base);print_char('=');
+  if (equiv(n)!=null) show_token_list(link(equiv(n)), null, 32);
+  }
+else if (n < cur_font_loc)
+  {@+print_esc("box");print_int(n-box_base);print_char('=');
+  if (equiv(n)==null) print("void");
+  else{@+depth_threshold=0;breadth_max=1;show_node_list(equiv(n));
+    }
+  }
+else if (n < cat_code_base) @<Show the font identifier in |eqtb[n]|@>@;
+else@<Show the halfword code in |eqtb[n]|@>@;
+
+@ @<Show the font identifier in |eqtb[n]|@>=
+{@+if (n==cur_font_loc) print("current font");
+else if (n < math_font_base+16)
+  {@+print_esc("textfont");print_int(n-math_font_base);
+  }
+else if (n < math_font_base+32)
+  {@+print_esc("scriptfont");print_int(n-math_font_base-16);
+  }
+else{@+print_esc("scriptscriptfont");print_int(n-math_font_base-32);
+  }
+print_char('=');@/
+printn_esc(hash[font_id_base+equiv(n)].rh);
+   /*that's |font_id_text(equiv(n))|*/
+}
+
+@ @<Show the halfword code in |eqtb[n]|@>=
+if (n < math_code_base)
+  {@+if (n < lc_code_base)
+    {@+print_esc("catcode");print_int(n-cat_code_base);
+    }
+  else if (n < uc_code_base)
+    {@+print_esc("lccode");print_int(n-lc_code_base);
+    }
+  else if (n < sf_code_base)
+    {@+print_esc("uccode");print_int(n-uc_code_base);
+    }
+  else{@+print_esc("sfcode");print_int(n-sf_code_base);
+    }
+  print_char('=');print_int(equiv(n));
+  }
+else{@+print_esc("mathcode");print_int(n-math_code_base);
+  print_char('=');print_int(ho(equiv(n)));
+  }
+
+@ Region 5 of |eqtb| contains the integer parameters and registers defined
+here, as well as the |del_code| table. The latter table differs from the
+|cat_code dotdot math_code| tables that precede it, since delimiter codes are
+fullword integers while the other kinds of codes occupy at most a
+halfword. This is what makes region~5 different from region~4. We will
+store the |eq_level| information in an auxiliary array of quarterwords
+that will be defined later.
+
+ at d pretolerance_code 0 /*badness tolerance before hyphenation*/
+ at d tolerance_code 1 /*badness tolerance after hyphenation*/
+ at d line_penalty_code 2 /*added to the badness of every line*/
+ at d hyphen_penalty_code 3 /*penalty for break after discretionary hyphen*/
+ at d ex_hyphen_penalty_code 4 /*penalty for break after explicit hyphen*/
+ at d club_penalty_code 5 /*penalty for creating a club line*/
+ at d widow_penalty_code 6 /*penalty for creating a widow line*/
+ at d display_widow_penalty_code 7 /*ditto, just before a display*/
+ at d broken_penalty_code 8 /*penalty for breaking a page at a broken line*/
+ at d bin_op_penalty_code 9 /*penalty for breaking after a binary operation*/
+ at d rel_penalty_code 10 /*penalty for breaking after a relation*/
+ at d pre_display_penalty_code 11
+   /*penalty for breaking just before a displayed formula*/
+ at d post_display_penalty_code 12
+   /*penalty for breaking just after a displayed formula*/
+ at d inter_line_penalty_code 13 /*additional penalty between lines*/
+ at d double_hyphen_demerits_code 14 /*demerits for double hyphen break*/
+ at d final_hyphen_demerits_code 15 /*demerits for final hyphen break*/
+ at d adj_demerits_code 16 /*demerits for adjacent incompatible lines*/
+ at d mag_code 17 /*magnification ratio*/
+ at d delimiter_factor_code 18 /*ratio for variable-size delimiters*/
+ at d looseness_code 19 /*change in number of lines for a paragraph*/
+ at d time_code 20 /*current time of day*/
+ at d day_code 21 /*current day of the month*/
+ at d month_code 22 /*current month of the year*/
+ at d year_code 23 /*current year of our Lord*/
+ at d show_box_breadth_code 24 /*nodes per level in |show_box|*/
+ at d show_box_depth_code 25 /*maximum level in |show_box|*/
+ at d hbadness_code 26 /*hboxes exceeding this badness will be shown by |hpack|*/
+ at d vbadness_code 27 /*vboxes exceeding this badness will be shown by |vpack|*/
+ at d pausing_code 28 /*pause after each line is read from a file*/
+ at d tracing_online_code 29 /*show diagnostic output on terminal*/
+ at d tracing_macros_code 30 /*show macros as they are being expanded*/
+ at d tracing_stats_code 31 /*show memory usage if \TeX\ knows it*/
+ at d tracing_paragraphs_code 32 /*show line-break calculations*/
+ at d tracing_pages_code 33 /*show page-break calculations*/
+ at d tracing_output_code 34 /*show boxes when they are shipped out*/
+ at d tracing_lost_chars_code 35 /*show characters that aren't in the font*/
+ at d tracing_commands_code 36 /*show command codes at |big_switch|*/
+ at d tracing_restores_code 37 /*show equivalents when they are restored*/
+ at d uc_hyph_code 38 /*hyphenate words beginning with a capital letter*/
+ at d output_penalty_code 39 /*penalty found at current page break*/
+ at d max_dead_cycles_code 40 /*bound on consecutive dead cycles of output*/
+ at d hang_after_code 41 /*hanging indentation changes after this many lines*/
+ at d floating_penalty_code 42 /*penalty for insertions held over after a split*/
+ at d global_defs_code 43 /*override \.{\\global} specifications*/
+ at d cur_fam_code 44 /*current family*/
+ at d escape_char_code 45 /*escape character for token output*/
+ at d default_hyphen_char_code 46 /*value of \.{\\hyphenchar} when a font is loaded*/
+ at d default_skew_char_code 47 /*value of \.{\\skewchar} when a font is loaded*/
+ at d end_line_char_code 48 /*character placed at the right end of the buffer*/
+ at d new_line_char_code 49 /*character that prints as |print_ln|*/
+ at d language_code 50 /*current hyphenation table*/
+ at d left_hyphen_min_code 51 /*minimum left hyphenation fragment size*/
+ at d right_hyphen_min_code 52 /*minimum right hyphenation fragment size*/
+ at d holding_inserts_code 53 /*do not remove insertion nodes from \.{\\box255}*/
+ at d error_context_lines_code 54 /*maximum intermediate line pairs shown*/
+ at d tex_int_pars 55 /*total number of \TeX's integer parameters*/
+@#
+ at d etex_int_base tex_int_pars /*base for \eTeX's integer parameters*/
+ at d tracing_assigns_code etex_int_base /*show assignments*/
+ at d tracing_groups_code (etex_int_base+1) /*show save/restore groups*/
+ at d tracing_ifs_code (etex_int_base+2) /*show conditionals*/
+ at d tracing_scan_tokens_code (etex_int_base+3) /*show pseudo file open and close*/
+ at d tracing_nesting_code (etex_int_base+4) /*show incomplete groups and ifs within files*/
+ at d saving_vdiscards_code (etex_int_base+5) /*save items discarded from vlists*/
+ at d expand_depth_code (etex_int_base+6) /*maximum depth for expansion---\eTeX*/
+ at d eTeX_state_code (etex_int_base+7) /*\eTeX\ state variables*/
+ at d etex_int_pars (eTeX_state_code+eTeX_states) /*total number of \eTeX's integer parameters*/
+@#
+ at d int_pars etex_int_pars /*total number of integer parameters*/
+ at d count_base (int_base+int_pars) /*256 user \.{\\count} registers*/
+ at d del_code_base (count_base+256) /*256 delimiter code mappings*/
+ at d dimen_base (del_code_base+256) /*beginning of region 6*/
+@#
+ at d del_code(A) eqtb[del_code_base+A].i
+ at d count(A) eqtb[count_base+A].i
+ at d int_par(A) eqtb[int_base+A].i /*an integer parameter*/
+ at d pretolerance int_par(pretolerance_code)
+ at d tolerance int_par(tolerance_code)
+ at d line_penalty int_par(line_penalty_code)
+ at d hyphen_penalty int_par(hyphen_penalty_code)
+ at d ex_hyphen_penalty int_par(ex_hyphen_penalty_code)
+ at d club_penalty int_par(club_penalty_code)
+ at d widow_penalty int_par(widow_penalty_code)
+ at d display_widow_penalty int_par(display_widow_penalty_code)
+ at d broken_penalty int_par(broken_penalty_code)
+ at d bin_op_penalty int_par(bin_op_penalty_code)
+ at d rel_penalty int_par(rel_penalty_code)
+ at d pre_display_penalty int_par(pre_display_penalty_code)
+ at d post_display_penalty int_par(post_display_penalty_code)
+ at d inter_line_penalty int_par(inter_line_penalty_code)
+ at d double_hyphen_demerits int_par(double_hyphen_demerits_code)
+ at d final_hyphen_demerits int_par(final_hyphen_demerits_code)
+ at d adj_demerits int_par(adj_demerits_code)
+ at d mag int_par(mag_code)
+ at d delimiter_factor int_par(delimiter_factor_code)
+ at d looseness int_par(looseness_code)
+ at d time int_par(time_code)
+ at d day int_par(day_code)
+ at d month int_par(month_code)
+ at d year int_par(year_code)
+ at d show_box_breadth int_par(show_box_breadth_code)
+ at d show_box_depth int_par(show_box_depth_code)
+ at d hbadness int_par(hbadness_code)
+ at d vbadness int_par(vbadness_code)
+ at d pausing int_par(pausing_code)
+ at d tracing_online int_par(tracing_online_code)
+ at d tracing_macros int_par(tracing_macros_code)
+ at d tracing_stats int_par(tracing_stats_code)
+ at d tracing_paragraphs int_par(tracing_paragraphs_code)
+ at d tracing_pages int_par(tracing_pages_code)
+ at d tracing_output int_par(tracing_output_code)
+ at d tracing_lost_chars int_par(tracing_lost_chars_code)
+ at d tracing_commands int_par(tracing_commands_code)
+ at d tracing_restores int_par(tracing_restores_code)
+ at d uc_hyph int_par(uc_hyph_code)
+ at d output_penalty int_par(output_penalty_code)
+ at d max_dead_cycles int_par(max_dead_cycles_code)
+ at d hang_after int_par(hang_after_code)
+ at d floating_penalty int_par(floating_penalty_code)
+ at d global_defs int_par(global_defs_code)
+ at d cur_fam int_par(cur_fam_code)
+ at d escape_char int_par(escape_char_code)
+ at d default_hyphen_char int_par(default_hyphen_char_code)
+ at d default_skew_char int_par(default_skew_char_code)
+ at d end_line_char int_par(end_line_char_code)
+ at d new_line_char int_par(new_line_char_code)
+ at d language int_par(language_code)
+ at d left_hyphen_min int_par(left_hyphen_min_code)
+ at d right_hyphen_min int_par(right_hyphen_min_code)
+ at d holding_inserts int_par(holding_inserts_code)
+ at d error_context_lines int_par(error_context_lines_code)
+@#
+ at d tracing_assigns int_par(tracing_assigns_code)
+ at d tracing_groups int_par(tracing_groups_code)
+ at d tracing_ifs int_par(tracing_ifs_code)
+ at d tracing_scan_tokens int_par(tracing_scan_tokens_code)
+ at d tracing_nesting int_par(tracing_nesting_code)
+ at d expand_depth int_par(expand_depth_code)
+ at d saving_vdiscards int_par(saving_vdiscards_code)
+
+@<Assign the values |depth_threshold:=show_box_depth|...@>=
+depth_threshold=show_box_depth;
+breadth_max=show_box_breadth
+
+@ We can print the symbolic name of an integer parameter as follows.
+
+ at p static void print_param(int @!n)
+{@+switch (n) {
+case pretolerance_code: print_esc("pretolerance");@+break;
+case tolerance_code: print_esc("tolerance");@+break;
+case line_penalty_code: print_esc("linepenalty");@+break;
+case hyphen_penalty_code: print_esc("hyphenpenalty");@+break;
+case ex_hyphen_penalty_code: print_esc("exhyphenpenalty");@+break;
+case club_penalty_code: print_esc("clubpenalty");@+break;
+case widow_penalty_code: print_esc("widowpenalty");@+break;
+case display_widow_penalty_code: print_esc("displaywidowpenalty");@+break;
+case broken_penalty_code: print_esc("brokenpenalty");@+break;
+case bin_op_penalty_code: print_esc("binoppenalty");@+break;
+case rel_penalty_code: print_esc("relpenalty");@+break;
+case pre_display_penalty_code: print_esc("predisplaypenalty");@+break;
+case post_display_penalty_code: print_esc("postdisplaypenalty");@+break;
+case inter_line_penalty_code: print_esc("interlinepenalty");@+break;
+case double_hyphen_demerits_code: print_esc("doublehyphendemerits");@+break;
+case final_hyphen_demerits_code: print_esc("finalhyphendemerits");@+break;
+case adj_demerits_code: print_esc("adjdemerits");@+break;
+case mag_code: print_esc("mag");@+break;
+case delimiter_factor_code: print_esc("delimiterfactor");@+break;
+case looseness_code: print_esc("looseness");@+break;
+case time_code: print_esc("time");@+break;
+case day_code: print_esc("day");@+break;
+case month_code: print_esc("month");@+break;
+case year_code: print_esc("year");@+break;
+case show_box_breadth_code: print_esc("showboxbreadth");@+break;
+case show_box_depth_code: print_esc("showboxdepth");@+break;
+case hbadness_code: print_esc("hbadness");@+break;
+case vbadness_code: print_esc("vbadness");@+break;
+case pausing_code: print_esc("pausing");@+break;
+case tracing_online_code: print_esc("tracingonline");@+break;
+case tracing_macros_code: print_esc("tracingmacros");@+break;
+case tracing_stats_code: print_esc("tracingstats");@+break;
+case tracing_paragraphs_code: print_esc("tracingparagraphs");@+break;
+case tracing_pages_code: print_esc("tracingpages");@+break;
+case tracing_output_code: print_esc("tracingoutput");@+break;
+case tracing_lost_chars_code: print_esc("tracinglostchars");@+break;
+case tracing_commands_code: print_esc("tracingcommands");@+break;
+case tracing_restores_code: print_esc("tracingrestores");@+break;
+case uc_hyph_code: print_esc("uchyph");@+break;
+case output_penalty_code: print_esc("outputpenalty");@+break;
+case max_dead_cycles_code: print_esc("maxdeadcycles");@+break;
+case hang_after_code: print_esc("hangafter");@+break;
+case floating_penalty_code: print_esc("floatingpenalty");@+break;
+case global_defs_code: print_esc("globaldefs");@+break;
+case cur_fam_code: print_esc("fam");@+break;
+case escape_char_code: print_esc("escapechar");@+break;
+case default_hyphen_char_code: print_esc("defaulthyphenchar");@+break;
+case default_skew_char_code: print_esc("defaultskewchar");@+break;
+case end_line_char_code: print_esc("endlinechar");@+break;
+case new_line_char_code: print_esc("newlinechar");@+break;
+case language_code: print_esc("language");@+break;
+case left_hyphen_min_code: print_esc("lefthyphenmin");@+break;
+case right_hyphen_min_code: print_esc("righthyphenmin");@+break;
+case holding_inserts_code: print_esc("holdinginserts");@+break;
+case error_context_lines_code: print_esc("errorcontextlines");@+break;
+@/@<Cases for |print_param|@>@/
+default:print("[unknown integer parameter!]");
+}
+}
+
+@ The integer parameter names must be entered into the hash table.
+
+@<Put each...@>=
+primitive("pretolerance", assign_int, int_base+pretolerance_code);@/
+@!@:pretolerance\_}{\.{\\pretolerance} primitive@>
+primitive("tolerance", assign_int, int_base+tolerance_code);@/
+@!@:tolerance\_}{\.{\\tolerance} primitive@>
+primitive("linepenalty", assign_int, int_base+line_penalty_code);@/
+@!@:line\_penalty\_}{\.{\\linepenalty} primitive@>
+primitive("hyphenpenalty", assign_int, int_base+hyphen_penalty_code);@/
+@!@:hyphen\_penalty\_}{\.{\\hyphenpenalty} primitive@>
+primitive("exhyphenpenalty", assign_int, int_base+ex_hyphen_penalty_code);@/
+@!@:ex\_hyphen\_penalty\_}{\.{\\exhyphenpenalty} primitive@>
+primitive("clubpenalty", assign_int, int_base+club_penalty_code);@/
+@!@:club\_penalty\_}{\.{\\clubpenalty} primitive@>
+primitive("widowpenalty", assign_int, int_base+widow_penalty_code);@/
+@!@:widow\_penalty\_}{\.{\\widowpenalty} primitive@>
+primitive("displaywidowpenalty",
+  assign_int, int_base+display_widow_penalty_code);@/
+@!@:display\_widow\_penalty\_}{\.{\\displaywidowpenalty} primitive@>
+primitive("brokenpenalty", assign_int, int_base+broken_penalty_code);@/
+@!@:broken\_penalty\_}{\.{\\brokenpenalty} primitive@>
+primitive("binoppenalty", assign_int, int_base+bin_op_penalty_code);@/
+@!@:bin\_op\_penalty\_}{\.{\\binoppenalty} primitive@>
+primitive("relpenalty", assign_int, int_base+rel_penalty_code);@/
+@!@:rel\_penalty\_}{\.{\\relpenalty} primitive@>
+primitive("predisplaypenalty", assign_int, int_base+pre_display_penalty_code);@/
+@!@:pre\_display\_penalty\_}{\.{\\predisplaypenalty} primitive@>
+primitive("postdisplaypenalty", assign_int, int_base+post_display_penalty_code);@/
+@!@:post\_display\_penalty\_}{\.{\\postdisplaypenalty} primitive@>
+primitive("interlinepenalty", assign_int, int_base+inter_line_penalty_code);@/
+@!@:inter\_line\_penalty\_}{\.{\\interlinepenalty} primitive@>
+primitive("doublehyphendemerits",
+  assign_int, int_base+double_hyphen_demerits_code);@/
+@!@:double\_hyphen\_demerits\_}{\.{\\doublehyphendemerits} primitive@>
+primitive("finalhyphendemerits",
+  assign_int, int_base+final_hyphen_demerits_code);@/
+@!@:final\_hyphen\_demerits\_}{\.{\\finalhyphendemerits} primitive@>
+primitive("adjdemerits", assign_int, int_base+adj_demerits_code);@/
+@!@:adj\_demerits\_}{\.{\\adjdemerits} primitive@>
+primitive("mag", assign_int, int_base+mag_code);@/
+@!@:mag\_}{\.{\\mag} primitive@>
+primitive("delimiterfactor", assign_int, int_base+delimiter_factor_code);@/
+@!@:delimiter\_factor\_}{\.{\\delimiterfactor} primitive@>
+primitive("looseness", assign_int, int_base+looseness_code);@/
+@!@:looseness\_}{\.{\\looseness} primitive@>
+primitive("time", assign_int, int_base+time_code);@/
+@!@:time\_}{\.{\\time} primitive@>
+primitive("day", assign_int, int_base+day_code);@/
+@!@:day\_}{\.{\\day} primitive@>
+primitive("month", assign_int, int_base+month_code);@/
+@!@:month\_}{\.{\\month} primitive@>
+primitive("year", assign_int, int_base+year_code);@/
+@!@:year\_}{\.{\\year} primitive@>
+primitive("showboxbreadth", assign_int, int_base+show_box_breadth_code);@/
+@!@:show\_box\_breadth\_}{\.{\\showboxbreadth} primitive@>
+primitive("showboxdepth", assign_int, int_base+show_box_depth_code);@/
+@!@:show\_box\_depth\_}{\.{\\showboxdepth} primitive@>
+primitive("hbadness", assign_int, int_base+hbadness_code);@/
+@!@:hbadness\_}{\.{\\hbadness} primitive@>
+primitive("vbadness", assign_int, int_base+vbadness_code);@/
+@!@:vbadness\_}{\.{\\vbadness} primitive@>
+primitive("pausing", assign_int, int_base+pausing_code);@/
+@!@:pausing\_}{\.{\\pausing} primitive@>
+primitive("tracingonline", assign_int, int_base+tracing_online_code);@/
+@!@:tracing\_online\_}{\.{\\tracingonline} primitive@>
+primitive("tracingmacros", assign_int, int_base+tracing_macros_code);@/
+@!@:tracing\_macros\_}{\.{\\tracingmacros} primitive@>
+primitive("tracingstats", assign_int, int_base+tracing_stats_code);@/
+@!@:tracing\_stats\_}{\.{\\tracingstats} primitive@>
+primitive("tracingparagraphs", assign_int, int_base+tracing_paragraphs_code);@/
+@!@:tracing\_paragraphs\_}{\.{\\tracingparagraphs} primitive@>
+primitive("tracingpages", assign_int, int_base+tracing_pages_code);@/
+@!@:tracing\_pages\_}{\.{\\tracingpages} primitive@>
+primitive("tracingoutput", assign_int, int_base+tracing_output_code);@/
+@!@:tracing\_output\_}{\.{\\tracingoutput} primitive@>
+primitive("tracinglostchars", assign_int, int_base+tracing_lost_chars_code);@/
+@!@:tracing\_lost\_chars\_}{\.{\\tracinglostchars} primitive@>
+primitive("tracingcommands", assign_int, int_base+tracing_commands_code);@/
+@!@:tracing\_commands\_}{\.{\\tracingcommands} primitive@>
+primitive("tracingrestores", assign_int, int_base+tracing_restores_code);@/
+@!@:tracing\_restores\_}{\.{\\tracingrestores} primitive@>
+primitive("uchyph", assign_int, int_base+uc_hyph_code);@/
+@!@:uc\_hyph\_}{\.{\\uchyph} primitive@>
+primitive("outputpenalty", assign_int, int_base+output_penalty_code);@/
+@!@:output\_penalty\_}{\.{\\outputpenalty} primitive@>
+primitive("maxdeadcycles", assign_int, int_base+max_dead_cycles_code);@/
+@!@:max\_dead\_cycles\_}{\.{\\maxdeadcycles} primitive@>
+primitive("hangafter", assign_int, int_base+hang_after_code);@/
+@!@:hang\_after\_}{\.{\\hangafter} primitive@>
+primitive("floatingpenalty", assign_int, int_base+floating_penalty_code);@/
+@!@:floating\_penalty\_}{\.{\\floatingpenalty} primitive@>
+primitive("globaldefs", assign_int, int_base+global_defs_code);@/
+@!@:global\_defs\_}{\.{\\globaldefs} primitive@>
+primitive("fam", assign_int, int_base+cur_fam_code);@/
+@!@:fam\_}{\.{\\fam} primitive@>
+primitive("escapechar", assign_int, int_base+escape_char_code);@/
+@!@:escape\_char\_}{\.{\\escapechar} primitive@>
+primitive("defaulthyphenchar", assign_int, int_base+default_hyphen_char_code);@/
+@!@:default\_hyphen\_char\_}{\.{\\defaulthyphenchar} primitive@>
+primitive("defaultskewchar", assign_int, int_base+default_skew_char_code);@/
+@!@:default\_skew\_char\_}{\.{\\defaultskewchar} primitive@>
+primitive("endlinechar", assign_int, int_base+end_line_char_code);@/
+@!@:end\_line\_char\_}{\.{\\endlinechar} primitive@>
+primitive("newlinechar", assign_int, int_base+new_line_char_code);@/
+@!@:new\_line\_char\_}{\.{\\newlinechar} primitive@>
+primitive("language", assign_int, int_base+language_code);@/
+@!@:language\_}{\.{\\language} primitive@>
+primitive("lefthyphenmin", assign_int, int_base+left_hyphen_min_code);@/
+@!@:left\_hyphen\_min\_}{\.{\\lefthyphenmin} primitive@>
+primitive("righthyphenmin", assign_int, int_base+right_hyphen_min_code);@/
+@!@:right\_hyphen\_min\_}{\.{\\righthyphenmin} primitive@>
+primitive("holdinginserts", assign_int, int_base+holding_inserts_code);@/
+@!@:holding\_inserts\_}{\.{\\holdinginserts} primitive@>
+primitive("errorcontextlines", assign_int, int_base+error_context_lines_code);@/
+@!@:error\_context\_lines\_}{\.{\\errorcontextlines} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case assign_int: if (chr_code < count_base) print_param(chr_code-int_base);
+  else{@+print_esc("count");print_int(chr_code-count_base);
+    } @+break;
+
+@ The integer parameters should really be initialized by a macro package;
+the following initialization does the minimum to keep \TeX\ from
+complete failure.
+@^null delimiter@>
+
+@<Initialize table entries...@>=
+for (k=int_base; k<=del_code_base-1; k++) eqtb[k].i=0;
+mag=1000;tolerance=10000;hang_after=1;max_dead_cycles=25;
+escape_char='\\';end_line_char=carriage_return;
+for (k=0; k<=255; k++) del_code(k)=-1;
+del_code('.')=0; /*this null delimiter is used in error recovery*/
+
+@ The following procedure, which is called just before \TeX\ initializes its
+input and output, establishes the initial values of the date and time.
+This does include too, for system integrators, the creation date and
+the reference moment for the timer---\Prote\ extensions. If the system
+supports environment variables, if |FORCE_SOURCE_DATE| is set to $1$ and
+|SOURCE_DATE_EPOCH| is set, the date related values: year, month, day
+and time, including creation date, will be taken relative from the value
+defined by |SOURCE_DATE_EPOCH|.
+@^creation date@>
+@^reference time@>
+@^system dependencies@>
+k\TeX\ calls |tl_now| to obtain the current time (UTC) as a |tm| structure.
+ at p static void fix_date_and_time(void)
+{@+ struct tm *gmt=tl_now();
+  time=sys_time= gmt->tm_hour*60+gmt->tm_min;/*minutes since midnight*/
+  day=sys_day= gmt->tm_mday;/*day of the month*/
+  month=sys_month=gmt->tm_mon+1;/*month of the year*/
+  year=sys_year=gmt->tm_year+1900;/*Anno Domini*/
+}
+
+@ @<Show equivalent |n|, in region 5@>=
+{@+if (n < count_base) print_param(n-int_base);
+else if (n < del_code_base)
+  {@+print_esc("count");print_int(n-count_base);
+  }
+else{@+print_esc("delcode");print_int(n-del_code_base);
+  }
+print_char('=');print_int(eqtb[n].i);
+}
+
+@ @<Set variable |c| to the current escape character@>=c=escape_char
+
+@ @<Character |s| is the current new-line character@>=s==new_line_char
+
+@ \TeX\ is occasionally supposed to print diagnostic information that
+goes only into the transcript file, unless |tracing_online| is positive.
+Here are two routines that adjust the destination of print commands:
+
+ at p static void begin_diagnostic(void) /*prepare to do some tracing*/
+{@+old_setting=selector;
+if ((tracing_online <= 0)&&(selector==term_and_log))
+  {@+decr(selector);
+  if (history==spotless) history=warning_issued;
+  }
+}
+@#
+static void end_diagnostic(bool @!blank_line)
+   /*restore proper conditions after tracing*/
+{@+print_nl("");
+if (blank_line) print_ln();
+selector=old_setting;
+}
+
+@ Of course we had better declare a few more global variables, if the previous
+routines are going to work.
+
+@<Glob...@>=
+static int @!old_setting;
+static int @!sys_time, @!sys_day, @!sys_month, @!sys_year;
+     /*date and time supplied by external system*/
+
+@ The final region of |eqtb| contains the dimension parameters defined
+here, and the 256 \.{\\dimen} registers.
+
+ at d par_indent_code 0 /*indentation of paragraphs*/
+ at d math_surround_code 1 /*space around math in text*/
+ at d line_skip_limit_code 2 /*threshold for |line_skip| instead of |baseline_skip|*/
+ at d hsize_code 3 /*line width in horizontal mode*/
+ at d vsize_code 4 /*page height in vertical mode*/
+ at d max_depth_code 5 /*maximum depth of boxes on main pages*/
+ at d split_max_depth_code 6 /*maximum depth of boxes on split pages*/
+ at d box_max_depth_code 7 /*maximum depth of explicit vboxes*/
+ at d hfuzz_code 8 /*tolerance for overfull hbox messages*/
+ at d vfuzz_code 9 /*tolerance for overfull vbox messages*/
+ at d delimiter_shortfall_code 10 /*maximum amount uncovered by variable delimiters*/
+ at d null_delimiter_space_code 11 /*blank space in null delimiters*/
+ at d script_space_code 12 /*extra space after subscript or superscript*/
+ at d pre_display_size_code 13 /*length of text preceding a display*/
+ at d display_width_code 14 /*length of line for displayed equation*/
+ at d display_indent_code 15 /*indentation of line for displayed equation*/
+ at d overfull_rule_code 16 /*width of rule that identifies overfull hboxes*/
+ at d hang_indent_code 17 /*amount of hanging indentation*/
+ at d h_offset_code 18 /*amount of horizontal offset when shipping pages out*/
+ at d v_offset_code 19 /*amount of vertical offset when shipping pages out*/
+ at d emergency_stretch_code 20 /*reduces badnesses on final pass of line-breaking*/
+ at d page_width_code 21 /*current paper page width*/
+ at d page_height_code 22 /*current paper page height*/
+ at d dimen_pars 23 /*total number of dimension parameters*/
+ at d scaled_base (dimen_base+dimen_pars)
+   /*table of 256 user-defined \.{\\dimen} registers*/
+ at d eqtb_size (scaled_base+255) /*largest subscript of |eqtb|*/
+@#
+ at d dimen(A) eqtb[scaled_base+A].sc
+ at d dimen_par(A) eqtb[dimen_base+A].sc /*a scaled quantity*/
+ at d dimen_hfactor(A) hfactor_eqtb[scaled_base+A].sc
+ at d dimen_vfactor(A) vfactor_eqtb[scaled_base+A].sc
+ at d dimen_par_hfactor(A) hfactor_eqtb[dimen_base+A].sc
+ at d dimen_par_vfactor(A) vfactor_eqtb[dimen_base+A].sc
+ at d par_indent dimen_par(par_indent_code)
+ at d math_surround dimen_par(math_surround_code)
+ at d line_skip_limit dimen_par(line_skip_limit_code)
+ at d hsize dimen_par(hsize_code)
+ at d vsize dimen_par(vsize_code)
+ at d max_depth dimen_par(max_depth_code)
+ at d split_max_depth dimen_par(split_max_depth_code)
+ at d box_max_depth dimen_par(box_max_depth_code)
+ at d hfuzz dimen_par(hfuzz_code)
+ at d vfuzz dimen_par(vfuzz_code)
+ at d delimiter_shortfall dimen_par(delimiter_shortfall_code)
+ at d null_delimiter_space dimen_par(null_delimiter_space_code)
+ at d script_space dimen_par(script_space_code)
+ at d pre_display_size dimen_par(pre_display_size_code)
+ at d display_width dimen_par(display_width_code)
+ at d display_indent dimen_par(display_indent_code)
+ at d overfull_rule dimen_par(overfull_rule_code)
+ at d hang_indent dimen_par(hang_indent_code)
+ at d h_offset dimen_par(h_offset_code)
+ at d v_offset dimen_par(v_offset_code)
+ at d emergency_stretch dimen_par(emergency_stretch_code)
+ at d page_height dimen_par(page_height_code)
+
+ at p static void print_length_param(int @!n)
+{@+switch (n) {
+case par_indent_code: print_esc("parindent");@+break;
+case math_surround_code: print_esc("mathsurround");@+break;
+case line_skip_limit_code: print_esc("lineskiplimit");@+break;
+case hsize_code: print_esc("hsize");@+break;
+case vsize_code: print_esc("vsize");@+break;
+case max_depth_code: print_esc("maxdepth");@+break;
+case split_max_depth_code: print_esc("splitmaxdepth");@+break;
+case box_max_depth_code: print_esc("boxmaxdepth");@+break;
+case hfuzz_code: print_esc("hfuzz");@+break;
+case vfuzz_code: print_esc("vfuzz");@+break;
+case delimiter_shortfall_code: print_esc("delimitershortfall");@+break;
+case null_delimiter_space_code: print_esc("nulldelimiterspace");@+break;
+case script_space_code: print_esc("scriptspace");@+break;
+case pre_display_size_code: print_esc("predisplaysize");@+break;
+case display_width_code: print_esc("displaywidth");@+break;
+case display_indent_code: print_esc("displayindent");@+break;
+case overfull_rule_code: print_esc("overfullrule");@+break;
+case hang_indent_code: print_esc("hangindent");@+break;
+case h_offset_code: print_esc("hoffset");@+break;
+case v_offset_code: print_esc("voffset");@+break;
+case emergency_stretch_code: print_esc("emergencystretch");@+break;
+case page_width_code: print_esc("pagewidth");@+break;
+case page_height_code: print_esc("pageheight");@+break;
+default:print("[unknown dimen parameter!]");
+}
+}
+
+@ @<Put each...@>=
+primitive("parindent", assign_dimen, dimen_base+par_indent_code);@/
+@!@:par\_indent\_}{\.{\\parindent} primitive@>
+primitive("mathsurround", assign_dimen, dimen_base+math_surround_code);@/
+@!@:math\_surround\_}{\.{\\mathsurround} primitive@>
+primitive("lineskiplimit", assign_dimen, dimen_base+line_skip_limit_code);@/
+@!@:line\_skip\_limit\_}{\.{\\lineskiplimit} primitive@>
+primitive("hsize", assign_dimen, dimen_base+hsize_code);@/
+@!@:hsize\_}{\.{\\hsize} primitive@>
+primitive("vsize", assign_dimen, dimen_base+vsize_code);@/
+@!@:vsize\_}{\.{\\vsize} primitive@>
+primitive("maxdepth", assign_dimen, dimen_base+max_depth_code);@/
+@!@:max\_depth\_}{\.{\\maxdepth} primitive@>
+primitive("splitmaxdepth", assign_dimen, dimen_base+split_max_depth_code);@/
+@!@:split\_max\_depth\_}{\.{\\splitmaxdepth} primitive@>
+primitive("boxmaxdepth", assign_dimen, dimen_base+box_max_depth_code);@/
+@!@:box\_max\_depth\_}{\.{\\boxmaxdepth} primitive@>
+primitive("hfuzz", assign_dimen, dimen_base+hfuzz_code);@/
+@!@:hfuzz\_}{\.{\\hfuzz} primitive@>
+primitive("vfuzz", assign_dimen, dimen_base+vfuzz_code);@/
+@!@:vfuzz\_}{\.{\\vfuzz} primitive@>
+primitive("delimitershortfall",
+  assign_dimen, dimen_base+delimiter_shortfall_code);@/
+@!@:delimiter\_shortfall\_}{\.{\\delimitershortfall} primitive@>
+primitive("nulldelimiterspace",
+  assign_dimen, dimen_base+null_delimiter_space_code);@/
+@!@:null\_delimiter\_space\_}{\.{\\nulldelimiterspace} primitive@>
+primitive("scriptspace", assign_dimen, dimen_base+script_space_code);@/
+@!@:script\_space\_}{\.{\\scriptspace} primitive@>
+primitive("predisplaysize", assign_dimen, dimen_base+pre_display_size_code);@/
+@!@:pre\_display\_size\_}{\.{\\predisplaysize} primitive@>
+primitive("displaywidth", assign_dimen, dimen_base+display_width_code);@/
+@!@:display\_width\_}{\.{\\displaywidth} primitive@>
+primitive("displayindent", assign_dimen, dimen_base+display_indent_code);@/
+@!@:display\_indent\_}{\.{\\displayindent} primitive@>
+primitive("overfullrule", assign_dimen, dimen_base+overfull_rule_code);@/
+@!@:overfull\_rule\_}{\.{\\overfullrule} primitive@>
+primitive("hangindent", assign_dimen, dimen_base+hang_indent_code);@/
+@!@:hang\_indent\_}{\.{\\hangindent} primitive@>
+primitive("hoffset", assign_dimen, dimen_base+h_offset_code);@/
+@!@:h\_offset\_}{\.{\\hoffset} primitive@>
+primitive("voffset", assign_dimen, dimen_base+v_offset_code);@/
+@!@:v\_offset\_}{\.{\\voffset} primitive@>
+primitive("emergencystretch", assign_dimen, dimen_base+emergency_stretch_code);@/
+@!@:emergency\_stretch\_}{\.{\\emergencystretch} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case assign_dimen: if (chr_code < scaled_base)
+    print_length_param(chr_code-dimen_base);
+  else{@+print_esc("dimen");print_int(chr_code-scaled_base);
+    } @+break;
+
+@ @<Initialize table entries...@>=
+for (k=dimen_base; k<=eqtb_size; k++) hfactor_eqtb[k].sc=vfactor_eqtb[k].sc=eqtb[k].sc=0;
+
+@ @<Show equivalent |n|, in region 6@>=
+{@+if (n < scaled_base) print_length_param(n-dimen_base);
+else{@+print_esc("dimen");print_int(n-scaled_base);
+  }
+print_char('=');print_scaled(eqtb[n].sc);print("pt");
+}
+
+@ Here is a procedure that displays the contents of |eqtb[n]|
+symbolically.
+
+ at p @t\4@>@<Declare the procedure called |print_cmd_chr|@>@;@/
+#ifdef @!STAT
+static void show_eqtb(pointer @!n)
+{@+if (n < active_base) print_char('?'); /*this can't happen*/
+else if (n < glue_base) @<Show equivalent |n|, in region 1 or 2@>@;
+else if (n < local_base) @<Show equivalent |n|, in region 3@>@;
+else if (n < int_base) @<Show equivalent |n|, in region 4@>@;
+else if (n < dimen_base) @<Show equivalent |n|, in region 5@>@;
+else if (n <= eqtb_size) @<Show equivalent |n|, in region 6@>@;
+else print_char('?'); /*this can't happen either*/
+}
+#endif
+
+@ The last two regions of |eqtb| have fullword values instead of the
+three fields |eq_level|, |eq_type|, and |equiv|. An |eq_type| is unnecessary,
+but \TeX\ needs to store the |eq_level| information in another array
+called |xeq_level|.
+
+@<Glob...@>=
+static memory_word @!eqtb0[eqtb_size-active_base+1], *const @!eqtb = @!eqtb0-active_base;
+static memory_word hfactor_eqtb0[dimen_pars+256]={{{0}}}, *const @!hfactor_eqtb = @!hfactor_eqtb0-dimen_base;
+static memory_word vfactor_eqtb0[dimen_pars+256]={{{0}}}, *const @!vfactor_eqtb = @!vfactor_eqtb0-dimen_base;
+static scaled par_shape_hfactor=0, par_shape_vfactor=0;
+static scaled hhsize=0,hvsize=0;
+static quarterword @!xeq_level0[eqtb_size-int_base+1], *const @!xeq_level = @!xeq_level0-int_base;
+
+@ @<Set init...@>=
+for (k=int_base; k<=eqtb_size; k++) xeq_level[k]=level_one;
+
+@ When the debugging routine |search_mem| is looking for pointers having a
+given value, it is interested only in regions 1 to~3 of~|eqtb|, and in the
+first part of region~4.
+
+@<Search |eqtb| for equivalents equal to |p|@>=
+for (q=active_base; q<=box_base+255; q++)
+  {@+if (equiv(q)==p)
+    {@+print_nl("EQUIV(");print_int(q);print_char(')');
+    }
+  }
+
+@* The hash table.
+Control sequences are stored and retrieved by means of a fairly standard hash
+table algorithm called the method of ``coalescing lists'' (cf.\ Algorithm 6.4C
+in {\sl The Art of Computer Programming\/}). Once a control sequence enters the
+table, it is never removed, because there are complicated situations
+involving \.{\\gdef} where the removal of a control sequence at the end of
+a group would be a mistake preventable only by the introduction of a
+complicated reference-count mechanism.
+
+The actual sequence of letters forming a control sequence identifier is
+stored in the |str_pool| array together with all the other strings. An
+auxiliary array |hash| consists of items with two halfword fields per
+word. The first of these, called |next(p)|, points to the next identifier
+belonging to the same coalesced list as the identifier corresponding to~|p|;
+and the other, called |text(p)|, points to the |str_start| entry for
+|p|'s identifier. If position~|p| of the hash table is empty, we have
+|text(p)==0|; if position |p| is either empty or the end of a coalesced
+hash list, we have |next(p)==0|. An auxiliary pointer variable called
+|hash_used| is maintained in such a way that all locations |p >= hash_used|
+are nonempty. The global variable |cs_count| tells how many multiletter
+control sequences have been defined, if statistics are being kept.
+
+A global boolean variable called |no_new_control_sequence| is set to
+|true| during the time that new hash table entries are forbidden.
+
+ at d next(A) hash[A].lh /*link for coalesced lists*/
+ at d text(A) hash[A].rh /*string number for control sequence name*/
+ at d hash_is_full (hash_used==hash_base) /*test if all positions are occupied*/
+ at d font_id_text(A) text(font_id_base+A) /*a frozen font identifier's name*/
+
+@<Glob...@>=
+static two_halves @!hash0[undefined_control_sequence-hash_base], *const @!hash = @!hash0-hash_base;
+   /*the hash table*/
+static pointer @!hash_used; /*allocation pointer for |hash|*/
+static bool @!no_new_control_sequence; /*are new identifiers legal?*/
+static int @!cs_count; /*total number of known identifiers*/
+
+@ @<Set init...@>=
+no_new_control_sequence=true; /*new identifiers are usually forbidden*/
+next(hash_base)=0;text(hash_base)=0;
+for (k=hash_base+1; k<=undefined_control_sequence-1; k++) hash[k]=hash[hash_base];
+
+@ @<Initialize table entries...@>=
+hash_used=frozen_control_sequence; /*nothing is used*/
+cs_count=0;
+eq_type(frozen_dont_expand)=dont_expand;
+text(frozen_dont_expand)=s_no("notexpanded:");
+ at .notexpanded:@>
+
+@ Here is the subroutine that searches the hash table for an identifier
+that matches a given string of length |l > 1| appearing in |buffer[j dotdot
+(j+l-1)]|. If the identifier is found, the corresponding hash table address
+is returned. Otherwise, if the global variable |no_new_control_sequence|
+is |true|, the dummy address |undefined_control_sequence| is returned.
+Otherwise the identifier is inserted into the hash table and its location
+is returned.
+
+ at p static pointer id_lookup(int @!j, int @!l) /*search the hash table*/
+{@+ /*go here if you found it*/
+int h; /*hash code*/
+int @!d; /*number of characters in incomplete current string*/
+pointer @!p; /*index in |hash| array*/
+int @!k; /*index in |buffer| array*/
+@<Compute the hash code |h|@>;
+p=h+hash_base; /*we start searching here; note that |0 <= h < hash_prime|*/
+loop at +{@+if (text(p) > 0) if (length(text(p))==l)
+    if (str_eq_buf(text(p), j)) goto found;
+  if (next(p)==0)
+    {@+if (no_new_control_sequence)
+      p=undefined_control_sequence;
+    else@<Insert a new control sequence after |p|, then make |p| point to it@>;
+    goto found;
+    }
+  p=next(p);
+  }
+found: return p;
+}
+
+@ @<Insert a new control...@>=
+{@+if (text(p) > 0)
+  {@+@/do at +{if (hash_is_full) overflow("hash size", hash_size);
+@:TeX capacity exceeded hash size}{\quad hash size@>
+  decr(hash_used);
+  }@+ while (!(text(hash_used)==0)); /*search for an empty location in |hash|*/
+  next(p)=hash_used;p=hash_used;
+  }
+str_room(l);d=cur_length;
+while (pool_ptr > str_start[str_ptr])
+  {@+decr(pool_ptr);str_pool[pool_ptr+l]=str_pool[pool_ptr];
+  }  /*move current string up to make room for another*/
+for (k=j; k<=j+l-1; k++) append_char(buffer[k]);
+text(p)=make_string();pool_ptr=pool_ptr+d;
+#ifdef @!STAT
+incr(cs_count);
+#endif
+@;@/
+}
+
+@ The value of |hash_prime| should be roughly 85\pct! of |hash_size|, and it
+should be a prime number.  The theory of hashing tells us to expect fewer
+than two table probes, on the average, when the search is successful.
+[See J.~S. Vitter, {\sl Journal of the ACM\/ \bf30} (1983), 231--258.]
+@^Vitter, Jeffrey Scott@>
+
+@<Compute the hash code |h|@>=
+h=buffer[j];
+for (k=j+1; k<=j+l-1; k++)
+  {@+h=h+h+buffer[k];
+  while (h >= hash_prime) h=h-hash_prime;
+  }
+
+@ Single-character control sequences do not need to be looked up in a hash
+table, since we can use the character code itself as a direct address.
+The procedure |print_cs| prints the name of a control sequence, given
+a pointer to its address in |eqtb|. A space is printed after the name
+unless it is a single nonletter or an active character. This procedure
+might be invoked with invalid data, so it is ``extra robust.'' The
+individual characters must be printed one at a time using |print|, since
+they may be unprintable.
+
+@<Basic printing...@>=
+static void print_cs(int @!p) /*prints a purported control sequence*/
+{@+if (p < hash_base)  /*single character*/
+  if (p >= single_base)
+    if (p==null_cs)
+      {@+print_esc("csname");print_esc("endcsname");print_char(' ');
+      }
+    else{@+printn_esc(p-single_base);
+      if (cat_code(p-single_base)==letter) print_char(' ');
+      }
+  else if (p < active_base) print_esc("IMPOSSIBLE.");
+ at .IMPOSSIBLE@>
+  else printn(p-active_base);
+else if (p >= undefined_control_sequence) print_esc("IMPOSSIBLE.");
+else if ((text(p) < 0)||(text(p) >= str_ptr)) print_esc("NONEXISTENT.");
+ at .NONEXISTENT@>
+else{@+if (p==frozen_primitive) print_esc("primitive");
+  printn_esc(text(p));print_char(' ');
+  }
+}
+
+@ Here is a similar procedure; it avoids the error checks, and it never
+prints a space after the control sequence.
+
+@<Basic printing procedures@>=
+static void sprint_cs(pointer @!p) /*prints a control sequence*/
+{@+if (p < hash_base)
+  if (p < single_base) printn(p-active_base);
+  else if (p < null_cs) printn_esc(p-single_base);
+    else{@+print_esc("csname");print_esc("endcsname");
+      }
+else printn_esc(text(p));
+}
+
+@ We need to put \TeX's ``primitive'' control sequences into the hash
+table, together with their command code (which will be the |eq_type|)
+and an operand (which will be the |equiv|). The |primitive| procedure
+does this, in a way that no \TeX\ user can. The global value |cur_val|
+contains the new |eqtb| pointer after |primitive| has acted.
+
+ at p
+#ifdef @!INIT
+static void primitive(char *@!str, quarterword @!c, halfword @!o)
+{@+str_number s=s_no(str);
+int k; /*index into |str_pool|*/
+int @!j; /*index into |buffer|*/
+small_number @!l; /*length of the string*/
+pointer @!p; /*pointer in |ROM|*/
+if (s < 256) cur_val=s+single_base;
+else{@+k=str_start[s];l=str_start[s+1]-k;
+     /*we will move |s| into the (possibly non-empty) |buffer|*/
+  if (first+l > buf_size+1)
+      overflow("buffer size", buf_size);
+@:TeX capacity exceeded buffer size}{\quad buffer size@>
+  for (j=0; j<=l-1; j++) buffer[first+j]=so(str_pool[k+j]);
+  cur_val=id_lookup(first, l); /*|no_new_control_sequence| is |false|*/
+  flush_string;text(cur_val)=s; /*we don't want to have the string twice*/
+  }
+eq_level(cur_val)=level_one;eq_type(cur_val)=c;equiv(cur_val)=o;
+@<Add primitive definition to the |ROM| array@>;
+}
+#endif
+
+@ Many of \TeX's primitives need no |equiv|, since they are identifiable
+by their |eq_type| alone. These primitives are loaded into the hash table
+as follows:
+
+@<Put each of \TeX's primitives into the hash table@>=
+primitive(" ", ex_space, 0);@/
+@!@:Single-character primitives /}{\quad\.{\\\ }@>
+primitive("/", ital_corr, 0);@/
+@!@:Single-character primitives /}{\quad\.{\\/}@>
+primitive("accent", accent, 0);@/
+@!@:accent\_}{\.{\\accent} primitive@>
+primitive("advance", advance, 0);@/
+@!@:advance\_}{\.{\\advance} primitive@>
+primitive("afterassignment", after_assignment, 0);@/
+@!@:after\_assignment\_}{\.{\\afterassignment} primitive@>
+primitive("aftergroup", after_group, 0);@/
+@!@:after\_group\_}{\.{\\aftergroup} primitive@>
+primitive("begingroup", begin_group, 0);@/
+@!@:begin\_group\_}{\.{\\begingroup} primitive@>
+primitive("char", char_num, 0);@/
+@!@:char\_}{\.{\\char} primitive@>
+primitive("csname", cs_name, 0);@/
+@!@:cs\_name\_}{\.{\\csname} primitive@>
+primitive("delimiter", delim_num, 0);@/
+@!@:delimiter\_}{\.{\\delimiter} primitive@>
+primitive("divide", divide, 0);@/
+@!@:divide\_}{\.{\\divide} primitive@>
+primitive("endcsname", end_cs_name, 0);@/
+@!@:end\_cs\_name\_}{\.{\\endcsname} primitive@>
+primitive("endgroup", end_group, 0);
+@!@:end\_group\_}{\.{\\endgroup} primitive@>
+text(frozen_end_group)=text(cur_val);eqtb[frozen_end_group]=eqtb[cur_val];@/
+primitive("expandafter", expand_after, 0);@/
+@!@:expand\_after\_}{\.{\\expandafter} primitive@>
+primitive("font", def_font, 0);@/
+@!@:font\_}{\.{\\font} primitive@>
+primitive("fontdimen", assign_font_dimen, 0);@/
+@!@:font\_dimen\_}{\.{\\fontdimen} primitive@>
+primitive("halign", halign, 0);@/
+@!@:halign\_}{\.{\\halign} primitive@>
+primitive("hrule", hrule, 0);@/
+@!@:hrule\_}{\.{\\hrule} primitive@>
+primitive("ignorespaces", ignore_spaces, 0);@/
+@!@:ignore\_spaces\_}{\.{\\ignorespaces} primitive@>
+primitive("insert", insert, 0);@/
+@!@:insert\_}{\.{\\insert} primitive@>
+primitive("mark", mark, 0);@/
+@!@:mark\_}{\.{\\mark} primitive@>
+primitive("mathaccent", math_accent, 0);@/
+@!@:math\_accent\_}{\.{\\mathaccent} primitive@>
+primitive("mathchar", math_char_num, 0);@/
+@!@:math\_char\_}{\.{\\mathchar} primitive@>
+primitive("mathchoice", math_choice, 0);@/
+@!@:math\_choice\_}{\.{\\mathchoice} primitive@>
+primitive("multiply", multiply, 0);@/
+@!@:multiply\_}{\.{\\multiply} primitive@>
+primitive("noalign", no_align, 0);@/
+@!@:no\_align\_}{\.{\\noalign} primitive@>
+primitive("noboundary", no_boundary, 0);@/
+@!@:no\_boundary\_}{\.{\\noboundary} primitive@>
+primitive("noexpand", no_expand, 0);@/
+@!@:no\_expand\_}{\.{\\noexpand} primitive@>
+primitive("nonscript", non_script, 0);@/
+@!@:non\_script\_}{\.{\\nonscript} primitive@>
+primitive("omit", omit, 0);@/
+@!@:omit\_}{\.{\\omit} primitive@>
+primitive("parshape", set_shape, par_shape_loc);@/
+@!@:par\_shape\_}{\.{\\parshape} primitive@>
+primitive("penalty", break_penalty, 0);@/
+@!@:penalty\_}{\.{\\penalty} primitive@>
+primitive("prevgraf", set_prev_graf, 0);@/
+@!@:prev\_graf\_}{\.{\\prevgraf} primitive@>
+primitive("radical", radical, 0);@/
+@!@:radical\_}{\.{\\radical} primitive@>
+primitive("read", read_to_cs, 0);@/
+@!@:read\_}{\.{\\read} primitive@>
+primitive("relax", relax, 256); /*cf.\ |scan_file_name|*/
+@!@:relax\_}{\.{\\relax} primitive@>
+text(frozen_relax)=text(cur_val);eqtb[frozen_relax]=eqtb[cur_val];@/
+primitive("setbox", set_box, 0);@/
+@!@:set\_box\_}{\.{\\setbox} primitive@>
+primitive("the", the, 0);@/
+@!@:the\_}{\.{\\the} primitive@>
+primitive("toks", toks_register, mem_bot);@/
+@!@:toks\_}{\.{\\toks} primitive@>
+primitive("vadjust", vadjust, 0);@/
+@!@:vadjust\_}{\.{\\vadjust} primitive@>
+primitive("valign", valign, 0);@/
+@!@:valign\_}{\.{\\valign} primitive@>
+primitive("vcenter", vcenter, 0);@/
+@!@:vcenter\_}{\.{\\vcenter} primitive@>
+primitive("vrule", vrule, 0);@/
+@!@:vrule\_}{\.{\\vrule} primitive@>
+
+@ Each primitive has a corresponding inverse, so that it is possible to
+display the cryptic numeric contents of |eqtb| in symbolic form.
+Every call of |primitive| in this program is therefore accompanied by some
+straightforward code that forms part of the |print_cmd_chr| routine
+below.
+
+@<Cases of |print_cmd_chr|...@>=
+case accent: print_esc("accent");@+break;
+case advance: print_esc("advance");@+break;
+case after_assignment: print_esc("afterassignment");@+break;
+case after_group: print_esc("aftergroup");@+break;
+case assign_font_dimen: print_esc("fontdimen");@+break;
+case begin_group: print_esc("begingroup");@+break;
+case break_penalty: print_esc("penalty");@+break;
+case char_num: print_esc("char");@+break;
+case cs_name: print_esc("csname");@+break;
+case def_font: print_esc("font");@+break;
+case delim_num: print_esc("delimiter");@+break;
+case divide: print_esc("divide");@+break;
+case end_cs_name: print_esc("endcsname");@+break;
+case end_group: print_esc("endgroup");@+break;
+case ex_space: print_esc(" ");@+break;
+case expand_after: switch (chr_code) {
+case 0: print_esc("expandafter");@+break;
+@/@<Cases of |expandafter| for |print_cmd_chr|@>@/
+} @+break; /*there are no other cases*/
+case halign: print_esc("halign");@+break;
+case hrule: print_esc("hrule");@+break;
+case ignore_spaces: print_esc("ignorespaces");@+break;
+case insert: print_esc("insert");@+break;
+case ital_corr: print_esc("/");@+break;
+case mark: print_esc("mark");@+break;
+case math_accent: print_esc("mathaccent");@+break;
+case math_char_num: print_esc("mathchar");@+break;
+case math_choice: print_esc("mathchoice");@+break;
+case multiply: print_esc("multiply");@+break;
+case no_align: print_esc("noalign");@+break;
+case no_boundary: print_esc("noboundary");@+break;
+case no_expand: print_esc("noexpand");@+break;
+case non_script: print_esc("nonscript");@+break;
+case omit: print_esc("omit");@+break;
+case radical: print_esc("radical");@+break;
+case read_to_cs: if (chr_code==0) print_esc("read")
+  @<Cases of |read| for |print_cmd_chr|@>;@+break;
+case relax: print_esc("relax");@+break;
+case set_box: print_esc("setbox");@+break;
+case set_prev_graf: print_esc("prevgraf");@+break;
+case set_shape: switch (chr_code) {
+  case par_shape_loc: print_esc("parshape");@+break;
+  @<Cases of |set_shape| for |print_cmd_chr|@>@;@/
+  } @+break; /*there are no other cases*/
+case the: if (chr_code==0) print_esc("the")
+  @<Cases of |the| for |print_cmd_chr|@>;@+break;
+case toks_register: @<Cases of |toks_register| for |print_cmd_chr|@>@;@+break;
+case vadjust: print_esc("vadjust");@+break;
+case valign: print_esc("valign");@+break;
+case vcenter: print_esc("vcenter");@+break;
+case vrule: print_esc("vrule");@+break;
+
+@ We will deal with the other primitives later, at some point in the program
+where their |eq_type| and |equiv| values are more meaningful.  For example,
+the primitives for math mode will be loaded when we consider the routines
+that deal with formulas. It is easy to find where each particular
+primitive was treated by looking in the index at the end; for example, the
+section where |"radical"| entered |eqtb| is listed under `\.{\\radical}
+primitive'. (Primitives consisting of a single nonalphabetic character,
+@!like `\.{\\/}', are listed under `Single-character primitives'.)
+@!@^Single-character primitives@>
+
+Meanwhile, this is a convenient place to catch up on something we were unable
+to do before the hash table was defined:
+
+@<Print the font identifier for |font(p)|@>=
+printn_esc(font_id_text(font(p)))
+
+@* Saving and restoring equivalents.
+The nested structure provided by `$\.{\char'173}\ldots\.{\char'175}$' groups
+in \TeX\ means that |eqtb| entries valid in outer groups should be saved
+and restored later if they are overridden inside the braces. When a new |eqtb|
+value is being assigned, the program therefore checks to see if the previous
+entry belongs to an outer level. In such a case, the old value is placed
+on the |save_stack| just before the new value enters |eqtb|. At the
+end of a grouping level, i.e., when the right brace is sensed, the
+|save_stack| is used to restore the outer values, and the inner ones are
+destroyed.
+
+Entries on the |save_stack| are of type |memory_word|. The top item on
+this stack is |save_stack[p]|, where |p==save_ptr-1|; it contains three
+fields called |save_type|, |save_level|, and |save_index|, and it is
+interpreted in one of five ways:
+
+\yskip\hangg 1) If |save_type(p)==restore_old_value|, then
+|save_index(p)| is a location in |eqtb| whose current value should
+be destroyed at the end of the current group and replaced by |save_stack[p-1]|.
+Furthermore if |save_index(p) >= int_base|, then |save_level(p)|
+should replace the corresponding entry in |xeq_level|.
+
+\yskip\hangg 2) If |save_type(p)==restore_zero|, then |save_index(p)|
+is a location in |eqtb| whose current value should be destroyed at the end
+of the current group, when it should be
+replaced by the value of |eqtb[undefined_control_sequence]|.
+
+\yskip\hangg 3) If |save_type(p)==insert_token|, then |save_index(p)|
+is a token that should be inserted into \TeX's input when the current
+group ends.
+
+\yskip\hangg 4) If |save_type(p)==level_boundary|, then |save_level(p)|
+is a code explaining what kind of group we were previously in, and
+|save_index(p)| points to the level boundary word at the bottom of
+the entries for that group.
+Furthermore, in extended \eTeX\ mode, |save_stack[p-1]| contains the
+source line number at which the current level of grouping was entered.
+
+\yskip\hang 5) If |save_type(p)==restore_sa|, then |sa_chain| points to a
+chain of sparse array entries to be restored at the end of the current
+group. Furthermore |save_index(p)| and |save_level(p)| should replace
+the values of |sa_chain| and |sa_level| respectively.
+
+ at d save_type(A) save_stack[A].hh.b0 /*classifies a |save_stack| entry*/
+ at d save_level(A) save_stack[A].hh.b1
+   /*saved level for regions 5 and 6, or group code*/
+ at d save_index(A) save_stack[A].hh.rh
+   /*|eqtb| location or token or |save_stack| location*/
+ at d restore_old_value 0 /*|save_type| when a value should be restored later*/
+ at d restore_zero 1 /*|save_type| when an undefined entry should be restored*/
+ at d insert_token 2 /*|save_type| when a token is being saved for later use*/
+ at d level_boundary 3 /*|save_type| corresponding to beginning of group*/
+ at d restore_sa 4 /*|save_type| when sparse array entries should be restored*/
+
+ at p @t\4@>@<Declare \eTeX\ procedures for tracing and input@>@;
+
+@ Here are the group codes that are used to discriminate between different
+kinds of groups. They allow \TeX\ to decide what special actions, if any,
+should be performed when a group ends.
+\def\grp{\.{\char'173...\char'175}}
+
+Some groups are not supposed to be ended by right braces. For example,
+the `\.\$' that begins a math formula causes a |math_shift_group| to
+be started, and this should be terminated by a matching `\.\$'. Similarly,
+a group that starts with \.{\\left} should end with \.{\\right}, and
+one that starts with \.{\\begingroup} should end with \.{\\endgroup}.
+
+ at d bottom_level 0 /*group code for the outside world*/
+ at d simple_group 1 /*group code for local structure only*/
+ at d hbox_group 2 /*code for `\.{\\hbox}\grp'*/
+ at d adjusted_hbox_group 3 /*code for `\.{\\hbox}\grp' in vertical mode*/
+ at d vbox_group 4 /*code for `\.{\\vbox}\grp'*/
+ at d vtop_group 5 /*code for `\.{\\vtop}\grp'*/
+ at d align_group 6 /*code for `\.{\\halign}\grp', `\.{\\valign}\grp'*/
+ at d no_align_group 7 /*code for `\.{\\noalign}\grp'*/
+ at d output_group 8 /*code for output routine*/
+ at d math_group 9 /*code for, e.g., `\.{\char'136}\grp'*/
+ at d disc_group 10 /*code for `\.{\\discretionary}\grp\grp\grp'*/
+ at d insert_group 11 /*code for `\.{\\insert}\grp', `\.{\\vadjust}\grp'*/
+ at d vcenter_group 12 /*code for `\.{\\vcenter}\grp'*/
+ at d math_choice_group 13 /*code for `\.{\\mathchoice}\grp\grp\grp\grp'*/
+ at d semi_simple_group 14 /*code for `\.{\\begingroup...\\endgroup}'*/
+ at d math_shift_group 15 /*code for `\.{\$...\$}'*/
+ at d math_left_group 16 /*code for `\.{\\left...\\right}'*/
+ at d page_group           17
+ at d stream_group  18
+ at d stream_before_group  19
+ at d stream_after_group   20
+ at d outline_group        21
+ at d max_group_code 21
+
+@<Types...@>=
+typedef int8_t group_code; /*|save_level| for a level boundary*/
+
+@ The global variable |cur_group| keeps track of what sort of group we are
+currently in. Another global variable, |cur_boundary|, points to the
+topmost |level_boundary| word.  And |cur_level| is the current depth of
+nesting. The routines are designed to preserve the condition that no entry
+in the |save_stack| or in |eqtb| ever has a level greater than |cur_level|.
+
+@ @<Glob...@>=
+static memory_word @!save_stack[save_size+1];
+static memory_word @!save_hfactor[save_size+1];
+static memory_word @!save_vfactor[save_size+1];
+static int @!save_ptr; /*first unused entry on |save_stack|*/
+static int @!max_save_stack; /*maximum usage of save stack*/
+static quarterword @!cur_level; /*current nesting level for groups*/
+static group_code @!cur_group; /*current group type*/
+static int @!cur_boundary; /*where the current level begins*/
+
+@ At this time it might be a good idea for the reader to review the introduction
+to |eqtb| that was given above just before the long lists of parameter names.
+Recall that the ``outer level'' of the program is |level_one|, since
+undefined control sequences are assumed to be ``defined'' at |level_zero|.
+
+@<Set init...@>=
+save_ptr=0;cur_level=level_one;cur_group=bottom_level;cur_boundary=0;
+max_save_stack=0;
+
+@ The following macro is used to test if there is room for up to seven more
+entries on |save_stack|. By making a conservative test like this, we can
+get by with testing for overflow in only a few places.
+
+ at d check_full_save_stack if (save_ptr > max_save_stack)
+  {@+max_save_stack=save_ptr;
+  if (max_save_stack > save_size-7) overflow("save size", save_size);
+@:TeX capacity exceeded save size}{\quad save size@>
+  }
+
+@ Procedure |new_save_level| is called when a group begins. The
+argument is a group identification code like `|hbox_group|'. After
+calling this routine, it is safe to put five more entries on |save_stack|.
+
+In some cases integer-valued items are placed onto the
+|save_stack| just below a |level_boundary| word, because this is a
+convenient place to keep information that is supposed to ``pop up'' just
+when the group has finished.
+For example, when `\.{\\hbox to 100pt}\grp' is being treated, the 100pt
+dimension is stored on |save_stack| just before |new_save_level| is
+called.
+
+We use the notation |saved(k)| to stand for an integer item that
+appears in location |save_ptr+k| of the save stack.
+
+ at d saved(A) save_stack[save_ptr+A].i
+ at d saved_hfactor(A) save_hfactor[save_ptr+A].i
+ at d saved_vfactor(A) save_vfactor[save_ptr+A].i
+
+ at p static void new_save_level(group_code @!c) /*begin a new level of grouping*/
+{@+check_full_save_stack;
+if (eTeX_ex)
+  {@+saved(0)=line;incr(save_ptr);
+  }
+save_type(save_ptr)=level_boundary;save_level(save_ptr)=cur_group;
+save_index(save_ptr)=cur_boundary;
+if (cur_level==max_quarterword) overflow("grouping levels",
+@:TeX capacity exceeded grouping levels}{\quad grouping levels@>
+  max_quarterword-min_quarterword);
+   /*quit if |(cur_level+1)| is too big to be stored in |eqtb|*/
+cur_boundary=save_ptr;cur_group=c;
+#ifdef @!STAT
+if (tracing_groups > 0) group_trace(false);
+#endif
+@;@/
+incr(cur_level);incr(save_ptr);
+}
+
+@ Just before an entry of |eqtb| is changed, the following procedure should
+be called to update the other data structures properly. It is important
+to keep in mind that reference counts in |mem| include references from
+within |save_stack|, so these counts must be handled carefully.
+@^reference counts@>
+
+ at p static void eq_destroy(memory_word @!w) /*gets ready to forget |w|*/
+{@+pointer q; /*|equiv| field of |w|*/
+switch (eq_type_field(w)) {
+case call: case long_call: case outer_call: case long_outer_call: delete_token_ref(equiv_field(w));@+break;
+case glue_ref: delete_glue_ref(equiv_field(w));@+break;
+case shape_ref: {@+q=equiv_field(w); /*we need to free a \.{\\parshape} block*/
+  if (q!=null) free_node(q, info(q)+info(q)+1);
+  } @+break; /*such a block is |2 n+1| words long, where |n==info(q)|*/
+case box_ref: flush_node_list(equiv_field(w));@+break;
+@/@<Cases for |eq_destroy|@>@/
+default:do_nothing;
+}
+}
+
+@ To save a value of |eqtb[p]| that was established at level |l|, we
+can use the following subroutine.
+
+ at p static void eq_save(pointer @!p, quarterword @!l) /*saves |eqtb[p]|*/
+{@+check_full_save_stack;
+if (l==level_zero) save_type(save_ptr)=restore_zero;
+else{@+save_stack[save_ptr]=eqtb[p];
+  if (p>=dimen_base)
+  { save_hfactor[save_ptr]=hfactor_eqtb[p];
+    save_vfactor[save_ptr]=vfactor_eqtb[p];
+  }
+  else if (p==par_shape_loc)
+  { save_hfactor[save_ptr].i=par_shape_hfactor;
+    save_vfactor[save_ptr].i=par_shape_vfactor;
+  }
+  incr(save_ptr);
+  save_type(save_ptr)=restore_old_value;
+  }
+save_level(save_ptr)=l;save_index(save_ptr)=p;incr(save_ptr);
+}
+
+@ The procedure |eq_define| defines an |eqtb| entry having specified
+|eq_type| and |equiv| fields, and saves the former value if appropriate.
+This procedure is used only for entries in the first four regions of |eqtb|,
+i.e., only for entries that have |eq_type| and |equiv| fields.
+After calling this routine, it is safe to put four more entries on
+|save_stack|, provided that there was room for four more entries before
+the call, since |eq_save| makes the necessary test.
+
+ at p
+#ifdef @!STAT
+#define  assign_trace(A, B) if (tracing_assigns > 0) restore_trace(A, B);
+#else
+#define  assign_trace(A, B)
+#endif
+
+static void eq_define(pointer @!p, quarterword @!t, halfword @!e)
+   /*new data for |eqtb|*/
+{@+
+if (eTeX_ex&&(eq_type(p)==t)&&(equiv(p)==e))
+  {@+assign_trace(p,"reassigning")@;@/
+  eq_destroy(eqtb[p]);return;
+  }
+assign_trace(p,"changing")@;@/
+if (eq_level(p)==cur_level) eq_destroy(eqtb[p]);
+else if (cur_level > level_one) eq_save(p, eq_level(p));
+eq_level(p)=cur_level;eq_type(p)=t;equiv(p)=e;
+if (p==par_shape_loc)
+{ par_shape_hfactor=cur_hfactor;
+  par_shape_vfactor=cur_vfactor;
+}
+assign_trace(p,"into")@;@/
+}
+
+@ The counterpart of |eq_define| for the remaining (fullword) positions in
+|eqtb| is called |eq_word_define|. Since |xeq_level[p] >= level_one| for all
+|p|, a `|restore_zero|' will never be used in this case.
+
+ at p static void eq_word_define(pointer @!p, int @!w)
+{@+
+if (eTeX_ex&&(eqtb[p].i==w))
+  {@+assign_trace(p,"reassigning")@;@/
+  return;
+  }
+assign_trace(p,"changing")@;@/
+if (cur_level==level_one)@t\1@>
+   { if (p==dimen_base+hsize_code)
+     { hhsize=w+round(((double)cur_hfactor*hhsize +(double)cur_vfactor*hvsize)/unity); return; @+}
+     if (p==dimen_base+vsize_code)
+     { hvsize=w+round(((double)cur_hfactor*hhsize +(double)cur_vfactor*hvsize)/unity); return; @+}
+   }
+if (xeq_level[p]!=cur_level)
+  {@+eq_save(p, xeq_level[p]);xeq_level[p]=cur_level;
+  }
+eqtb[p].i=w;
+if (p>=dimen_base)
+{ hfactor_eqtb[p].i=cur_hfactor;
+  vfactor_eqtb[p].i=cur_vfactor;
+}
+assign_trace(p,"into")@;@/
+}
+
+@ The |eq_define| and |eq_word_define| routines take care of local definitions.
+@^global definitions@>
+Global definitions are done in almost the same way, but there is no need
+to save old values, and the new value is associated with |level_one|.
+
+ at p static void geq_define(pointer @!p, quarterword @!t, halfword @!e)
+   /*global |eq_define|*/
+{@+assign_trace(p,"globally changing")@;@/
+{@+eq_destroy(eqtb[p]);
+eq_level(p)=level_one;eq_type(p)=t;equiv(p)=e;
+}
+assign_trace(p,"into");@/
+}
+@#
+static void geq_word_define(pointer @!p, int @!w) /*global |eq_word_define|*/
+{@+assign_trace(p,"globally changing")@;@/
+{@t\1@>xeq_level[p]=level_one;
+  if (p==dimen_base+hsize_code)
+    hhsize=w+round(((double)cur_hfactor*hhsize +(double)cur_vfactor*hvsize)/unity);
+  else if (p==dimen_base+vsize_code)
+    hvsize=w+round(((double)cur_hfactor*hhsize +(double)cur_vfactor*hvsize)/unity);
+  else
+ { eqtb[p].i=w;
+  if (p>=dimen_base)
+  { hfactor_eqtb[p].i=cur_hfactor;
+    vfactor_eqtb[p].i=cur_vfactor;
+  }
+}
+}
+assign_trace(p,"into");@/
+}
+
+@ Subroutine |save_for_after| puts a token on the stack for save-keeping.
+
+ at p static void save_for_after(halfword @!t)
+{@+if (cur_level > level_one)
+  {@+check_full_save_stack;
+  save_type(save_ptr)=insert_token;save_level(save_ptr)=level_zero;
+  save_index(save_ptr)=t;incr(save_ptr);
+  }
+}
+
+@ The |unsave| routine goes the other way, taking items off of |save_stack|.
+This routine takes care of restoration when a level ends; everything
+belonging to the topmost group is cleared off of the save stack.
+
+ at p
+static void back_input(void);
+static void unsave(void) /*pops the top level off the save stack*/
+{@+
+pointer p; /*position to be restored*/
+quarterword @!l; /*saved level, if in fullword regions of |eqtb|*/
+halfword @!t; /*saved value of |cur_tok|*/
+bool @!a; /*have we already processed an \.{\\aftergroup} ?*/
+a=false;
+if (cur_level > level_one)
+  {@+decr(cur_level);
+  @<Clear off top level from |save_stack|@>;
+  }
+else confusion("curlevel"); /*|unsave| is not used when |cur_group==bottom_level|*/
+@:this can't happen curlevel}{\quad curlevel@>
+}
+
+@ @<Clear off...@>=
+loop at +{@+decr(save_ptr);
+  if (save_type(save_ptr)==level_boundary) goto done;
+  p=save_index(save_ptr);
+  if (save_type(save_ptr)==insert_token)
+    @<Insert token |p| into \TeX's input@>@;
+  else if (save_type(save_ptr)==restore_sa)
+    {@+sa_restore();sa_chain=p;sa_level=save_level(save_ptr);
+    }
+  else{@+if (save_type(save_ptr)==restore_old_value)
+      {@+l=save_level(save_ptr);decr(save_ptr);
+      }
+    else save_stack[save_ptr]=eqtb[undefined_control_sequence];
+    @<Store \(s)|save_stack[save_ptr]| in |eqtb[p]|, unless |eqtb[p]| holds a global
+value@>;
+    }
+  }
+done:
+#ifdef @!STAT
+if (tracing_groups > 0) group_trace(true);
+#endif
+@;@/
+if (grp_stack[in_open]==cur_boundary) group_warning();
+   /*groups possibly not properly nested with files*/
+cur_group=save_level(save_ptr);cur_boundary=save_index(save_ptr);
+if (eTeX_ex) decr(save_ptr)
+
+@ A global definition, which sets the level to |level_one|,
+@^global definitions@>
+will not be undone by |unsave|. If at least one global definition of
+|eqtb[p]| has been carried out within the group that just ended, the
+last such definition will therefore survive.
+
+@<Store \(s)|save...@>=
+if (p < int_base)
+  if (eq_level(p)==level_one)
+    {@+eq_destroy(save_stack[save_ptr]); /*destroy the saved value*/
+#ifdef @!STAT
+    if (tracing_restores > 0) restore_trace(p,"retaining");
+#endif
+@;@/
+    }
+  else{@+eq_destroy(eqtb[p]); /*destroy the current value*/
+    eqtb[p]=save_stack[save_ptr]; /*restore the saved value*/
+    if (p==par_shape_loc)
+    { par_shape_hfactor=save_hfactor[save_ptr].i;
+      par_shape_vfactor=save_vfactor[save_ptr].i;
+    }
+#ifdef @!STAT
+    if (tracing_restores > 0) restore_trace(p,"restoring");
+#endif
+@;@/
+    }
+else if (xeq_level[p]!=level_one)
+  {@t\1@>@+eqtb[p]=save_stack[save_ptr];
+    if (p>=dimen_base)
+    { hfactor_eqtb[p]=save_hfactor[save_ptr];
+      vfactor_eqtb[p]=save_vfactor[save_ptr];
+    }
+    xeq_level[p]=l;
+#ifdef @!STAT
+  if (tracing_restores > 0) restore_trace(p,"restoring");
+#endif
+@;@/
+  }
+else{
+#ifdef @!STAT
+  if (tracing_restores > 0) restore_trace(p,"retaining");
+#endif
+@;@/
+  }
+
+@ @<Declare \eTeX\ procedures for tr...@>=
+#ifdef @!STAT
+static void restore_trace(pointer @!p, char *@!s)
+   /*|eqtb[p]| has just been restored or retained*/
+{@+begin_diagnostic();print_char('{');print(s);print_char(' ');
+show_eqtb(p);print_char('}');
+end_diagnostic(false);
+}
+#endif
+
+@ When looking for possible pointers to a memory location, it is helpful
+to look for references from |eqtb| that might be waiting on the
+save stack. Of course, we might find spurious pointers too; but this
+routine is merely an aid when debugging, and at such times we are
+grateful for any scraps of information, even if they prove to be irrelevant.
+@^dirty \PASCAL@>
+
+@<Search |save_stack| for equivalents that point to |p|@>=
+if (save_ptr > 0) for (q=0; q<=save_ptr-1; q++)
+  {@+if (equiv_field(save_stack[q])==p)
+    {@+print_nl("SAVE(");print_int(q);print_char(')');
+    }
+  }
+
+@ Most of the parameters kept in |eqtb| can be changed freely, but there's
+an exception:  The magnification should not be used with two different
+values during any \TeX\ job, since a single magnification is applied to an
+entire run. The global variable |mag_set| is set to the current magnification
+whenever it becomes necessary to ``freeze'' it at a particular value.
+
+@<Glob...@>=
+static int @!mag_set; /*if nonzero, this magnification should be used henceforth*/
+
+@ @<Set init...@>=
+mag_set=0;
+
+@ The |prepare_mag| subroutine is called whenever \TeX\ wants to use |mag|
+for magnification.
+
+ at p static void prepare_mag(void)
+{@+if ((mag_set > 0)&&(mag!=mag_set))
+  {@+print_err("Incompatible magnification (");print_int(mag);
+ at .Incompatible magnification@>
+  print(");");print_nl(" the previous value will be retained");
+  help2("I can handle only one magnification ratio per job. So I've",@/
+  "reverted to the magnification you used earlier on this run.");@/
+  int_error(mag_set);
+  geq_word_define(int_base+mag_code, mag_set); /*|mag=mag_set|*/
+  }
+if ((mag <= 0)||(mag > 32768))
+  {@+print_err("Illegal magnification has been changed to 1000");@/
+ at .Illegal magnification...@>
+  help1("The magnification ratio must be between 1 and 32768.");
+  int_error(mag);geq_word_define(int_base+mag_code, 1000);
+  }
+mag_set=mag;
+}
+
+@* Token lists.
+A \TeX\ token is either a character or a control sequence, and it is
+@^token@>
+represented internally in one of two ways: (1)~A character whose ASCII
+code number is |c| and whose command code is |m| is represented as the
+number $2^8m+c$; the command code is in the range |1 <= m <= 14|. (2)~A control
+sequence whose |eqtb| address is |p| is represented as the number
+|cs_token_flag+p|. Here |cs_token_flag==@t$2^{12}-1$@>| is larger than
+$2^8m+c$, yet it is small enough that |cs_token_flag+p < max_halfword|;
+thus, a token fits comfortably in a halfword.
+
+A token |t| represents a |left_brace| command if and only if
+|t < left_brace_limit|; it represents a |right_brace| command if and only if
+we have |left_brace_limit <= t < right_brace_limit|; and it represents a |match| or
+|end_match| command if and only if |match_token <= t <= end_match_token|.
+The following definitions take care of these token-oriented constants
+and a few others.
+
+ at d cs_token_flag 07777 /*amount added to the |eqtb| location in a
+  token that stands for a control sequence; is a multiple of~256, less~1*/
+ at d left_brace_token 00400 /*$2^8\cdot|left_brace|$*/
+ at d left_brace_limit 01000 /*$2^8\cdot(|left_brace|+1)$*/
+ at d right_brace_token 01000 /*$2^8\cdot|right_brace|$*/
+ at d right_brace_limit 01400 /*$2^8\cdot(|right_brace|+1)$*/
+ at d math_shift_token 01400 /*$2^8\cdot|math_shift|$*/
+ at d tab_token 02000 /*$2^8\cdot|tab_mark|$*/
+ at d out_param_token 02400 /*$2^8\cdot|out_param|$*/
+ at d space_token 05040 /*$2^8\cdot|spacer|+|' '|$*/
+ at d letter_token 05400 /*$2^8\cdot|letter|$*/
+ at d other_token 06000 /*$2^8\cdot|other_char|$*/
+ at d match_token 06400 /*$2^8\cdot|match|$*/
+ at d end_match_token 07000 /*$2^8\cdot|end_match|$*/
+ at d protected_token 07001 /*$2^8\cdot|end_match|+1$*/
+
+@ @<Check the ``constant''...@>=
+if (cs_token_flag+undefined_control_sequence > max_halfword) bad=21;
+
+@ A token list is a singly linked list of one-word nodes in |mem|, where
+each word contains a token and a link. Macro definitions, output-routine
+definitions, marks, \.{\\write} texts, and a few other things
+are remembered by \TeX\ in the form
+of token lists, usually preceded by a node with a reference count in its
+|token_ref_count| field. The token stored in location |p| is called
+|info(p)|.
+
+Three special commands appear in the token lists of macro definitions.
+When |m==match|, it means that \TeX\ should scan a parameter
+for the current macro; when |m==end_match|, it means that parameter
+matching should end and \TeX\ should start reading the macro text; and
+when |m==out_param|, it means that \TeX\ should insert parameter
+number |c| into the text at this point.
+
+The enclosing \.{\char'173} and \.{\char'175} characters of a macro
+definition are omitted, but an output routine
+will be enclosed in braces.
+
+Here is an example macro definition that illustrates these conventions.
+After \TeX\ processes the text
+$$\.{\\def\\mac a\#1\#2 \\b \{\#1\\-a \#\#1\#2 \#2\}}$$
+the definition of \.{\\mac} is represented as a token list containing
+$$\def\,{\hskip2pt}
+\vbox{\halign{\hfil#\hfil\cr
+(reference count), |letter|\,\.a, |match|\,\#, |match|\,\#, |spacer|\,\.\ ,
+\.{\\b}, |end_match|,\cr
+|out_param|\,1, \.{\\-}, |letter|\,\.a, |spacer|\,\.\ , |mac_param|\,\#,
+|other_char|\,\.1,\cr
+|out_param|\,2, |spacer|\,\.\ , |out_param|\,2.\cr}}$$
+The procedure |scan_toks| builds such token lists, and |macro_call|
+does the parameter matching.
+@^reference counts@>
+
+Examples such as
+$$\.{\\def\\m\{\\def\\m\{a\}\ b\}}$$
+explain why reference counts would be needed even if \TeX\ had no \.{\\let}
+operation: When the token list for \.{\\m} is being read, the redefinition of
+\.{\\m} changes the |eqtb| entry before the token list has been fully
+consumed, so we dare not simply destroy a token list when its
+control sequence is being redefined.
+
+If the parameter-matching part of a definition ends with `\.{\#\{}',
+the corresponding token list will have `\.\{' just before the `|end_match|'
+and also at the very end. The first `\.\{' is used to delimit the parameter; the
+second one keeps the first from disappearing.
+
+@ The procedure |show_token_list|, which prints a symbolic form of
+the token list that starts at a given node |p|, illustrates these
+conventions. The token list being displayed should not begin with a reference
+count. However, the procedure is intended to be robust, so that if the
+memory links are awry or if |p| is not really a pointer to a token list,
+nothing catastrophic will happen.
+
+An additional parameter |q| is also given; this parameter is either null
+or it points to a node in the token list where a certain magic computation
+takes place that will be explained later. (Basically, |q| is non-null when
+we are printing the two-line context information at the time of an error
+message; |q| marks the place corresponding to where the second line
+should begin.)
+
+For example, if |p| points to the node containing the first \.a in the
+token list above, then |show_token_list| will print the string
+$$\hbox{`\.{a\#1\#2\ \\b\ ->\#1\\-a\ \#\#1\#2\ \#2}';}$$
+and if |q| points to the node containing the second \.a,
+the magic computation will be performed just before the second \.a is printed.
+
+The generation will stop, and `\.{\\ETC.}' will be printed, if the length
+of printing exceeds a given limit~|l|. Anomalous entries are printed in the
+form of control sequences that are not followed by a blank space, e.g.,
+`\.{\\BAD.}'; this cannot be confused with actual control sequences because
+a real control sequence named \.{BAD} would come out `\.{\\BAD\ }'.
+
+@<Declare the procedure called |show_token_list|@>=
+static void show_token_list(int @!p, int @!q, int @!l)
+{@+
+int m, @!c; /*pieces of a token*/
+ASCII_code @!match_chr; /*character used in a `|match|'*/
+ASCII_code @!n; /*the highest parameter number, as an ASCII digit*/
+match_chr='#';n='0';tally=0;
+while ((p!=null)&&(tally < l))
+  {@+if (p==q) @<Do magic computation@>;
+  @<Display token |p|, and |return| if there are problems@>;
+  p=link(p);
+  }
+if (p!=null) print_esc("ETC.");
+ at .ETC@>
+
+}
+
+@ @<Display token |p|...@>=
+if ((p < hi_mem_min)||(p > mem_end))
+  {@+print_esc("CLOBBERED.");return;
+ at .CLOBBERED@>
+  }
+if (info(p) >= cs_token_flag) print_cs(info(p)-cs_token_flag);
+else{@+m=info(p)/0400;c=info(p)%0400;
+  if (info(p) < 0) print_esc("BAD.");
+ at .BAD@>
+  else@<Display the token $(|m|,|c|)$@>;
+  }
+
+@ The procedure usually ``learns'' the character code used for macro
+parameters by seeing one in a |match| command before it runs into any
+|out_param| commands.
+
+@<Display the token...@>=
+switch (m) {
+case left_brace: case right_brace: case math_shift: case tab_mark: case sup_mark: case sub_mark: case spacer:
+  case letter: case other_char: printn(c);@+break;
+case mac_param: {@+printn(c);printn(c);
+  } @+break;
+case out_param: {@+printn(match_chr);
+  if (c <= 9) print_char(c+'0');
+  else{@+print_char('!');return;
+    }
+  } @+break;
+case match: {@+match_chr=c;printn(c);incr(n);print_char(n);
+  if (n > '9') return;
+  } @+break;
+case end_match: if (c==0) print("->");@+break;
+ at .->@>
+default:print_esc("BAD.");
+ at .BAD@>
+}
+
+@ Here's the way we sometimes want to display a token list, given a pointer
+to its reference count; the pointer may be null.
+
+ at p static void token_show(pointer @!p)
+{@+if (p!=null) show_token_list(link(p), null, 10000000);
+}
+
+@ The |print_meaning| subroutine displays |cur_cmd| and |cur_chr| in
+symbolic form, including the expansion of a macro or mark.
+
+ at p static void print_meaning(void)
+{@+print_cmd_chr(cur_cmd, cur_chr);
+if (cur_cmd >= call)
+  {@+print_char(':');print_ln();token_show(cur_chr);
+  }
+else if (cur_cmd==top_bot_mark)
+  {@+print_char(':');print_ln();
+  token_show(cur_mark[cur_chr]);
+  }
+}
+
+@* Introduction to the syntactic routines.
+Let's pause a moment now and try to look at the Big Picture.
+The \TeX\ program consists of three main parts: syntactic routines,
+semantic routines, and output routines. The chief purpose of the
+syntactic routines is to deliver the user's input to the semantic routines,
+one token at a time. The semantic routines act as an interpreter
+responding to these tokens, which may be regarded as commands. And the
+output routines are periodically called on to convert box-and-glue
+lists into a compact set of instructions that will be sent
+to a typesetter. We have discussed the basic data structures and utility
+routines of \TeX, so we are good and ready to plunge into the real activity by
+considering the syntactic routines.
+
+Our current goal is to come to grips with the |get_next| procedure,
+which is the keystone of \TeX's input mechanism. Each call of |get_next|
+sets the value of three variables |cur_cmd|, |cur_chr|, and |cur_cs|,
+representing the next input token.
+$$\vbox{\halign{#\hfil\cr
+  \hbox{|cur_cmd| denotes a command code from the long list of codes
+   given above;}\cr
+  \hbox{|cur_chr| denotes a character code or other modifier of the command
+   code;}\cr
+  \hbox{|cur_cs| is the |eqtb| location of the current control sequence,}\cr
+  \hbox{\qquad if the current token was a control sequence,
+   otherwise it's zero.}\cr}}$$
+Underlying this external behavior of |get_next| is all the machinery
+necessary to convert from character files to tokens. At a given time we
+may be only partially finished with the reading of several files (for
+which \.{\\input} was specified), and partially finished with the expansion
+of some user-defined macros and/or some macro parameters, and partially
+finished with the generation of some text in a template for \.{\\halign},
+and so on. When reading a character file, special characters must be
+classified as math delimiters, etc.; comments and extra blank spaces must
+be removed, paragraphs must be recognized, and control sequences must be
+found in the hash table. Furthermore there are occasions in which the
+scanning routines have looked ahead for a word like `\.{plus}' but only
+part of that word was found, hence a few characters must be put back
+into the input and scanned again.
+
+To handle these situations, which might all be present simultaneously,
+\TeX\ uses various stacks that hold information about the incomplete
+activities, and there is a finite state control for each level of the
+input mechanism. These stacks record the current state of an implicitly
+recursive process, but the |get_next| procedure is not recursive.
+Therefore it will not be difficult to translate these algorithms into
+low-level languages that do not support recursion.
+
+@<Glob...@>=
+static eight_bits @!cur_cmd; /*current command set by |get_next|*/
+static halfword @!cur_chr; /*operand of current command*/
+static pointer @!cur_cs; /*control sequence found here, zero if none found*/
+static halfword @!cur_tok; /*packed representative of |cur_cmd| and |cur_chr|*/
+
+@ The |print_cmd_chr| routine prints a symbolic interpretation of a
+command code and its modifier. This is used in certain `\.{You can\'t}'
+error messages, and in the implementation of diagnostic routines like
+\.{\\show}.
+
+The body of |print_cmd_chr| is a rather tedious listing of print
+commands, and most of it is essentially an inverse to the |primitive|
+routine that enters a \TeX\ primitive into |eqtb|. Therefore much of
+this procedure appears elsewhere in the program,
+together with the corresponding |primitive| calls.
+
+ at d chr_cmd(A) {@+print(A);print_ASCII(chr_code);
+  }
+
+@<Declare the procedure called |print_cmd_chr|@>=
+static void print_cmd_chr(quarterword @!cmd, halfword @!chr_code)
+{@+int n; /*temp variable*/
+switch (cmd) {
+case left_brace: chr_cmd("begin-group character ")@;@+break;
+case right_brace: chr_cmd("end-group character ")@;@+break;
+case math_shift: chr_cmd("math shift character ")@;@+break;
+case mac_param: chr_cmd("macro parameter character ")@;@+break;
+case sup_mark: chr_cmd("superscript character ")@;@+break;
+case sub_mark: chr_cmd("subscript character ")@;@+break;
+case endv: print("end of alignment template");@+break;
+case spacer: chr_cmd("blank space ")@;@+break;
+case letter: chr_cmd("the letter ")@;@+break;
+case other_char: chr_cmd("the character ")@;@+break;
+ at t\4@>@<Cases of |print_cmd_chr| for symbolic printing of primitives@>@/
+default:print("[unknown command code!]");
+}
+}
+
+@ Here is a procedure that displays the current command.
+
+ at p static void show_cur_cmd_chr(void)
+{@+int n; /*level of \.{\\if...\\fi} nesting*/
+int @!l; /*line where \.{\\if} started*/
+pointer @!p;
+begin_diagnostic();print_nl("{");
+if (mode!=shown_mode)
+  {@+print_mode(mode);print(": ");shown_mode=mode;
+  }
+print_cmd_chr(cur_cmd, cur_chr);
+if (tracing_ifs > 0)
+  if (cur_cmd >= if_test) if (cur_cmd <= fi_or_else)
+    {@+print(": ");
+    if (cur_cmd==fi_or_else)
+      {@+print_cmd_chr(if_test, cur_if);print_char(' ');
+      n=0;l=if_line;
+      }
+    else{@+n=1;l=line;
+      }
+    p=cond_ptr;
+    while (p!=null)
+      {@+incr(n);p=link(p);
+      }
+    print("(level ");print_int(n);print_char(')');print_if_line(l);
+    }
+print_char('}');
+end_diagnostic(false);
+}
+
+@* Input stacks and states.
+This implementation of
+\TeX\ uses two different conventions for representing sequential stacks.
+@^stack conventions@>@^conventions for representing stacks@>
+
+\yskip\hangg 1) If there is frequent access to the top entry, and if the
+stack is essentially never empty, then the top entry is kept in a global
+variable (even better would be a machine register), and the other entries
+appear in the array $\\{stack}[0\to(\\{ptr}-1)]$. For example, the
+semantic stack described above is handled this way, and so is the input
+stack that we are about to study.
+
+\yskip\hangg 2) If there is infrequent top access, the entire stack contents
+are in the array $\\{stack}[0\to(\\{ptr}-1)]$. For example, the |save_stack|
+is treated this way, as we have seen.
+
+\yskip\noindent
+The state of \TeX's input mechanism appears in the input stack, whose
+entries are records with six fields, called |state|, |index|, |start|, |loc|,
+|limit|, and |name|. This stack is maintained with
+convention~(1), so it is declared in the following way:
+
+@<Types...@>=
+typedef struct {
+  quarterword @!state_field, @!index_field;
+  halfword @!start_field, @!loc_field, @!limit_field, @!name_field;
+  } in_state_record;
+
+@ @<Glob...@>=
+static in_state_record @!input_stack[stack_size+1];
+static int @!input_ptr; /*first unused location of |input_stack|*/
+static int @!max_in_stack; /*largest value of |input_ptr| when pushing*/
+static in_state_record @!cur_input;
+   /*the ``top'' input state, according to convention (1)*/
+
+@ We've already defined the special variable |loc====cur_input.loc_field|
+in our discussion of basic input-output routines. The other components of
+|cur_input| are defined in the same way:
+
+ at d state cur_input.state_field /*current scanner state*/
+ at d index cur_input.index_field /*reference for buffer information*/
+ at d start cur_input.start_field /*starting position in |buffer|*/
+ at d limit cur_input.limit_field /*end of current line in |buffer|*/
+ at d name cur_input.name_field /*name of the current file*/
+
+@ Let's look more closely now at the control variables
+(|state|,~|index|,~|start|,~|loc|,~|limit|,~|name|),
+assuming that \TeX\ is reading a line of characters that have been input
+from some file or from the user's terminal. There is an array called
+|buffer| that acts as a stack of all lines of characters that are
+currently being read from files, including all lines on subsidiary
+levels of the input stack that are not yet completed. \TeX\ will return to
+the other lines when it is finished with the present input file.
+
+(Incidentally, on a machine with byte-oriented addressing, it might be
+appropriate to combine |buffer| with the |str_pool| array,
+letting the buffer entries grow downward from the top of the string pool
+and checking that these two tables don't bump into each other.)
+
+The line we are currently working on begins in position |start| of the
+buffer; the next character we are about to read is |buffer[loc]|; and
+|limit| is the location of the last character present.  If |loc > limit|,
+the line has been completely read. Usually |buffer[limit]| is the
+|end_line_char|, denoting the end of a line, but this is not
+true if the current line is an insertion that was entered on the user's
+terminal in response to an error message.
+
+The |name| variable is a string number that designates the name of
+the current file, if we are reading a text file. It is zero if we
+are reading from the terminal; it is |n+1| if we are reading from
+input stream |n|, where |0 <= n <= 16|. (Input stream 16 stands for
+an invalid stream number; in such cases the input is actually from
+the terminal, under control of the procedure |read_toks|.)
+Finally |18 <= name <= 19| indicates that we are reading a pseudo file
+created by the \.{\\scantokens} command.
+
+The |state| variable has one of three values, when we are scanning such
+files:
+$$\baselineskip 15pt\vbox{\halign{#\hfil\cr
+1) |state==mid_line| is the normal state.\cr
+2) |state==skip_blanks| is like |mid_line|, but blanks are ignored.\cr
+3) |state==new_line| is the state at the beginning of a line.\cr}}$$
+These state values are assigned numeric codes so that if we add the state
+code to the next character's command code, we get distinct values. For
+example, `|mid_line+spacer|' stands for the case that a blank
+space character occurs in the middle of a line when it is not being
+ignored; after this case is processed, the next value of |state| will
+be |skip_blanks|.
+
+ at d mid_line 1 /*|state| code when scanning a line of characters*/
+ at d skip_blanks (2+max_char_code) /*|state| code when ignoring blanks*/
+ at d new_line (3+max_char_code+max_char_code) /*|state| code at start of line*/
+
+@ Additional information about the current line is available via the
+|index| variable, which counts how many lines of characters are present
+in the buffer below the current level. We have |index==0| when reading
+from the terminal and prompting the user for each line; then if the user types,
+e.g., `\.{\\input paper}', we will have |index==1| while reading
+the file \.{paper.tex}. However, it does not follow that |index| is the
+same as the input stack pointer, since many of the levels on the input
+stack may come from token lists. For example, the instruction `\.{\\input
+paper}' might occur in a token list.
+
+The global variable |in_open| is equal to the |index|
+value of the highest non-token-list level. Thus, the number of partially read
+lines in the buffer is |in_open+1|, and we have |in_open==index|
+when we are not reading a token list.
+
+If we are not currently reading from the terminal, or from an input
+stream, we are reading from the file variable |input_file[index]|. We use
+the notation |terminal_input| as a convenient abbreviation for |name==0|,
+and |cur_file| as an abbreviation for |input_file[index]|.
+
+The global variable |line| contains the line number in the topmost
+open file, for use in error messages. If we are not reading from
+the terminal, |line_stack[index]| holds the line number for the
+enclosing level, so that |line| can be restored when the current
+file has been read. Line numbers should never be negative, since the
+negative of the current line number is used to identify the user's output
+routine in the |mode_line| field of the semantic nest entries.
+
+If more information about the input state is needed, it can be
+included in small arrays like those shown here. For example,
+the current page or segment number in the input file might be
+put into a variable |@!page|, maintained for enclosing levels in
+`\ignorespaces|@!page_stack: array[1 dotdot max_in_open]int|\unskip'
+by analogy with |line_stack|.
+@^system dependencies@>
+
+ at d terminal_input (name==0) /*are we reading from the terminal?*/
+ at d cur_file input_file[index] /*the current |alpha_file| variable*/
+
+@<Glob...@>=
+static int @!in_open; /*the number of lines in the buffer, less one*/
+static int @!open_parens; /*the number of open text files*/
+static alpha_file @!input_file0[max_in_open], *const @!input_file = @!input_file0-1;
+static int @!line; /*current line number in the current source file*/
+static int @!line_stack0[max_in_open], *const @!line_stack = @!line_stack0-1;
+
+@ Users of \TeX\ sometimes forget to balance left and right braces properly,
+and one of the ways \TeX\ tries to spot such errors is by considering an
+input file as broken into subfiles by control sequences that
+are declared to be \.{\\outer}.
+
+A variable called |scanner_status| tells \TeX\ whether or not to complain
+when a subfile ends. This variable has six possible values:
+
+\yskip\hang|normal|, means that a subfile can safely end here without incident.
+
+\yskip\hang|skipping|, means that a subfile can safely end here, but not a file,
+because we're reading past some conditional text that was not selected.
+
+\yskip\hang|defining|, means that a subfile shouldn't end now because a
+macro is being defined.
+
+\yskip\hang|matching|, means that a subfile shouldn't end now because a
+macro is being used and we are searching for the end of its arguments.
+
+\yskip\hang|aligning|, means that a subfile shouldn't end now because we are
+not finished with the preamble of an \.{\\halign} or \.{\\valign}.
+
+\yskip\hang|absorbing|, means that a subfile shouldn't end now because we are
+reading a balanced token list for \.{\\message}, \.{\\write}, etc.
+
+\yskip\noindent
+If the |scanner_status| is not |normal|, the variable |warning_index| points
+to the |eqtb| location for the relevant control sequence name to print
+in an error message.
+
+ at d skipping 1 /*|scanner_status| when passing conditional text*/
+ at d defining 2 /*|scanner_status| when reading a macro definition*/
+ at d matching 3 /*|scanner_status| when reading macro arguments*/
+ at d aligning 4 /*|scanner_status| when reading an alignment preamble*/
+ at d absorbing 5 /*|scanner_status| when reading a balanced text*/
+
+@<Glob...@>=
+static int @!scanner_status; /*can a subfile end now?*/
+static pointer @!warning_index; /*identifier relevant to non-|normal| scanner status*/
+static pointer @!def_ref; /*reference count of token list being defined*/
+
+@ Here is a procedure that uses |scanner_status| to print a warning message
+when a subfile has ended, and at certain other crucial times:
+
+@<Declare the procedure called |runaway|@>=
+static void runaway(void)
+{@+pointer p; /*head of runaway list*/
+if (scanner_status > skipping)
+  {@+print_nl("Runaway ");
+ at .Runaway...@>
+  switch (scanner_status) {
+  case defining: {@+print("definition");p=def_ref;
+    } @+break;
+  case matching: {@+print("argument");p=temp_head;
+    } @+break;
+  case aligning: {@+print("preamble");p=hold_head;
+    } @+break;
+  case absorbing: {@+print("text");p=def_ref;
+    }
+  }  /*there are no other cases*/
+  print_char('?');print_ln();show_token_list(link(p), null, error_line-10);
+  }
+}
+
+@ However, all this discussion about input state really applies only to the
+case that we are inputting from a file. There is another important case,
+namely when we are currently getting input from a token list. In this case
+|state==token_list|, and the conventions about the other state variables
+are different:
+
+\yskip\hang|loc| is a pointer to the current node in the token list, i.e.,
+the node that will be read next. If |loc==null|, the token list has been
+fully read.
+
+\yskip\hang|start| points to the first node of the token list; this node
+may or may not contain a reference count, depending on the type of token
+list involved.
+
+\yskip\hang|token_type|, which takes the place of |index| in the
+discussion above, is a code number that explains what kind of token list
+is being scanned.
+
+\yskip\hang|name| points to the |eqtb| address of the control sequence
+being expanded, if the current token list is a macro.
+
+\yskip\hang|param_start|, which takes the place of |limit|, tells where
+the parameters of the current macro begin in the |param_stack|, if the
+current token list is a macro.
+
+\yskip\noindent The |token_type| can take several values, depending on
+where the current token list came from:
+
+\yskip\hang|parameter|, if a parameter is being scanned;
+
+\hang|u_template|, if the \<u_j> part of an alignment
+template is being scanned;
+
+\hang|v_template|, if the \<v_j> part of an alignment
+template is being scanned;
+
+\hang|backed_up|, if the token list being scanned has been inserted as
+`to be read again';
+
+\hang|inserted|, if the token list being scanned has been inserted as
+the text expansion of a \.{\\count} or similar variable;
+
+\hang|macro|, if a user-defined control sequence is being scanned;
+
+\hang|output_text|, if an \.{\\output} routine is being scanned;
+
+\hang|every_par_text|, if the text of \.{\\everypar} is being scanned;
+
+\hang|every_math_text|, if the text of \.{\\everymath} is being scanned;
+
+\hang|every_display_text|, if the text of \.{\\everydisplay} is being scanned;
+
+\hang|every_hbox_text|, if the text of \.{\\everyhbox} is being scanned;
+
+\hang|every_vbox_text|, if the text of \.{\\everyvbox} is being scanned;
+
+\hang|every_job_text|, if the text of \.{\\everyjob} is being scanned;
+
+\hang|every_cr_text|, if the text of \.{\\everycr} is being scanned;
+
+\hang|mark_text|, if the text of a \.{\\mark} is being scanned;
+
+\hang|write_text|, if the text of a \.{\\write} is being scanned.
+
+\yskip\noindent
+The codes for |output_text|, |every_par_text|, etc., are equal to a constant
+plus the corresponding codes for token list parameters |output_routine_loc|,
+|every_par_loc|, etc.  The token list begins with a reference count if and
+only if |token_type >= macro|.
+@^reference counts@>
+
+Since \eTeX's additional token list parameters precede |toks_base|, the
+corresponding token types must precede |write_text|.
+
+ at d token_list 0 /*|state| code when scanning a token list*/
+ at d token_type index /*type of current token list*/
+ at d param_start limit /*base of macro parameters in |param_stack|*/
+ at d parameter 0 /*|token_type| code for parameter*/
+ at d u_template 1 /*|token_type| code for \<u_j> template*/
+ at d v_template 2 /*|token_type| code for \<v_j> template*/
+ at d backed_up 3 /*|token_type| code for text to be reread*/
+ at d inserted 4 /*|token_type| code for inserted texts*/
+ at d macro 5 /*|token_type| code for defined control sequences*/
+ at d output_text 6 /*|token_type| code for output routines*/
+ at d every_par_text 7 /*|token_type| code for \.{\\everypar}*/
+ at d every_math_text 8 /*|token_type| code for \.{\\everymath}*/
+ at d every_display_text 9 /*|token_type| code for \.{\\everydisplay}*/
+ at d every_hbox_text 10 /*|token_type| code for \.{\\everyhbox}*/
+ at d every_vbox_text 11 /*|token_type| code for \.{\\everyvbox}*/
+ at d every_job_text 12 /*|token_type| code for \.{\\everyjob}*/
+ at d every_cr_text 13 /*|token_type| code for \.{\\everycr}*/
+ at d mark_text 14 /*|token_type| code for \.{\\topmark}, etc.*/
+@#
+ at d eTeX_text_offset (output_routine_loc-output_text)
+ at d every_eof_text (every_eof_loc-eTeX_text_offset)
+   /*|token_type| code for \.{\\everyeof}*/
+@#
+ at d write_text (toks_base-eTeX_text_offset) /*|token_type| code for \.{\\write}*/
+
+@ The |param_stack| is an auxiliary array used to hold pointers to the token
+lists for parameters at the current level and subsidiary levels of input.
+This stack is maintained with convention (2), and it grows at a different
+rate from the others.
+
+@<Glob...@>=
+static pointer @!param_stack[param_size+1];
+   /*token list pointers for parameters*/
+static int @!param_ptr; /*first unused entry in |param_stack|*/
+static int @!max_param_stack;
+   /*largest value of |param_ptr|, will be | <= param_size+9|*/
+
+@ The input routines must also interact with the processing of
+\.{\\halign} and \.{\\valign}, since the appearance of tab marks and
+\.{\\cr} in certain places is supposed to trigger the beginning of special
+\<v_j> template text in the scanner. This magic is accomplished by an
+|align_state| variable that is increased by~1 when a `\.{\char'173}' is
+scanned and decreased by~1 when a `\.{\char'175}' is scanned. The |align_state|
+is nonzero during the \<u_j> template, after which it is set to zero; the
+\<v_j> template begins when a tab mark or \.{\\cr} occurs at a time that
+|align_state==0|.
+
+The same principle applies when entering the definition of a
+control sequence between \.{\\csname} and \.{\\endcsname}.
+
+@<Glob...@>=
+static int @!align_state; /*group level with respect to current alignment*/
+static int @!incsname_state; /*group level with respect to in csname state*/
+
+@ Thus, the ``current input state'' can be very complicated indeed; there
+can be many levels and each level can arise in a variety of ways. The
+|show_context| procedure, which is used by \TeX's error-reporting routine to
+print out the current input state on all levels down to the most recent
+line of characters from an input file, illustrates most of these conventions.
+The global variable |base_ptr| contains the lowest level that was
+displayed by this procedure.
+
+@<Glob...@>=
+static int @!base_ptr; /*shallowest level shown by |show_context|*/
+
+@ The status at each level is indicated by printing two lines, where the first
+line indicates what was read so far and the second line shows what remains
+to be read. The context is cropped, if necessary, so that the first line
+contains at most |half_error_line| characters, and the second contains
+at most |error_line|. Non-current input levels whose |token_type| is
+`|backed_up|' are shown only if they have not been fully read.
+
+ at p static void show_context(void) /*prints where the scanner is*/
+{@+
+int old_setting; /*saved |selector| setting*/
+int @!nn; /*number of contexts shown so far, less one*/
+bool @!bottom_line; /*have we reached the final context to be shown?*/
+@<Local variables for formatting calculations@>@/
+base_ptr=input_ptr;input_stack[base_ptr]=cur_input;
+   /*store current state*/
+nn=-1;bottom_line=false;
+loop at +{@+cur_input=input_stack[base_ptr]; /*enter into the context*/
+  if ((state!=token_list))
+    if ((name > 19)||(base_ptr==0)) bottom_line=true;
+  if ((base_ptr==input_ptr)||bottom_line||(nn < error_context_lines))
+    @<Display the current context@>@;
+  else if (nn==error_context_lines)
+    {@+print_nl("...");incr(nn); /*omitted if |error_context_lines < 0|*/
+    }
+  if (bottom_line) goto done;
+  decr(base_ptr);
+  }
+done: cur_input=input_stack[input_ptr]; /*restore original state*/
+}
+
+@ @<Display the current context@>=
+{@+if ((base_ptr==input_ptr)||(state!=token_list)||
+   (token_type!=backed_up)||(loc!=null))
+     /*we omit backed-up token lists that have already been read*/
+  {@+tally=0; /*get ready to count characters*/
+  old_setting=selector;
+  if (state!=token_list)
+    {@+@<Print location of current line@>;
+    @<Pseudoprint the line@>;
+    }
+  else{@+@<Print type of token list@>;
+    @<Pseudoprint the token list@>;
+    }
+  selector=old_setting; /*stop pseudoprinting*/
+  @<Print two lines using the tricky pseudoprinted information@>;
+  incr(nn);
+  }
+}
+
+@ This routine should be changed, if necessary, to give the best possible
+indication of where the current line resides in the input file.
+For example, on some systems it is best to print both a page and line number.
+@^system dependencies@>
+
+@<Print location of current line@>=
+if (name <= 17)
+  if (terminal_input)
+    if (base_ptr==0) print_nl("<*>");else print_nl("<insert> ");
+  else{@+print_nl("<read ");
+    if (name==17) print_char('*');@+else print_int(name-1);
+ at .*\relax@>
+    print_char('>');
+    }
+else{@+print_nl("l.");
+  if (index==in_open) print_int(line);
+  else print_int(line_stack[index+1]); /*input from a pseudo file*/
+  }
+print_char(' ')
+
+@ @<Print type of token list@>=
+switch (token_type) {
+case parameter: print_nl("<argument> ");@+break;
+case u_template: case v_template: print_nl("<template> ");@+break;
+case backed_up: if (loc==null) print_nl("<recently read> ");
+  else print_nl("<to be read again> ");@+break;
+case inserted: print_nl("<inserted text> ");@+break;
+case macro: {@+print_ln();print_cs(name);
+  } @+break;
+case output_text: print_nl("<output> ");@+break;
+case every_par_text: print_nl("<everypar> ");@+break;
+case every_math_text: print_nl("<everymath> ");@+break;
+case every_display_text: print_nl("<everydisplay> ");@+break;
+case every_hbox_text: print_nl("<everyhbox> ");@+break;
+case every_vbox_text: print_nl("<everyvbox> ");@+break;
+case every_job_text: print_nl("<everyjob> ");@+break;
+case every_cr_text: print_nl("<everycr> ");@+break;
+case mark_text: print_nl("<mark> ");@+break;
+case every_eof_text: print_nl("<everyeof> ");@+break;
+case write_text: print_nl("<write> ");@+break;
+default:print_nl("?"); /*this should never happen*/
+}
+
+@ Here it is necessary to explain a little trick. We don't want to store a long
+string that corresponds to a token list, because that string might take up
+lots of memory; and we are printing during a time when an error message is
+being given, so we dare not do anything that might overflow one of \TeX's
+tables. So `pseudoprinting' is the answer: We enter a mode of printing
+that stores characters into a buffer of length |error_line|, where character
+$k+1$ is placed into \hbox{|trick_buf[k%error_line]|} if
+|k < trick_count|, otherwise character |k| is dropped. Initially we set
+|tally=0| and |trick_count=1000000|; then when we reach the
+point where transition from line 1 to line 2 should occur, we
+set |first_count=tally| and |trick_count=@tmax@>(error_line,
+tally+1+error_line-half_error_line)|. At the end of the
+pseudoprinting, the values of |first_count|, |tally|, and
+|trick_count| give us all the information we need to print the two lines,
+and all of the necessary text is in |trick_buf|.
+
+Namely, let |l| be the length of the descriptive information that appears
+on the first line. The length of the context information gathered for that
+line is |k==first_count|, and the length of the context information
+gathered for line~2 is $m=\min(|tally|, |trick_count|)-k$. If |l+k <= h|,
+where |h==half_error_line|, we print |trick_buf[0 dotdot k-1]| after the
+descriptive information on line~1, and set |n=l+k|; here |n| is the
+length of line~1. If $l+k>h$, some cropping is necessary, so we set |n=h|
+and print `\.{...}' followed by
+$$\hbox{|trick_buf[(l+k-h+3)dotdot k-1]|,}$$
+where subscripts of |trick_buf| are circular modulo |error_line|. The
+second line consists of |n|~spaces followed by |trick_buf[k dotdot(k+m-1)]|,
+unless |n+m > error_line|; in the latter case, further cropping is done.
+This is easier to program than to explain.
+
+@<Local variables for formatting...@>=
+int @!i; /*index into |buffer|*/
+int @!j; /*end of current line in |buffer|*/
+int @!l; /*length of descriptive information on line 1*/
+int @!m; /*context information gathered for line 2*/
+int @!n; /*length of line 1*/
+int @!p; /*starting or ending place in |trick_buf|*/
+int @!q; /*temporary index*/
+
+@ The following code sets up the print routines so that they will gather
+the desired information.
+
+ at d begin_pseudoprint
+  {@+l=tally;tally=0;selector=pseudo;
+  trick_count=1000000;
+  }
+ at d set_trick_count
+  {@+first_count=tally;
+  trick_count=tally+1+error_line-half_error_line;
+  if (trick_count < error_line) trick_count=error_line;
+  }
+
+@ And the following code uses the information after it has been gathered.
+
+@<Print two lines using the tricky pseudoprinted information@>=
+if (trick_count==1000000) set_trick_count;
+   /*|set_trick_count| must be performed*/
+if (tally < trick_count) m=tally-first_count;
+else m=trick_count-first_count; /*context on line 2*/
+if (l+first_count <= half_error_line)
+  {@+p=0;n=l+first_count;
+  }
+else{@+print("...");p=l+first_count-half_error_line+3;
+  n=half_error_line;
+  }
+for (q=p; q<=first_count-1; q++) print_char(trick_buf[q%error_line]);
+print_ln();
+for (q=1; q<=n; q++) print_char(' '); /*print |n| spaces to begin line~2*/
+if (m+n <= error_line) p=first_count+m;else p=first_count+(error_line-n-3);
+for (q=first_count; q<=p-1; q++) print_char(trick_buf[q%error_line]);
+if (m+n > error_line) print("...")
+
+@ But the trick is distracting us from our current goal, which is to
+understand the input state. So let's concentrate on the data structures that
+are being pseudoprinted as we finish up the |show_context| procedure.
+
+@<Pseudoprint the line@>=
+begin_pseudoprint;
+if (buffer[limit]==end_line_char) j=limit;
+else j=limit+1; /*determine the effective end of the line*/
+if (j > 0) for (i=start; i<=j-1; i++)
+  {@+if (i==loc) set_trick_count;
+  printn(buffer[i]);
+  }
+
+@ @<Pseudoprint the token list@>=
+begin_pseudoprint;
+if (token_type < macro) show_token_list(start, loc, 100000);
+else show_token_list(link(start), loc, 100000) /*avoid reference count*/
+
+@ Here is the missing piece of |show_token_list| that is activated when the
+token beginning line~2 is about to be shown:
+
+@<Do magic computation@>=set_trick_count
+
+@* Maintaining the input stacks.
+The following subroutines change the input status in commonly needed ways.
+
+First comes |push_input|, which stores the current state and creates a
+new level (having, initially, the same properties as the old).
+
+ at d push_input @t@> /*enter a new input level, save the old*/
+  {@+if (input_ptr > max_in_stack)
+    {@+max_in_stack=input_ptr;
+    if (input_ptr==stack_size) overflow("input stack size", stack_size);
+@:TeX capacity exceeded input stack size}{\quad input stack size@>
+    }
+  input_stack[input_ptr]=cur_input; /*stack the record*/
+  incr(input_ptr);
+  }
+
+@ And of course what goes up must come down.
+
+ at d pop_input @t@> /*leave an input level, re-enter the old*/
+  {@+decr(input_ptr);cur_input=input_stack[input_ptr];
+  }
+
+@ Here is a procedure that starts a new level of token-list input, given
+a token list |p| and its type |t|. If |t==macro|, the calling routine should
+set |name| and |loc|.
+
+ at d back_list(A) begin_token_list(A, backed_up) /*backs up a simple token list*/
+ at d ins_list(A) begin_token_list(A, inserted) /*inserts a simple token list*/
+
+ at p static void begin_token_list(pointer @!p, quarterword @!t)
+{@+push_input;state=token_list;start=p;token_type=t;
+if (t >= macro)  /*the token list starts with a reference count*/
+  {@+add_token_ref(p);
+  if (t==macro) param_start=param_ptr;
+  else{@+loc=link(p);
+    if (tracing_macros > 1)
+      {@+begin_diagnostic();print_nl("");
+      switch (t) {
+      case mark_text: print_esc("mark");@+break;
+      case write_text: print_esc("write");@+break;
+      default:print_cmd_chr(assign_toks, t-output_text+output_routine_loc);
+      } @/
+      print("->");token_show(p);end_diagnostic(false);
+      }
+    }
+  }
+else loc=p;
+}
+
+@ When a token list has been fully scanned, the following computations
+should be done as we leave that level of input. The |token_type| tends
+to be equal to either |backed_up| or |inserted| about 2/3 of the time.
+@^inner loop@>
+
+ at p static void end_token_list(void) /*leave a token-list input level*/
+{@+if (token_type >= backed_up)  /*token list to be deleted*/
+  {@+if (token_type <= inserted) flush_list(start);
+  else{@+delete_token_ref(start); /*update reference count*/
+    if (token_type==macro)  /*parameters must be flushed*/
+      while (param_ptr > param_start)
+        {@+decr(param_ptr);
+        flush_list(param_stack[param_ptr]);
+        }
+    }
+  }
+else if (token_type==u_template)
+  if (align_state > 500000) align_state=0;
+  else fatal_error("(interwoven alignment preambles are not allowed)");
+ at .interwoven alignment preambles...@>
+pop_input;
+check_interrupt;
+}
+
+@ Sometimes \TeX\ has read too far and wants to ``unscan'' what it has
+seen. The |back_input| procedure takes care of this by putting the token
+just scanned back into the input stream, ready to be read again. This
+procedure can be used only if |cur_tok| represents the token to be
+replaced. Some applications of \TeX\ use this procedure a lot,
+so it has been slightly optimized for speed.
+@^inner loop@>
+
+ at p static void back_input(void) /*undoes one token of input*/
+{@+pointer p; /*a token list of length one*/
+while ((state==token_list)&&(loc==null)&&(token_type!=v_template))
+  end_token_list(); /*conserve stack space*/
+p=get_avail();info(p)=cur_tok;
+if (cur_tok < right_brace_limit)
+  if (cur_tok < left_brace_limit) decr(align_state);
+  else incr(align_state);
+push_input;state=token_list;start=p;token_type=backed_up;
+loc=p; /*that was |back_list(p)|, without procedure overhead*/
+}
+
+@ @<Insert token |p| into \TeX's input@>=
+{@+t=cur_tok;cur_tok=p;
+if (a)
+  {@+p=get_avail();info(p)=cur_tok;link(p)=loc;loc=p;start=p;
+  if (cur_tok < right_brace_limit)
+    if (cur_tok < left_brace_limit) decr(align_state);
+    else incr(align_state);
+  }
+else{@+back_input();a=eTeX_ex;
+  }
+cur_tok=t;
+}
+
+@ The |back_error| routine is used when we want to replace an offending token
+just before issuing an error message. This routine, like |back_input|,
+requires that |cur_tok| has been set. We disable interrupts during the
+call of |back_input| so that the help message won't be lost.
+
+ at p static void back_error(void) /*back up one token and call |error|*/
+{@+OK_to_interrupt=false;back_input();OK_to_interrupt=true;error();
+}
+@#
+static void ins_error(void) /*back up one inserted token and call |error|*/
+{@+OK_to_interrupt=false;back_input();token_type=inserted;
+OK_to_interrupt=true;error();
+}
+
+@ The |begin_file_reading| procedure starts a new level of input for lines
+of characters to be read from a file, or as an insertion from the
+terminal. It does not take care of opening the file, nor does it set |loc|
+or |limit| or |line|.
+@^system dependencies@>
+
+ at p static void begin_file_reading(void)
+{@+if (in_open==max_in_open) overflow("text input levels", max_in_open);
+@:TeX capacity exceeded text input levels}{\quad text input levels@>
+if (first==buf_size) overflow("buffer size", buf_size);
+@:TeX capacity exceeded buffer size}{\quad buffer size@>
+incr(in_open);push_input;index=in_open;@/
+source_filename_stack[index]=0; /* k\TeX\ */
+eof_seen[index]=false;
+grp_stack[index]=cur_boundary;if_stack[index]=cond_ptr;
+line_stack[index]=line;start=first;state=mid_line;
+name=0; /*|terminal_input| is now |true|*/
+}
+
+@ Conversely, the variables must be downdated when such a level of input
+is finished:
+
+ at p static void end_file_reading(void)
+{@+first=start;line=line_stack[index];
+if ((name==18)||(name==19)) pseudo_close();else
+if (name > 17) a_close(&cur_file); /*forget it*/
+pop_input;decr(in_open);
+}
+
+@ In order to keep the stack from overflowing during a long sequence of
+inserted `\.{\\show}' commands, the following routine removes completed
+error-inserted lines from memory.
+
+ at p static void clear_for_error_prompt(void)
+{@+while ((state!=token_list)&&terminal_input&&@|
+  (input_ptr > 0)&&(loc > limit)) end_file_reading();
+print_ln();clear_terminal;
+}
+
+@ To get \TeX's whole input mechanism going, we perform the following
+actions.
+
+@<Initialize the input routines@>=
+{@+input_ptr=0;max_in_stack=0;
+in_open=0;open_parens=0;max_buf_stack=0;
+grp_stack[0]=0;if_stack[0]=null;
+param_ptr=0;max_param_stack=0;
+first=buf_size;@/do at +{buffer[first]=0;decr(first);}@+ while (!(first==0));
+scanner_status=normal;warning_index=null;first=1;
+state=new_line;start=1;index=0;line=0;name=0;
+force_eof=false;
+align_state=1000000;@/
+if (!init_terminal()) exit(0);
+limit=last;first=last+1; /*|init_terminal| has set |loc| and |last|*/
+}
+
+@* Getting the next token.
+The heart of \TeX's input mechanism is the |get_next| procedure, which
+we shall develop in the next few sections of the program. Perhaps we
+shouldn't actually call it the ``heart,'' however, because it really acts
+as \TeX's eyes and mouth, reading the source files and gobbling them up.
+And it also helps \TeX\ to regurgitate stored token lists that are to be
+processed again.
+@^eyes and mouth@>
+
+The main duty of |get_next| is to input one token and to set |cur_cmd|
+and |cur_chr| to that token's command code and modifier. Furthermore, if
+the input token is a control sequence, the |eqtb| location of that control
+sequence is stored in |cur_cs|; otherwise |cur_cs| is set to zero.
+
+Underlying this simple description is a certain amount of complexity
+because of all the cases that need to be handled.
+However, the inner loop of |get_next| is reasonably short and fast.
+
+When |get_next| is asked to get the next token of a \.{\\read} line,
+it sets |cur_cmd==cur_chr==cur_cs==0| in the case that no more tokens
+appear on that line. (There might not be any tokens at all, if the
+|end_line_char| has |ignore| as its catcode.)
+
+@ The value of |par_loc| is the |eqtb| address of `\.{\\par}'. This quantity
+is needed because a blank line of input is supposed to be exactly equivalent
+to the appearance of \.{\\par}; we must set |cur_cs=par_loc|
+when detecting a blank line.
+
+@<Glob...@>=
+static pointer @!par_loc; /*location of `\.{\\par}' in |eqtb|*/
+static halfword @!par_token; /*token representing `\.{\\par}'*/
+
+@ @<Put each...@>=
+primitive("par", par_end, 256); /*cf.\ |scan_file_name|*/
+@!@:par\_}{\.{\\par} primitive@>
+par_loc=cur_val;par_token=cs_token_flag+par_loc;
+
+@ @<Cases of |print_cmd_chr|...@>=
+case par_end: print_esc("par");@+break;
+
+@ Before getting into |get_next|, let's consider the subroutine that
+is called when an `\.{\\outer}' control sequence has been scanned or
+when the end of a file has been reached. These two cases are distinguished
+by |cur_cs|, which is zero at the end of a file.
+
+ at p static void check_outer_validity(void)
+{@+pointer p; /*points to inserted token list*/
+pointer @!q; /*auxiliary pointer*/
+if (scanner_status!=normal)
+  {@+deletions_allowed=false;
+  @<Back up an outer control sequence so that it can be reread@>;
+  if (scanner_status > skipping)
+    @<Tell the user what has run away and try to recover@>@;
+  else{@+print_err("Incomplete ");print_cmd_chr(if_test, cur_if);
+ at .Incomplete \\if...@>
+    print("; all text was ignored after line ");print_int(skip_line);
+    help3("A forbidden control sequence occurred in skipped text.",@/
+    "This kind of error happens when you say `\\if...' and forget",@/
+    "the matching `\\fi'. I've inserted a `\\fi'; this might work.");
+    if (cur_cs!=0) cur_cs=0;
+    else help_line[2]=@|
+      "The file ended while I was skipping conditional text.";
+    cur_tok=cs_token_flag+frozen_fi;ins_error();
+    }
+  deletions_allowed=true;
+  }
+}
+
+@ An outer control sequence that occurs in a \.{\\read} will not be reread,
+since the error recovery for \.{\\read} is not very powerful.
+
+@<Back up an outer control sequence so that it can be reread@>=
+if (cur_cs!=0)
+  {@+if ((state==token_list)||(name < 1)||(name > 17))
+    {@+p=get_avail();info(p)=cs_token_flag+cur_cs;
+    back_list(p); /*prepare to read the control sequence again*/
+    }
+  cur_cmd=spacer;cur_chr=' '; /*replace it by a space*/
+  }
+
+@ @<Tell the user what has run away...@>=
+{@+runaway(); /*print a definition, argument, or preamble*/
+if (cur_cs==0) print_err("File ended");
+ at .File ended while scanning...@>
+else{@+cur_cs=0;print_err("Forbidden control sequence found");
+ at .Forbidden control sequence...@>
+  }
+print(" while scanning ");
+@<Print either `\.{definition}' or `\.{use}' or `\.{preamble}' or `\.{text}', and
+insert tokens that should lead to recovery@>;
+print(" of ");sprint_cs(warning_index);
+help4("I suspect you have forgotten a `}', causing me",@/
+"to read past where you wanted me to stop.",@/
+"I'll try to recover; but if the error is serious,",@/
+"you'd better type `E' or `X' now and fix your file.");@/
+error();
+}
+
+@ The recovery procedure can't be fully understood without knowing more
+about the \TeX\ routines that should be aborted, but we can sketch the
+ideas here:  For a runaway definition or a runaway balanced text
+we will insert a right brace; for a
+runaway preamble, we will insert a special \.{\\cr} token and a right
+brace; and for a runaway argument, we will set |long_state| to
+|outer_call| and insert \.{\\par}.
+
+@<Print either `\.{definition}' or...@>=
+p=get_avail();
+switch (scanner_status) {
+case defining: {@+print("definition");info(p)=right_brace_token+'}';
+  } @+break;
+case matching: {@+print("use");info(p)=par_token;long_state=outer_call;
+  } @+break;
+case aligning: {@+print("preamble");info(p)=right_brace_token+'}';q=p;
+  p=get_avail();link(p)=q;info(p)=cs_token_flag+frozen_cr;
+  align_state=-1000000;
+  } @+break;
+case absorbing: {@+print("text");info(p)=right_brace_token+'}';
+  }
+}  /*there are no other cases*/
+ins_list(p)
+
+@ We need to mention a procedure here that may be called by |get_next|.
+
+ at p static void firm_up_the_line(void);
+
+@ Now we're ready to take the plunge into |get_next| itself. Parts of
+this routine are executed more often than any other instructions of \TeX.
+@^mastication@>@^inner loop@>
+
+ at p static void get_next(void) /*sets |cur_cmd|, |cur_chr|, |cur_cs| to next token*/
+{@+ /*go here to get the next input token*/
+   /*go here to eat the next character from a file*/
+   /*go here to digest it again*/
+   /*go here to start looking for a control sequence*/
+   /*go here when a control sequence has been found*/
+   /*go here when the next input token has been got*/
+int k; /*an index into |buffer|*/
+halfword @!t; /*a token*/
+int @!cat; /*|cat_code(cur_chr)|, usually*/
+ASCII_code @!c, @!cc; /*constituents of a possible expanded code*/
+int @!d; /*number of excess characters in an expanded code*/
+restart: cur_cs=0;
+if (state!=token_list)
+@<Input from external file, |goto restart| if no input found@>@;
+else@<Input from token list, |goto restart| if end of list or if a parameter needs
+to be expanded@>;
+@<If an alignment entry has just ended, take appropriate action@>;
+}
+
+@ An alignment entry ends when a tab or \.{\\cr} occurs, provided that the
+current level of braces is the same as the level that was present at the
+beginning of that alignment entry; i.e., provided that |align_state| has
+returned to the value it had after the \<u_j> template for that entry.
+@^inner loop@>
+
+@<If an alignment entry has just ended, take appropriate action@>=
+if (cur_cmd <= car_ret) if (cur_cmd >= tab_mark) if (align_state==0)
+  @<Insert the \(v)\<v_j> template and |goto restart|@>@;
+
+@ @<Input from external file, |goto restart| if no input found@>=
+@^inner loop@>
+{@+get_cur_chr: if (loc <= limit)  /*current line not yet finished*/
+  {@+cur_chr=buffer[loc];incr(loc);
+  reswitch: cur_cmd=cat_code(cur_chr);
+  @<Change state if necessary, and |goto switch| if the current character should be
+ignored, or |goto reswitch| if the current character changes to another@>;
+  }
+else{@+state=new_line;@/
+  @<Move to next line of file, or |goto restart| if there is no next line, or |return|
+if a \.{\\read} line has finished@>;
+  check_interrupt;
+  goto get_cur_chr;
+  }
+}
+
+@ The following 48-way switch accomplishes the scanning quickly, assuming
+that a decent \PASCAL\ compiler has translated the code. Note that the numeric
+values for |mid_line|, |skip_blanks|, and |new_line| are spaced
+apart from each other by |max_char_code+1|, so we can add a character's
+command code to the state to get a single number that characterizes both.
+
+ at d any_state_plus(A) case mid_line+A: case skip_blanks+A: case new_line+A
+
+@<Change state if necessary...@>=
+switch (state+cur_cmd) {
+@<Cases where character is ignored@>: goto get_cur_chr;
+any_state_plus(escape): @<Scan a control sequence and set |state:=skip_blanks| or
+|mid_line|@>@;@+break;
+any_state_plus(active_char): @<Process an active-character control sequence and set
+|state:=mid_line|@>@;@+break;
+any_state_plus(sup_mark): @<If this |sup_mark| starts an expanded character like~\.{\^\^A}
+or~\.{\^\^df}, then |goto reswitch|, otherwise set |state:=mid_line|@>@;@+break;
+any_state_plus(invalid_char): @<Decry the invalid character and |goto restart|@>@;
+ at t\4@>@<Handle situations involving spaces, braces, changes of state@>@;
+default:do_nothing;
+}
+
+@ @<Cases where character is ignored@>=
+any_state_plus(ignore): case skip_blanks+spacer: case new_line+spacer
+
+@ We go to |restart| instead of to |get_cur_chr|, because |state| might equal
+|token_list| after the error has been dealt with
+(cf.\ |clear_for_error_prompt|).
+
+@<Decry the invalid...@>=
+{@+print_err("Text line contains an invalid character");
+ at .Text line contains...@>
+help2("A funny symbol that I can't read has just been input.",@/
+"Continue, and I'll forget that it ever happened.");@/
+deletions_allowed=false;error();deletions_allowed=true;
+goto restart;
+}
+
+@ @d add_delims_to(A) A+math_shift: A+tab_mark: A+mac_param:
+  A+sub_mark: A+letter: A+other_char
+
+@<Handle situations involving spaces, braces, changes of state@>=
+case mid_line+spacer: @<Enter |skip_blanks| state, emit a space@>@;@+break;
+case mid_line+car_ret: @<Finish line, emit a space@>@;@+break;
+case skip_blanks+car_ret: any_state_plus(comment):
+  @<Finish line, |goto switch|@>@;
+case new_line+car_ret: @<Finish line, emit a \.{\\par}@>@;@+break;
+case mid_line+left_brace: incr(align_state);@+break;
+case skip_blanks+left_brace: case new_line+left_brace: {@+
+  state=mid_line;incr(align_state);
+  } @+break;
+case mid_line+right_brace: decr(align_state);@+break;
+case skip_blanks+right_brace: case new_line+right_brace: {@+
+  state=mid_line;decr(align_state);
+  } @+break;
+add_delims_to(case skip_blanks): add_delims_to(case new_line): state=mid_line;@+break;
+
+@ When a character of type |spacer| gets through, its character code is
+changed to $\.{"\ "}=040$. This means that the ASCII codes for tab and space,
+and for the space inserted at the end of a line, will
+be treated alike when macro parameters are being matched. We do this
+since such characters are indistinguishable on most computer terminal displays.
+
+@<Finish line, emit a space@>=
+{@+loc=limit+1;cur_cmd=spacer;cur_chr=' ';
+}
+
+@ The following code is performed only when |cur_cmd==spacer|.
+
+@<Enter |skip_blanks| state, emit a space@>=
+{@+state=skip_blanks;cur_chr=' ';
+}
+
+@ @<Finish line, |goto switch|@>=
+{@+loc=limit+1;goto get_cur_chr;
+}
+
+@ @<Finish line, emit a \.{\\par}@>=
+{@+loc=limit+1;cur_cs=par_loc;cur_cmd=eq_type(cur_cs);
+cur_chr=equiv(cur_cs);
+if (cur_cmd >= outer_call) check_outer_validity();
+}
+
+@ Notice that a code like \.{\^\^8} becomes \.x if not followed by a hex digit.
+
+ at d is_hex(A) (((A >= '0')&&(A <= '9'))||((A >= 'a')&&(A <= 'f')))
+ at d hex_to_cur_chr
+  if (c <= '9') cur_chr=c-'0';@+else cur_chr=c-'a'+10;
+  if (cc <= '9') cur_chr=16*cur_chr+cc-'0';
+  else cur_chr=16*cur_chr+cc-'a'+10
+
+@<If this |sup_mark| starts an expanded character...@>=
+{@+if (cur_chr==buffer[loc]) if (loc < limit)
+  {@+c=buffer[loc+1];@+if (c < 0200)  /*yes we have an expanded char*/
+    {@+loc=loc+2;
+    if (is_hex(c)) if (loc <= limit)
+      {@+cc=buffer[loc];@+if (is_hex(cc))
+        {@+incr(loc);hex_to_cur_chr;goto reswitch;
+        }
+      }
+    if (c < 0100) cur_chr=c+0100;@+else cur_chr=c-0100;
+    goto reswitch;
+    }
+  }
+state=mid_line;
+}
+
+@ @<Process an active-character...@>=
+{@+cur_cs=cur_chr+active_base;
+cur_cmd=eq_type(cur_cs);cur_chr=equiv(cur_cs);state=mid_line;
+if (cur_cmd >= outer_call) check_outer_validity();
+}
+
+@ Control sequence names are scanned only when they appear in some line of
+a file; once they have been scanned the first time, their |eqtb| location
+serves as a unique identification, so \TeX\ doesn't need to refer to the
+original name any more except when it prints the equivalent in symbolic form.
+
+The program that scans a control sequence has been written carefully
+in order to avoid the blowups that might otherwise occur if a malicious
+user tried something like `\.{\\catcode\'15=0}'. The algorithm might
+look at |buffer[limit+1]|, but it never looks at |buffer[limit+2]|.
+
+If expanded characters like `\.{\^\^A}' or `\.{\^\^df}'
+appear in or just following
+a control sequence name, they are converted to single characters in the
+buffer and the process is repeated, slowly but surely.
+
+@<Scan a control...@>=
+{@+if (loc > limit) cur_cs=null_cs; /*|state| is irrelevant in this case*/
+else{@+start_cs: k=loc;cur_chr=buffer[k];cat=cat_code(cur_chr);
+  incr(k);
+  if (cat==letter) state=skip_blanks;
+  else if (cat==spacer) state=skip_blanks;
+  else state=mid_line;
+  if ((cat==letter)&&(k <= limit))
+    @<Scan ahead in the buffer until finding a nonletter; if an expanded code is encountered,
+reduce it and |goto start_cs|; otherwise if a multiletter control sequence is found,
+adjust |cur_cs| and |loc|, and |goto found|@>@;
+  else@<If an expanded code is present, reduce it and |goto start_cs|@>;
+  cur_cs=single_base+buffer[loc];incr(loc);
+  }
+found: cur_cmd=eq_type(cur_cs);cur_chr=equiv(cur_cs);
+if (cur_cmd >= outer_call) check_outer_validity();
+}
+
+@ Whenever we reach the following piece of code, we will have
+|cur_chr==buffer[k-1]| and |k <= limit+1| and |cat==cat_code(cur_chr)|. If an
+expanded code like \.{\^\^A} or \.{\^\^df} appears in |buffer[(k-1)dotdot(k+1)]|
+or |buffer[(k-1)dotdot(k+2)]|, we
+will store the corresponding code in |buffer[k-1]| and shift the rest of
+the buffer left two or three places.
+
+@<If an expanded...@>=
+{@+if (buffer[k]==cur_chr) @+if (cat==sup_mark) @+if (k < limit)
+  {@+c=buffer[k+1];@+if (c < 0200)  /*yes, one is indeed present*/
+    {@+d=2;
+    if (is_hex(c)) @+if (k+2 <= limit)
+      {@+cc=buffer[k+2];@+if (is_hex(cc)) incr(d);
+      }
+    if (d > 2)
+      {@+hex_to_cur_chr;buffer[k-1]=cur_chr;
+      }
+    else if (c < 0100) buffer[k-1]=c+0100;
+    else buffer[k-1]=c-0100;
+    limit=limit-d;first=first-d;
+    while (k <= limit)
+      {@+buffer[k]=buffer[k+d];incr(k);
+      }
+    goto start_cs;
+    }
+  }
+}
+
+@ @<Scan ahead in the buffer...@>=
+{@+@/do at +{cur_chr=buffer[k];cat=cat_code(cur_chr);incr(k);
+}@+ while (!((cat!=letter)||(k > limit)));
+@<If an expanded...@>;
+if (cat!=letter) decr(k);
+   /*now |k| points to first nonletter*/
+if (k > loc+1)  /*multiletter control sequence has been scanned*/
+  {@+cur_cs=id_lookup(loc, k-loc);loc=k;goto found;
+  }
+}
+
+@ Let's consider now what happens when |get_next| is looking at a token list.
+
+@<Input from token list, |goto restart| if end of list or if a parameter needs to
+be expanded@>=
+if (loc!=null)  /*list not exhausted*/
+@^inner loop@>
+  {@+t=info(loc);loc=link(loc); /*move to next*/
+  if (t >= cs_token_flag)  /*a control sequence token*/
+    {@+cur_cs=t-cs_token_flag;
+    cur_cmd=eq_type(cur_cs);cur_chr=equiv(cur_cs);
+    if (cur_cmd >= outer_call)
+      if (cur_cmd==dont_expand)
+        @<Get the next token, suppressing expansion@>@;
+      else check_outer_validity();
+    }
+  else{@+cur_cmd=t/0400;cur_chr=t%0400;
+    switch (cur_cmd) {
+    case left_brace: incr(align_state);@+break;
+    case right_brace: decr(align_state);@+break;
+    case out_param: @<Insert macro parameter and |goto restart|@>@;
+    default:do_nothing;
+    }
+    }
+  }
+else{@+ /*we are done with this token list*/
+  end_token_list();goto restart; /*resume previous level*/
+  }
+
+@ The present point in the program is reached only when the |expand|
+routine has inserted a special marker into the input. In this special
+case, |info(loc)| is known to be a control sequence token, and |link(loc)==null|.
+
+ at d no_expand_flag 257 /*this characterizes a special variant of |relax|*/
+
+@<Get the next token, suppressing expansion@>=
+{@+cur_cs=info(loc)-cs_token_flag;loc=null;@/
+cur_cmd=eq_type(cur_cs);cur_chr=equiv(cur_cs);
+if (cur_cmd > max_command)
+  {@+cur_cmd=relax;cur_chr=no_expand_flag;
+  }
+}
+
+@ @<Insert macro parameter...@>=
+{@+begin_token_list(param_stack[param_start+cur_chr-1], parameter);
+goto restart;
+}
+
+@ All of the easy branches of |get_next| have now been taken care of.
+There is one more branch.
+
+ at d end_line_char_inactive (end_line_char < 0)||(end_line_char > 255)
+
+@<Move to next line of file, or |goto restart|...@>=
+if (name > 17) @<Read next line of file into |buffer|, or |goto restart| if the file
+has ended@>@;
+else{@+if (!terminal_input)  /*\.{\\read} line has ended*/
+    {@+cur_cmd=0;cur_chr=0;return;
+    }
+  if (input_ptr > 0)  /*text was inserted during error recovery*/
+    {@+end_file_reading();goto restart; /*resume previous level*/
+    }
+  if (selector < log_only) open_log_file();
+  if (interaction > nonstop_mode)
+    {@+if (end_line_char_inactive) incr(limit);
+    if (limit==start)  /*previous line was empty*/
+      print_nl("(Please type a command or say `\\end')");
+ at .Please type...@>
+    print_ln();first=start;
+    prompt_input("*"); /*input on-line into |buffer|*/
+ at .*\relax@>
+    limit=last;
+    if (end_line_char_inactive) decr(limit);
+    else buffer[limit]=end_line_char;
+    first=limit+1;
+    loc=start;
+    }
+  else fatal_error("*** (job aborted, no legal \\end found)");
+ at .job aborted@>
+     /*nonstop mode, which is intended for overnight batch processing,
+    never waits for on-line input*/
+  }
+
+@ The global variable |force_eof| is normally |false|; it is set |true|
+by an \.{\\endinput} command.
+
+@<Glob...@>=
+static bool @!force_eof; /*should the next \.{\\input} be aborted early?*/
+
+@ @<Read next line of file into |buffer|, or |goto restart| if the file has ended@>=
+{@+incr(line);first=start;
+if (!force_eof)
+  if (name <= 19)
+    {@+if (pseudo_input())  /*not end of file*/
+      firm_up_the_line(); /*this sets |limit|*/
+    else if ((every_eof!=null)&&!eof_seen[index])
+      {@+limit=first-1;eof_seen[index]=true; /*fake one empty line*/
+      begin_token_list(every_eof, every_eof_text);goto restart;
+      }
+    else force_eof=true;
+    }
+  else
+  {@+if (input_ln(&cur_file, true))  /*not end of file*/
+    firm_up_the_line(); /*this sets |limit|*/
+  else if ((every_eof!=null)&&!eof_seen[index])
+    {@+limit=first-1;eof_seen[index]=true; /*fake one empty line*/
+    begin_token_list(every_eof, every_eof_text);goto restart;
+    }
+  else force_eof=true;
+  }
+if (force_eof)
+  {@+if (tracing_nesting > 0)
+    if ((grp_stack[in_open]!=cur_boundary)||@|
+        (if_stack[in_open]!=cond_ptr)) file_warning();
+     /*give warning for some unfinished groups and/or conditionals*/
+  if (name >= 19)
+  {@+print_char(')');decr(open_parens);
+  update_terminal; /*show user that file has been read*/
+  }
+  force_eof=false;
+  end_file_reading(); /*resume previous level*/
+  check_outer_validity();goto restart;
+  }
+if (end_line_char_inactive) decr(limit);
+else buffer[limit]=end_line_char;
+first=limit+1;loc=start; /*ready to read*/
+}
+
+@ If the user has set the |pausing| parameter to some positive value,
+and if nonstop mode has not been selected, each line of input is displayed
+on the terminal and the transcript file, followed by `\.{=>}'.
+\TeX\ waits for a response. If the response is simply |carriage_return|, the
+line is accepted as it stands, otherwise the line typed is
+used instead of the line in the file.
+
+ at p static void firm_up_the_line(void)
+{@+int k; /*an index into |buffer|*/
+limit=last;
+if (pausing > 0) if (interaction > nonstop_mode)
+  {@+wake_up_terminal;print_ln();
+  if (start < limit) for (k=start; k<=limit-1; k++) printn(buffer[k]);
+  first=limit;prompt_input("=>"); /*wait for user response*/
+ at .=>@>
+  if (last > first)
+    {@+for (k=first; k<=last-1; k++)  /*move line down in buffer*/
+      buffer[k+start-first]=buffer[k];
+    limit=start+last-first;
+    }
+  }
+}
+
+@ Since |get_next| is used so frequently in \TeX, it is convenient
+to define three related procedures that do a little more:
+
+\yskip\hang|get_token| not only sets |cur_cmd| and |cur_chr|, it
+also sets |cur_tok|, a packed halfword version of the current token.
+
+\yskip\hang|get_x_token|, meaning ``get an expanded token,'' is like
+|get_token|, but if the current token turns out to be a user-defined
+control sequence (i.e., a macro call), or a conditional,
+or something like \.{\\topmark} or \.{\\expandafter} or \.{\\csname},
+it is eliminated from the input by beginning the expansion of the macro
+or the evaluation of the conditional.
+
+\yskip\hang|x_token| is like |get_x_token| except that it assumes that
+|get_next| has already been called.
+
+\yskip\noindent
+In fact, these three procedures account for almost every use of |get_next|.
+
+@ No new control sequences will be defined except during a call of
+|get_token|, or when \.{\\csname} compresses a token list, because
+|no_new_control_sequence| is always |true| at other times.
+
+ at p static void get_token(void) /*sets |cur_cmd|, |cur_chr|, |cur_tok|*/
+{@+no_new_control_sequence=false;get_next();no_new_control_sequence=true;
+@^inner loop@>
+if (cur_cs==0) cur_tok=(cur_cmd*0400)+cur_chr;
+else cur_tok=cs_token_flag+cur_cs;
+}
+
+@* Expanding the next token.
+Only a dozen or so command codes | > max_command| can possibly be returned by
+|get_next|; in increasing order, they are |undefined_cs|, |expand_after|,
+|no_expand|, |input|, |if_test|, |fi_or_else|, |cs_name|, |convert|, |the|,
+|top_bot_mark|, |call|, |long_call|, |outer_call|, |long_outer_call|, and
+|end_template|.{\emergencystretch=40pt\par}
+
+The |expand| subroutine is used when |cur_cmd > max_command|. It removes a
+``call'' or a conditional or one of the other special operations just
+listed.  It follows that |expand| might invoke itself recursively. In all
+cases, |expand| destroys the current token, but it sets things up so that
+the next |get_next| will deliver the appropriate next token. The value of
+|cur_tok| need not be known when |expand| is called.
+
+Since several of the basic scanning routines communicate via global variables,
+their values are saved as local variables of |expand| so that
+recursive calls don't invalidate them.
+@^recursion@>
+
+ at p @t\4@>@<Declare the procedure called |macro_call|@>@;@/
+ at t\4@>@<Declare the procedure called |insert_relax|@>@;@/
+ at t\4@>@<Declare \eTeX\ procedures for expanding@>@;@/
+ at t\4@>@<Declare \Prote\ procedures for expanding@>@;@/
+static void pass_text(void);
+static void start_input(void);
+static void conditional(void);
+static void get_x_token(void);
+static void conv_toks(void);
+static void ins_the_toks(void);
+static void expand(void)
+{@+
+halfword t; /*token that is being ``expanded after''*/
+pointer @!p, @!q, @!r; /*for list manipulation*/
+int @!j; /*index into |buffer|*/
+int @!cv_backup; /*to save the global quantity |cur_val|*/
+small_number @!cvl_backup, @!radix_backup, @!co_backup;
+   /*to save |cur_val_level|, etc.*/
+pointer @!backup_backup; /*to save |link(backup_head)|*/
+small_number @!save_scanner_status; /*temporary storage of |scanner_status|*/
+cv_backup=cur_val;cvl_backup=cur_val_level;radix_backup=radix;
+co_backup=cur_order;backup_backup=link(backup_head);
+reswitch:
+if (cur_cmd < call) @<Expand a nonmacro@>@;
+else if (cur_cmd < end_template) macro_call();
+else@<Insert a token containing |frozen_endv|@>;
+cur_val=cv_backup;cur_val_level=cvl_backup;radix=radix_backup;
+cur_order=co_backup;link(backup_head)=backup_backup;
+}
+
+@ @<Expand a nonmacro@>=
+{@+if (tracing_commands > 1) show_cur_cmd_chr();
+switch (cur_cmd) {
+case top_bot_mark: @<Insert the \(a)appropriate mark text into the scanner@>@;@+break;
+case expand_after: switch (cur_chr) {
+case 0: @<Expand the token after the next token@>@;@+break;
+case 1: @<Negate a boolean conditional and |goto reswitch|@>@;@+break;
+@/@<Cases for |expandafter|@>@/
+} @+break; /*there are no other cases*/
+case no_expand: @<Suppress expansion of the next token@>@;@+break;
+case cs_name: @<Manufacture a control sequence name@>@;@+break;
+case convert: conv_toks();@+break; /*this procedure is discussed in Part 27 below*/
+case the: ins_the_toks();@+break; /*this procedure is discussed in Part 27 below*/
+case if_test: conditional();@+break; /*this procedure is discussed in Part 28 below*/
+case fi_or_else: @<Terminate the current conditional and skip to \.{\\fi}@>@;@+break;
+case input: @<Initiate or terminate input from a file@>;@+break;
+default:@<Complain about an undefined macro@>@;
+}
+}
+
+@ It takes only a little shuffling to do what \TeX\ calls \.{\\expandafter}.
+
+@<Expand the token after...@>=
+{@+get_token();t=cur_tok;get_token();
+if (cur_cmd > max_command) expand();@+else back_input();
+cur_tok=t;back_input();
+}
+
+@ The implementation of \.{\\noexpand} is a bit trickier, because it is
+necessary to insert a special `|dont_expand|' marker into \TeX's reading
+mechanism.  This special marker is processed by |get_next|, but it does
+not slow down the inner loop.
+
+Since \.{\\outer} macros might arise here, we must also
+clear the |scanner_status| temporarily.
+
+@<Suppress expansion...@>=
+{@+save_scanner_status=scanner_status;scanner_status=normal;
+get_token();scanner_status=save_scanner_status;t=cur_tok;
+back_input(); /*now |start| and |loc| point to the backed-up token |t|*/
+if (t >= cs_token_flag)
+  {@+p=get_avail();info(p)=cs_token_flag+frozen_dont_expand;
+  link(p)=loc;start=p;loc=p;
+  }
+}
+
+@ @<Complain about an undefined macro@>=
+{@+print_err("Undefined control sequence");
+ at .Undefined control sequence@>
+help5("The control sequence at the end of the top line",@/
+"of your error message was never \\def'ed. If you have",@/
+"misspelled it (e.g., `\\hobx'), type `I' and the correct",@/
+"spelling (e.g., `I\\hbox'). Otherwise just continue,",@/
+"and I'll forget about whatever was undefined.");
+error();
+}
+
+@ The |expand| procedure and some other routines that construct token
+lists find it convenient to use the following macros, which are valid only if
+the variables |p| and |q| are reserved for token-list building.
+
+ at d store_new_token(A) {@+q=get_avail();link(p)=q;info(q)=A;
+  p=q; /*|link(p)| is |null|*/
+  }
+ at d fast_store_new_token(A) {@+fast_get_avail(q);link(p)=q;info(q)=A;
+  p=q; /*|link(p)| is |null|*/
+  }
+
+@ @<Manufacture a control...@>=
+{@+r=get_avail();p=r; /*head of the list of characters*/
+incr(incsname_state);
+@/do at +{get_x_token();
+if (cur_cs==0) store_new_token(cur_tok);
+}@+ while (!(cur_cs!=0));
+if (cur_cmd!=end_cs_name) @<Complain about missing \.{\\endcsname}@>;
+decr(incsname_state);
+@<Look up the characters of list |r| in the hash table, and set |cur_cs|@>;
+flush_list(r);
+if (eq_type(cur_cs)==undefined_cs)
+  {@+eq_define(cur_cs, relax, 256); /*N.B.: The |save_stack| might change*/
+  }  /*the control sequence will now match `\.{\\relax}'*/
+cur_tok=cur_cs+cs_token_flag;back_input();
+}
+
+@ @<Complain about missing \.{\\endcsname}@>=
+{@+print_err("Missing ");print_esc("endcsname");print(" inserted");
+ at .Missing \\endcsname...@>
+help2("The control sequence marked <to be read again> should",@/
+  "not appear between \\csname and \\endcsname.");
+back_error();
+}
+
+@ @<Look up the characters of list |r| in the hash table...@>=
+j=first;p=link(r);
+while (p!=null)
+  {@+if (j >= max_buf_stack)
+    {@+max_buf_stack=j+1;
+    if (max_buf_stack==buf_size)
+      overflow("buffer size", buf_size);
+@:TeX capacity exceeded buffer size}{\quad buffer size@>
+    }
+  buffer[j]=info(p)%0400;incr(j);p=link(p);
+  }
+if (j==first) cur_cs=null_cs; /*the list is empty*/
+else if (j > first+1)
+  {@+no_new_control_sequence=false;cur_cs=id_lookup(first, j-first);
+  no_new_control_sequence=true;
+  }
+else cur_cs=single_base+buffer[first] /*the list has length one*/
+
+@ An |end_template| command is effectively changed to an |endv| command
+by the following code. (The reason for this is discussed below; the
+|frozen_end_template| at the end of the template has passed the
+|check_outer_validity| test, so its mission of error detection has been
+accomplished.)
+
+@<Insert a token containing |frozen_endv|@>=
+{@+cur_tok=cs_token_flag+frozen_endv;back_input();
+}
+
+@ The processing of \.{\\input} involves the |start_input| subroutine,
+which will be declared later; the processing of \.{\\endinput} is trivial.
+
+@<Put each...@>=
+primitive("input", input, 0);@/
+@!@:input\_}{\.{\\input} primitive@>
+primitive("endinput", input, 1);@/
+@!@:end\_input\_}{\.{\\endinput} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case input: if (chr_code==0) print_esc("input")
+  @/@<Cases of |input| for |print_cmd_chr|@>;@/
+  else print_esc("endinput");@+break;
+
+@ @<Initiate or terminate input...@>=
+if (cur_chr==1) force_eof=true
+@/@<Cases for |input|@>;@/
+else if (name_in_progress) insert_relax();
+else start_input()
+
+@ Sometimes the expansion looks too far ahead, so we want to insert
+a harmless \.{\\relax} into the user's input.
+
+@<Declare the procedure called |insert_relax|@>=
+static void insert_relax(void)
+{@+cur_tok=cs_token_flag+cur_cs;back_input();
+cur_tok=cs_token_flag+frozen_relax;back_input();token_type=inserted;
+}
+
+@ Here is a recursive procedure that is \TeX's usual way to get the
+next token of input. It has been slightly optimized to take account of
+common cases.
+
+ at p static void get_x_token(void) /*sets |cur_cmd|, |cur_chr|, |cur_tok|,
+  and expands macros*/
+{@+
+restart: get_next();
+@^inner loop@>
+if (cur_cmd <= max_command) goto done;
+if (cur_cmd >= call)
+  if (cur_cmd < end_template) macro_call();
+  else{@+cur_cs=frozen_endv;cur_cmd=endv;
+    goto done; /*|cur_chr==null_list|*/
+    }
+else expand();
+goto restart;
+done: if (cur_cs==0) cur_tok=(cur_cmd*0400)+cur_chr;
+else cur_tok=cs_token_flag+cur_cs;
+}
+
+@ The |get_x_token| procedure is essentially equivalent to two consecutive
+procedure calls: |get_next;x_token|.
+
+ at p static void x_token(void) /*|get_x_token| without the initial |get_next|*/
+{@+while (cur_cmd > max_command)
+  {@+expand();
+  get_next();
+  }
+if (cur_cs==0) cur_tok=(cur_cmd*0400)+cur_chr;
+else cur_tok=cs_token_flag+cur_cs;
+}
+
+@ A control sequence that has been \.{\\def}'ed by the user is expanded by
+\TeX's |macro_call| procedure.
+
+Before we get into the details of |macro_call|, however, let's consider the
+treatment of primitives like \.{\\topmark}, since they are essentially
+macros without parameters. The token lists for such marks are kept in a
+global array of five pointers; we refer to the individual entries of this
+array by symbolic names |top_mark|, etc. The value of |top_mark| is either
+|null| or a pointer to the reference count of a token list.
+
+ at d top_mark_code 0 /*the mark in effect at the previous page break*/
+ at d first_mark_code 1 /*the first mark between |top_mark| and |bot_mark|*/
+ at d bot_mark_code 2 /*the mark in effect at the current page break*/
+ at d split_first_mark_code 3 /*the first mark found by \.{\\vsplit}*/
+ at d split_bot_mark_code 4 /*the last mark found by \.{\\vsplit}*/
+ at d top_mark cur_mark[top_mark_code]
+ at d first_mark cur_mark[first_mark_code]
+ at d bot_mark cur_mark[bot_mark_code]
+ at d split_first_mark cur_mark[split_first_mark_code]
+ at d split_bot_mark cur_mark[split_bot_mark_code]
+
+@<Glob...@>=
+static pointer @!cur_mark0[split_bot_mark_code-top_mark_code+1], *const @!cur_mark = @!cur_mark0-top_mark_code;
+   /*token lists for marks*/
+
+@ @<Set init...@>=
+top_mark=null;first_mark=null;bot_mark=null;
+split_first_mark=null;split_bot_mark=null;
+
+@ @<Put each...@>=
+primitive("topmark", top_bot_mark, top_mark_code);
+@!@:top\_mark\_}{\.{\\topmark} primitive@>
+primitive("firstmark", top_bot_mark, first_mark_code);
+@!@:first\_mark\_}{\.{\\firstmark} primitive@>
+primitive("botmark", top_bot_mark, bot_mark_code);
+@!@:bot\_mark\_}{\.{\\botmark} primitive@>
+primitive("splitfirstmark", top_bot_mark, split_first_mark_code);
+@!@:split\_first\_mark\_}{\.{\\splitfirstmark} primitive@>
+primitive("splitbotmark", top_bot_mark, split_bot_mark_code);
+@!@:split\_bot\_mark\_}{\.{\\splitbotmark} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case top_bot_mark: switch (chr_code) {
+  case first_mark_code: print_esc("firstmark");@+break;
+  case bot_mark_code: print_esc("botmark");@+break;
+  case split_first_mark_code: print_esc("splitfirstmark");@+break;
+  case split_bot_mark_code: print_esc("splitbotmark");@+break;
+  default:print_esc("topmark");
+  } @+break;
+
+@ The following code is activated when |cur_cmd==top_bot_mark| and
+when |cur_chr| is a code like |top_mark_code|.
+
+@<Insert the \(a)appropriate mark text into the scanner@>=
+{@+if (cur_mark[cur_chr]!=null)
+  begin_token_list(cur_mark[cur_chr], mark_text);
+}
+
+@ Now let's consider |macro_call| itself, which is invoked when \TeX\ is
+scanning a control sequence whose |cur_cmd| is either |call|, |long_call|,
+|outer_call|, or |long_outer_call|.  The control sequence definition
+appears in the token list whose reference count is in location |cur_chr|
+of |mem|.
+
+The global variable |long_state| will be set to |call| or to |long_call|,
+depending on whether or not the control sequence disallows \.{\\par}
+in its parameters. The |get_next| routine will set |long_state| to
+|outer_call| and emit \.{\\par}, if a file ends or if an \.{\\outer}
+control sequence occurs in the midst of an argument.
+
+@<Glob...@>=
+static int @!long_state; /*governs the acceptance of \.{\\par}*/
+
+@ The parameters, if any, must be scanned before the macro is expanded.
+Parameters are token lists without reference counts. They are placed on
+an auxiliary stack called |pstack| while they are being scanned, since
+the |param_stack| may be losing entries during the matching process.
+(Note that |param_stack| can't be gaining entries, since |macro_call| is
+the only routine that puts anything onto |param_stack|, and it
+is not recursive.)
+
+@<Glob...@>=
+static pointer @!pstack[9]; /*arguments supplied to a macro*/
+
+@ After parameter scanning is complete, the parameters are moved to the
+|param_stack|. Then the macro body is fed to the scanner; in other words,
+|macro_call| places the defined text of the control sequence at the
+top of\/ \TeX's input stack, so that |get_next| will proceed to read it
+next.
+
+The global variable |cur_cs| contains the |eqtb| address of the control sequence
+being expanded, when |macro_call| begins. If this control sequence has not been
+declared \.{\\long}, i.e., if its command code in the |eq_type| field is
+not |long_call| or |long_outer_call|, its parameters are not allowed to contain
+the control sequence \.{\\par}. If an illegal \.{\\par} appears, the macro
+call is aborted, and the \.{\\par} will be rescanned.
+
+@<Declare the procedure called |macro_call|@>=
+static void macro_call(void) /*invokes a user-defined control sequence*/
+{@+
+pointer r; /*current node in the macro's token list*/
+pointer @!p; /*current node in parameter token list being built*/
+pointer @!q; /*new node being put into the token list*/
+pointer @!s; /*backup pointer for parameter matching*/
+pointer @!t; /*cycle pointer for backup recovery*/
+pointer @!u, @!v; /*auxiliary pointers for backup recovery*/
+pointer @!rbrace_ptr; /*one step before the last |right_brace| token*/
+small_number @!n; /*the number of parameters scanned*/
+halfword @!unbalance; /*unmatched left braces in current parameter*/
+int @!m; /*the number of tokens or groups (usually)*/
+pointer @!ref_count; /*start of the token list*/
+small_number @!save_scanner_status; /*|scanner_status| upon entry*/
+pointer @!save_warning_index; /*|warning_index| upon entry*/
+ASCII_code @!match_chr; /*character used in parameter*/
+save_scanner_status=scanner_status;save_warning_index=warning_index;
+warning_index=cur_cs;ref_count=cur_chr;r=link(ref_count);n=0;
+if (tracing_macros > 0) @<Show the text of the macro being expanded@>;
+if (info(r)==protected_token) r=link(r);
+if (info(r)!=end_match_token)
+  @<Scan the parameters and make |link(r)| point to the macro body; but |return| if
+an illegal \.{\\par} is detected@>;
+@<Feed the macro body and its parameters to the scanner@>;
+end: scanner_status=save_scanner_status;warning_index=save_warning_index;
+}
+
+@ Before we put a new token list on the input stack, it is wise to clean off
+all token lists that have recently been depleted. Then a user macro that ends
+with a call to itself will not require unbounded stack space.
+
+@<Feed the macro body and its parameters to the scanner@>=
+while ((state==token_list)&&(loc==null)&&(token_type!=v_template))
+  end_token_list(); /*conserve stack space*/
+begin_token_list(ref_count, macro);name=warning_index;loc=link(r);
+if (n > 0)
+  {@+if (param_ptr+n > max_param_stack)
+    {@+max_param_stack=param_ptr+n;
+    if (max_param_stack > param_size)
+      overflow("parameter stack size", param_size);
+@:TeX capacity exceeded parameter stack size}{\quad parameter stack size@>
+    }
+  for (m=0; m<=n-1; m++) param_stack[param_ptr+m]=pstack[m];
+  param_ptr=param_ptr+n;
+  }
+
+@ At this point, the reader will find it advisable to review the explanation
+of token list format that was presented earlier, since many aspects of that
+format are of importance chiefly in the |macro_call| routine.
+
+The token list might begin with a string of compulsory tokens before the
+first |match| or |end_match|. In that case the macro name is supposed to be
+followed by those tokens; the following program will set |s==null| to
+represent this restriction. Otherwise |s| will be set to the first token of
+a string that will delimit the next parameter.
+
+@<Scan the parameters and make |link(r)| point to the macro body...@>=
+{@+scanner_status=matching;unbalance=0;
+long_state=eq_type(cur_cs);
+if (long_state >= outer_call) long_state=long_state-2;
+@/do at +{link(temp_head)=null;
+if ((info(r) > match_token+255)||(info(r) < match_token)) s=null;
+else{@+match_chr=info(r)-match_token;s=link(r);r=s;
+  p=temp_head;m=0;
+  }
+@<Scan a parameter until its delimiter string has been found; or, if |s=null|, simply
+scan the delimiter string@>;@/
+ /*now |info(r)| is a token whose command code is either |match| or |end_match|*/
+}@+ while (!(info(r)==end_match_token));
+}
+
+@ If |info(r)| is a |match| or |end_match| command, it cannot be equal to
+any token found by |get_token|. Therefore an undelimited parameter---i.e.,
+a |match| that is immediately followed by |match| or |end_match|---will
+always fail the test `|cur_tok==info(r)|' in the following algorithm.
+
+@<Scan a parameter until its delimiter string has been found; or,...@>=
+resume: get_token(); /*set |cur_tok| to the next token of input*/
+if (cur_tok==info(r))
+  @<Advance \(r)|r|; |goto found| if the parameter delimiter has been fully matched,
+otherwise |goto continue|@>;
+@<Contribute the recently matched tokens to the current parameter, and |goto continue|
+if a partial match is still in effect; but abort if |s=null|@>;
+if (cur_tok==par_token) if (long_state!=long_call)
+  @<Report a runaway argument and abort@>;
+if (cur_tok < right_brace_limit)
+  if (cur_tok < left_brace_limit)
+    @<Contribute an entire group to the current parameter@>@;
+  else@<Report an extra right brace and |goto continue|@>@;
+else@<Store the current token, but |goto continue| if it is a blank space that would
+become an undelimited parameter@>;
+incr(m);
+if (info(r) > end_match_token) goto resume;
+if (info(r) < match_token) goto resume;
+found: if (s!=null) @<Tidy up the parameter just scanned, and tuck it away@>@;
+
+@ @<Store the current token, but |goto continue| if it is...@>=
+{@+if (cur_tok==space_token)
+  if (info(r) <= end_match_token)
+    if (info(r) >= match_token) goto resume;
+store_new_token(cur_tok);
+}
+
+@ A slightly subtle point arises here: When the parameter delimiter ends
+with `\.{\#\{}', the token list will have a left brace both before and
+after the |end_match|\kern-.4pt. Only one of these should affect the
+|align_state|, but both will be scanned, so we must make a correction.
+
+@<Advance \(r)|r|; |goto found| if the parameter delimiter has been fully...@>=
+{@+r=link(r);
+if ((info(r) >= match_token)&&(info(r) <= end_match_token))
+  {@+if (cur_tok < left_brace_limit) decr(align_state);
+  goto found;
+  }
+else goto resume;
+}
+
+@ @<Report an extra right brace and |goto continue|@>=
+{@+back_input();print_err("Argument of ");sprint_cs(warning_index);
+ at .Argument of \\x has...@>
+print(" has an extra }");
+help6("I've run across a `}' that doesn't seem to match anything.",@/
+  "For example, `\\def\\a#1{...}' and `\\a}' would produce",@/
+  "this error. If you simply proceed now, the `\\par' that",@/
+  "I've just inserted will cause me to report a runaway",@/
+  "argument that might be the root of the problem. But if",@/
+  "your `}' was spurious, just type `2' and it will go away.");
+incr(align_state);long_state=call;cur_tok=par_token;ins_error();
+goto resume;
+}  /*a white lie; the \.{\\par} won't always trigger a runaway*/
+
+@ If |long_state==outer_call|, a runaway argument has already been reported.
+
+@<Report a runaway argument and abort@>=
+{@+if (long_state==call)
+  {@+runaway();print_err("Paragraph ended before ");
+ at .Paragraph ended before...@>
+  sprint_cs(warning_index);print(" was complete");
+  help3("I suspect you've forgotten a `}', causing me to apply this",@/
+    "control sequence to too much text. How can we recover?",@/
+    "My plan is to forget the whole thing and hope for the best.");
+  back_error();
+  }
+pstack[n]=link(temp_head);align_state=align_state-unbalance;
+for (m=0; m<=n; m++) flush_list(pstack[m]);
+goto end;
+}
+
+@ When the following code becomes active, we have matched tokens from |s| to
+the predecessor of |r|, and we have found that |cur_tok!=info(r)|. An
+interesting situation now presents itself: If the parameter is to be
+delimited by a string such as `\.{ab}', and if we have scanned `\.{aa}',
+we want to contribute one `\.a' to the current parameter and resume
+looking for a `\.b'. The program must account for such partial matches and
+for others that can be quite complex.  But most of the time we have |s==r|
+and nothing needs to be done.
+
+Incidentally, it is possible for \.{\\par} tokens to sneak in to certain
+parameters of non-\.{\\long} macros. For example, consider a case like
+`\.{\\def\\a\#1\\par!\{...\}}' where the first \.{\\par} is not followed
+by an exclamation point. In such situations it does not seem appropriate
+to prohibit the \.{\\par}, so \TeX\ keeps quiet about this bending of
+the rules.
+
+@<Contribute the recently matched tokens to the current parameter...@>=
+if (s!=r)
+  if (s==null) @<Report an improper use of the macro and abort@>@;
+  else{@+t=s;
+    @/do at +{store_new_token(info(t));incr(m);u=link(t);v=s;
+    loop at +{@+if (u==r)
+        if (cur_tok!=info(v)) goto done;
+        else{@+r=link(v);goto resume;
+          }
+      if (info(u)!=info(v)) goto done;
+      u=link(u);v=link(v);
+      }
+    done: t=link(t);
+    }@+ while (!(t==r));
+    r=s; /*at this point, no tokens are recently matched*/
+    }
+
+@ @<Report an improper use...@>=
+{@+print_err("Use of ");sprint_cs(warning_index);
+ at .Use of x doesn't match...@>
+print(" doesn't match its definition");
+help4("If you say, e.g., `\\def\\a1{...}', then you must always",@/
+  "put `1' after `\\a', since control sequence names are",@/
+  "made up of letters only. The macro here has not been",@/
+  "followed by the required stuff, so I'm ignoring it.");
+error();goto end;
+}
+
+@ @<Contribute an entire group to the current parameter@>=
+{@+unbalance=1;
+@^inner loop@>
+loop at +{@+fast_store_new_token(cur_tok);get_token();
+  if (cur_tok==par_token) if (long_state!=long_call)
+    @<Report a runaway argument and abort@>;
+  if (cur_tok < right_brace_limit)
+    if (cur_tok < left_brace_limit) incr(unbalance);
+    else{@+decr(unbalance);
+      if (unbalance==0) goto done1;
+      }
+  }
+done1: rbrace_ptr=p;store_new_token(cur_tok);
+}
+
+@ If the parameter consists of a single group enclosed in braces, we must
+strip off the enclosing braces. That's why |rbrace_ptr| was introduced.
+
+@<Tidy up the parameter just scanned, and tuck it away@>=
+{@+if ((m==1)&&(info(p) < right_brace_limit))
+  {@+link(rbrace_ptr)=null;free_avail(p);
+  p=link(temp_head);pstack[n]=link(p);free_avail(p);
+  }
+else pstack[n]=link(temp_head);
+incr(n);
+if (tracing_macros > 0)
+  {@+begin_diagnostic();print_nl("");printn(match_chr);print_int(n);
+  print("<-");show_token_list(pstack[n-1], null, 1000);
+  end_diagnostic(false);
+  }
+}
+
+@ @<Show the text of the macro being expanded@>=
+{@+begin_diagnostic();print_ln();print_cs(warning_index);
+token_show(ref_count);end_diagnostic(false);
+}
+
+@* Basic scanning subroutines.
+Let's turn now to some procedures that \TeX\ calls upon frequently to digest
+certain kinds of patterns in the input. Most of these are quite simple;
+some are quite elaborate. Almost all of the routines call |get_x_token|,
+which can cause them to be invoked recursively.
+@^stomach@>
+@^recursion@>
+
+@ The |scan_left_brace| routine is called when a left brace is supposed to be
+the next non-blank token. (The term ``left brace'' means, more precisely,
+a character whose catcode is |left_brace|.) \TeX\ allows \.{\\relax} to
+appear before the |left_brace|.
+
+ at p static void scan_left_brace(void) /*reads a mandatory |left_brace|*/
+{@+@<Get the next non-blank non-relax non-call token@>;
+if (cur_cmd!=left_brace)
+  {@+print_err("Missing { inserted");
+ at .Missing \{ inserted@>
+  help4("A left brace was mandatory here, so I've put one in.",@/
+    "You might want to delete and/or insert some corrections",@/
+    "so that I will find a matching right brace soon.",@/
+    "(If you're confused by all this, try typing `I}' now.)");
+  back_error();cur_tok=left_brace_token+'{';cur_cmd=left_brace;
+  cur_chr='{';incr(align_state);
+  }
+}
+
+@ @<Get the next non-blank non-relax non-call token@>=
+@/do at +{get_x_token();
+}@+ while (!((cur_cmd!=spacer)&&(cur_cmd!=relax)))
+
+@ The |scan_optional_equals| routine looks for an optional `\.=' sign preceded
+by optional spaces; `\.{\\relax}' is not ignored here.
+
+ at p static void scan_optional_equals(void)
+{@+@<Get the next non-blank non-call token@>;
+if (cur_tok!=other_token+'=') back_input();
+}
+
+@ @<Get the next non-blank non-call token@>=
+@/do at +{get_x_token();
+}@+ while (!(cur_cmd!=spacer))
+
+@ In case you are getting bored, here is a slightly less trivial routine:
+Given a string of lowercase letters, like `\.{pt}' or `\.{plus}' or
+`\.{width}', the |scan_keyword| routine checks to see whether the next
+tokens of input match this string. The match must be exact, except that
+uppercase letters will match their lowercase counterparts; uppercase
+equivalents are determined by subtracting |'a'-'A'|, rather than using the
+|uc_code| table, since \TeX\ uses this routine only for its own limited
+set of keywords.
+
+If a match is found, the characters are effectively removed from the input
+and |true| is returned. Otherwise |false| is returned, and the input
+is left essentially unchanged (except for the fact that some macros
+may have been expanded, etc.).
+@^inner loop@>
+
+ at p static bool scan_keyword(char *@!s) /*look for a given string*/
+{@+
+pointer p; /*tail of the backup list*/
+pointer @!q; /*new node being added to the token list via |store_new_token|*/
+p=backup_head;link(p)=null;
+while (*s!=0)
+  {@+get_x_token(); /*recursion is possible here*/
+@^recursion@>
+  if ((cur_cs==0)&&@|
+   ((cur_chr==so(*s))||(cur_chr==so(*s)-'a'+'A')))
+    {@+store_new_token(cur_tok);incr(s);
+    }
+  else if ((cur_cmd!=spacer)||(p!=backup_head))
+    {@+back_input();
+    if (p!=backup_head) back_list(link(backup_head));
+    return false;
+    }
+  }
+flush_list(link(backup_head));return true;
+}
+
+@ Here is a procedure that sounds an alarm when mu and non-mu units
+are being switched.
+
+ at p static void mu_error(void)
+{@+print_err("Incompatible glue units");
+ at .Incompatible glue units@>
+help1("I'm going to assume that 1mu=1pt when they're mixed.");
+error();
+}
+
+@ The next routine `|scan_something_internal|' is used to fetch internal
+numeric quantities like `\.{\\hsize}', and also to handle the `\.{\\the}'
+when expanding constructions like `\.{\\the\\toks0}' and
+`\.{\\the\\baselineskip}'. Soon we will be considering the |scan_int|
+procedure, which calls |scan_something_internal|; on the other hand,
+|scan_something_internal| also calls |scan_int|, for constructions like
+`\.{\\catcode\`\\\$}' or `\.{\\fontdimen} \.3 \.{\\ff}'. So we
+have to declare |scan_int| as a |forward| procedure. A few other
+procedures are also declared at this point.
+
+ at p static void scan_int(void); /*scans an integer value*/
+ at t\4\4@>@<Declare procedures that scan restricted classes of integers@>@;
+ at t\4\4@>@<Declare \eTeX\ procedures for scanning@>@;
+ at t\4\4@>@<Declare \Prote\ procedures for scanning@>@;
+ at t\4\4@>@<Declare procedures that scan font-related stuff@>@;
+
+@ \TeX\ doesn't know exactly what to expect when |scan_something_internal|
+begins.  For example, an integer or dimension or glue value could occur
+immediately after `\.{\\hskip}'; and one can even say \.{\\the} with
+respect to token lists in constructions like
+`\.{\\xdef\\o\{\\the\\output\}}'.  On the other hand, only integers are
+allowed after a construction like `\.{\\count}'. To handle the various
+possibilities, |scan_something_internal| has a |level| parameter, which
+tells the ``highest'' kind of quantity that |scan_something_internal| is
+allowed to produce. Six levels are distinguished, namely |int_val|,
+|dimen_val|, |glue_val|, |mu_val|, |ident_val|, and |tok_val|.
+
+The output of |scan_something_internal| (and of the other routines
+|scan_int|, |scan_dimen|, and |scan_glue| below) is put into the global
+variable |cur_val|, and its level is put into |cur_val_level|. The highest
+values of |cur_val_level| are special: |mu_val| is used only when
+|cur_val| points to something in a ``muskip'' register, or to one of the
+three parameters \.{\\thinmuskip}, \.{\\medmuskip}, \.{\\thickmuskip};
+|ident_val| is used only when |cur_val| points to a font identifier;
+|tok_val| is used only when |cur_val| points to |null| or to the reference
+count of a token list. The last two cases are allowed only when
+|scan_something_internal| is called with |level==tok_val|.
+
+If the output is glue, |cur_val| will point to a glue specification, and
+the reference count of that glue will have been updated to reflect this
+reference; if the output is a nonempty token list, |cur_val| will point to
+its reference count, but in this case the count will not have been updated.
+Otherwise |cur_val| will contain the integer or scaled value in question.
+
+ at d int_val 0 /*integer values*/
+ at d dimen_val 1 /*dimension values*/
+ at d glue_val 2 /*glue specifications*/
+ at d mu_val 3 /*math glue specifications*/
+ at d ident_val 4 /*font identifier*/
+ at d tok_val 5 /*token lists*/
+ at d has_factor (cur_hfactor!=0 || cur_vfactor!=0)
+
+@<Glob...@>=
+static int @!cur_val, @!cur_hfactor, @!cur_vfactor; /*value returned by numeric scanners*/
+static int @!cur_val_level; /*the ``level'' of this value*/
+
+@ The hash table is initialized with `\.{\\count}', `\.{\\dimen}', `\.{\\skip}',
+and `\.{\\muskip}' all having |internal_register| as their command code; they are
+distinguished by the |chr_code|, which is either |int_val|, |dimen_val|,
+|glue_val|, or |mu_val| more than |mem_bot| (dynamic variable-size nodes
+cannot have these values)
+
+@<Put each...@>=
+primitive("count", internal_register, mem_bot+int_val);
+@!@:count\_}{\.{\\count} primitive@>
+primitive("dimen", internal_register, mem_bot+dimen_val);
+@!@:dimen\_}{\.{\\dimen} primitive@>
+primitive("skip", internal_register, mem_bot+glue_val);
+@!@:skip\_}{\.{\\skip} primitive@>
+primitive("muskip", internal_register, mem_bot+mu_val);
+@!@:mu\_skip\_}{\.{\\muskip} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case internal_register: @<Cases of |register| for |print_cmd_chr|@>@;@+break;
+
+@ OK, we're ready for |scan_something_internal| itself. A second parameter,
+|negative|, is set |true| if the value that is found should be negated.
+It is assumed that |cur_cmd| and |cur_chr| represent the first token of
+the internal quantity to be scanned; an error will be signalled if
+|cur_cmd < min_internal| or |cur_cmd > max_internal|.
+
+ at d scanned_result(A, B) @+{@+cur_val=A;cur_val_level=B;@+}
+
+ at p static void scan_something_internal(small_number @!level, bool @!negative)
+   /*fetch an internal parameter*/
+{@+
+halfword m; /*|chr_code| part of the operand token*/
+pointer @!q, @!r; /*general purpose indices*/
+pointer @!tx; /*effective tail node*/
+four_quarters @!i; /*character info*/
+int @!p; /*index into |nest|*/
+m=cur_chr;
+switch (cur_cmd) {
+case def_code: @<Fetch a character code from some table@>@;@+break;
+case toks_register: case assign_toks: case def_family: case set_font: case def_font: @<Fetch
+a token list or font identifier, provided that |level=tok_val|@>@;@+break;
+case assign_int: scanned_result(eqtb[m].i, int_val)@;@+break;
+case assign_dimen:
+  scanned_result(eqtb[m].sc, dimen_val);
+  if (m>=dimen_base)@/
+  { cur_hfactor=hfactor_eqtb[m].sc;@+
+    cur_vfactor=vfactor_eqtb[m].sc;@+
+  }
+  else
+    cur_hfactor=cur_vfactor=0;@/
+  @+break;
+case assign_glue: scanned_result(equiv(m), glue_val)@;@+break;
+case assign_mu_glue: scanned_result(equiv(m), mu_val)@;@+break;
+case set_aux: @<Fetch the |space_factor| or the |prev_depth|@>@;@+break;
+case set_prev_graf: @<Fetch the |prev_graf|@>@;@+break;
+case set_page_int: @<Fetch the |dead_cycles| or the |insert_penalties|@>@;@+break;
+case set_page_dimen: @<Fetch something on the |page_so_far|@>@;@+break;
+case set_shape: @<Fetch the |par_shape| size@>@;@+break;
+case set_box_dimen: @<Fetch a box dimension@>@;@+break;
+case char_given: case math_given: scanned_result(cur_chr, int_val)@;@+break;
+case assign_font_dimen: @<Fetch a font dimension@>@;@+break;
+case assign_font_int: @<Fetch a font integer@>@;@+break;
+case internal_register: @<Fetch a register@>@;@+break;
+case last_item: @<Fetch an item in the current node, if appropriate@>@;@+break;
+default:@<Complain that \.{\\the} can't do this; give zero result@>@;
+} @/
+while (cur_val_level > level) @<Convert \(c)|cur_val| to a lower level@>;
+@<Fix the reference count, if any, and negate |cur_val| if |negative|@>;
+}
+
+@ @<Fetch a character code from some table@>=
+{@+scan_char_num();
+if (m==math_code_base) scanned_result(ho(math_code(cur_val)), int_val)@;
+else if (m < math_code_base) scanned_result(equiv(m+cur_val), int_val)@;
+else scanned_result(eqtb[m+cur_val].i, int_val);
+}
+
+@ @<Fetch a token list...@>=
+if (level!=tok_val)
+  {@+print_err("Missing number, treated as zero");
+ at .Missing number...@>
+  help3("A number should have been here; I inserted `0'.",@/
+    "(If you can't figure out why I needed to see a number,",@/
+    "look up `weird error' in the index to The TeXbook.)");
+@:TeXbook}{\sl The \TeX book@>
+  back_error();scanned_result(0, dimen_val);
+  }
+else if (cur_cmd <= assign_toks)
+  {@+if (cur_cmd < assign_toks)  /*|cur_cmd==toks_register|*/
+    if (m==mem_bot)
+      {@+scan_register_num();
+      if (cur_val < 256) cur_val=equiv(toks_base+cur_val);
+      else{@+find_sa_element(tok_val, cur_val, false);
+        if (cur_ptr==null) cur_val=null;
+        else cur_val=sa_ptr(cur_ptr);
+        }
+      }
+    else cur_val=sa_ptr(m);
+  else cur_val=equiv(m);
+  cur_val_level=tok_val;
+  }
+else{@+back_input();scan_font_ident();
+  scanned_result(font_id_base+cur_val, ident_val);
+  }
+
+@ Users refer to `\.{\\the\\spacefactor}' only in horizontal
+mode, and to `\.{\\the\\prevdepth}' only in vertical mode; so we put the
+associated mode in the modifier part of the |set_aux| command.
+The |set_page_int| command has modifier 0 or 1, for `\.{\\deadcycles}' and
+`\.{\\insertpenalties}', respectively. The |set_box_dimen| command is
+modified by either |width_offset|, |height_offset|, or |depth_offset|.
+And the |last_item| command is modified by either |int_val|, |dimen_val|,
+|glue_val|, |input_line_no_code|, or |badness_code|.
+\eTeX\ inserts |last_node_type_code| after |glue_val| and adds
+the codes for its extensions: |eTeX_version_code|, \dots\ .
+
+ at d last_node_type_code (glue_val+1) /*code for \.{\\lastnodetype}*/
+ at d input_line_no_code (glue_val+2) /*code for \.{\\inputlineno}*/
+ at d badness_code (input_line_no_code+1) /*code for \.{\\badness}*/
+@#
+ at d eTeX_int (badness_code+1) /*first of \eTeX\ codes for integers*/
+ at d eTeX_dim (eTeX_int+8) /*first of \eTeX\ codes for dimensions*/
+ at d eTeX_glue (eTeX_dim+9) /*first of \eTeX\ codes for glue*/
+ at d eTeX_mu (eTeX_glue+1) /*first of \eTeX\ codes for muglue*/
+ at d eTeX_expr (eTeX_mu+1) /*first of \eTeX\ codes for expressions*/
+ at d eTeX_last_last_item_cmd_mod (eTeX_expr-int_val+mu_val) /*\.{\\muexpr}*/
+
+@<Put each...@>=
+primitive("spacefactor", set_aux, hmode);
+@!@:space\_factor\_}{\.{\\spacefactor} primitive@>
+primitive("prevdepth", set_aux, vmode);@/
+@!@:prev\_depth\_}{\.{\\prevdepth} primitive@>
+primitive("deadcycles", set_page_int, 0);
+@!@:dead\_cycles\_}{\.{\\deadcycles} primitive@>
+primitive("insertpenalties", set_page_int, 1);
+@!@:insert\_penalties\_}{\.{\\insertpenalties} primitive@>
+primitive("wd", set_box_dimen, width_offset);
+@!@:wd\_}{\.{\\wd} primitive@>
+primitive("ht", set_box_dimen, height_offset);
+@!@:ht\_}{\.{\\ht} primitive@>
+primitive("dp", set_box_dimen, depth_offset);
+@!@:dp\_}{\.{\\dp} primitive@>
+primitive("lastpenalty", last_item, int_val);
+@!@:last\_penalty\_}{\.{\\lastpenalty} primitive@>
+primitive("lastkern", last_item, dimen_val);
+@!@:last\_kern\_}{\.{\\lastkern} primitive@>
+primitive("lastskip", last_item, glue_val);
+@!@:last\_skip\_}{\.{\\lastskip} primitive@>
+primitive("inputlineno", last_item, input_line_no_code);
+@!@:input\_line\_no\_}{\.{\\inputlineno} primitive@>
+primitive("badness", last_item, badness_code);
+@!@:badness\_}{\.{\\badness} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case set_aux: if (chr_code==vmode) print_esc("prevdepth");
+ at +else print_esc("spacefactor");@+break;
+case set_page_int: if (chr_code==0) print_esc("deadcycles")
+@/@<Cases of |set_page_int| for |print_cmd_chr|@>;@/
+ at +else print_esc("insertpenalties");@+break;
+case set_box_dimen: if (chr_code==width_offset) print_esc("wd");
+else if (chr_code==height_offset) print_esc("ht");
+else print_esc("dp");@+break;
+case last_item: switch (chr_code) {
+  case int_val: print_esc("lastpenalty");@+break;
+  case dimen_val: print_esc("lastkern");@+break;
+  case glue_val: print_esc("lastskip");@+break;
+  case input_line_no_code: print_esc("inputlineno");@+break;
+  @/@<Cases of |last_item| for |print_cmd_chr|@>@/
+  default:print_esc("badness");
+  } @+break;
+
+@ @<Fetch the |space_factor| or the |prev_depth|@>=
+if (abs(mode)!=m)
+  {@+print_err("Improper ");print_cmd_chr(set_aux, m);
+ at .Improper \\spacefactor@>
+ at .Improper \\prevdepth@>
+  help4("You can refer to \\spacefactor only in horizontal mode;",@/
+    "you can refer to \\prevdepth only in vertical mode; and",@/
+    "neither of these is meaningful inside \\write. So",@/
+    "I'm forgetting what you said and using zero instead.");
+  error();
+  if (level!=tok_val) scanned_result(0, dimen_val)@;
+  else scanned_result(0, int_val);
+  }
+else if (m==vmode) scanned_result(prev_depth, dimen_val)@;
+else scanned_result(space_factor, int_val)
+
+@ @<Fetch the |dead_cycles| or the |insert_penalties|@>=
+{@+if (m==0) cur_val=dead_cycles
+@/@<Cases for `Fetch the |dead_cycles| or the |insert_penalties|'@>;@/
+else cur_val=insert_penalties;
+cur_val_level=int_val;
+}
+
+@ @<Fetch a box dimension@>=
+{@+scan_register_num();fetch_box(q);
+if (q==null) cur_val=0;@+else cur_val=mem[q+m].sc;
+cur_val_level=dimen_val;
+}
+
+@ Inside an \.{\\output} routine, a user may wish to look at the page totals
+that were present at the moment when output was triggered.
+
+ at d max_dimen 07777777777 /*$2^{30}-1$*/
+
+@<Fetch something on the |page_so_far|@>=
+{@+if ((page_contents==empty)&&(!output_active))
+  if (m==0) cur_val=max_dimen;@+else cur_val=0;
+else cur_val=page_so_far[m];
+cur_val_level=dimen_val;
+}
+
+@ @<Fetch the |prev_graf|@>=
+if (mode==0) scanned_result(0, int_val)@; /*|prev_graf==0| within \.{\\write}*/
+else{@+nest[nest_ptr]=cur_list;p=nest_ptr;
+  while (abs(nest[p].mode_field)!=vmode) decr(p);
+  scanned_result(nest[p].pg_field, int_val);
+  }
+
+@ @<Fetch the |par_shape| size@>=
+{@+if (m > par_shape_loc) @<Fetch a penalties array element@>@;
+else if (par_shape_ptr==null) cur_val=0;
+else cur_val=info(par_shape_ptr);
+cur_val_level=int_val;
+}
+
+@ Here is where \.{\\lastpenalty}, \.{\\lastkern}, \.{\\lastskip}, and
+\.{\\lastnodetype} are
+implemented. The reference count for \.{\\lastskip} will be updated later.
+
+We also handle \.{\\inputlineno} and \.{\\badness} here, because they are
+legal in similar contexts.
+
+@<Fetch an item in the current node...@>=
+if (m > eTeX_last_last_item_cmd_mod)
+  @/@<Fetch a \Prote\ item@>@;@/
+else if (m >= input_line_no_code)
+ if (m >= eTeX_glue) @<Process an expression and |return|@>@;
+ else if (m >= eTeX_dim)
+  {@+switch (m) {
+  @/@<Cases for fetching a dimension value@>@/
+  }  /*there are no other cases*/
+  cur_val_level=dimen_val;
+  }
+ else{@+switch (m) {
+  case input_line_no_code: cur_val=line;@+break;
+  case badness_code: cur_val=last_badness;@+break;
+  @/@<Cases for fetching an integer value@>@/
+  }  /*there are no other cases*/
+  cur_val_level=int_val;
+  }
+else{@+if (cur_chr==glue_val) cur_val=zero_glue;@+else cur_val=0;
+  tx=tail;
+  if (cur_chr==last_node_type_code)
+    {@+cur_val_level=int_val;
+    if ((tx==head)||(mode==0)) cur_val=-1;
+    }
+  else cur_val_level=cur_chr;
+  if (!is_char_node(tx)&&(mode!=0))
+    switch (cur_chr) {
+    case int_val: if (type(tx)==penalty_node) cur_val=penalty(tx);@+break;
+    case dimen_val: if (type(tx)==kern_node) cur_val=width(tx);@+break;
+    case glue_val: if (type(tx)==glue_node)
+      {@+cur_val=glue_ptr(tx);
+      if (subtype(tx)==mu_glue) cur_val_level=mu_val;
+      } @+break;
+    case last_node_type_code: if (type(tx) <= unset_node) cur_val=type(tx)+1;
+      else cur_val=unset_node+2;
+    }  /*there are no other cases*/
+  else if ((mode==vmode)&&(tx==head))
+    switch (cur_chr) {
+    case int_val: cur_val=last_penalty;@+break;
+    case dimen_val: cur_val=last_kern;@+break;
+    case glue_val: if (last_glue!=max_halfword) cur_val=last_glue;@+break;
+    case last_node_type_code: cur_val=last_node_type;
+    }  /*there are no other cases*/
+  }
+
+@ @<Fetch a font dimension@>=
+{@+find_font_dimen(false);font_info[fmem_ptr].sc=0;
+scanned_result(font_info[cur_val].sc, dimen_val);
+}
+
+@ @<Fetch a font integer@>=
+{@+scan_font_ident();
+if (m==0) scanned_result(hyphen_char[cur_val], int_val)@;
+else scanned_result(skew_char[cur_val], int_val);
+}
+
+@ @<Fetch a register@>=
+{@+if ((m < mem_bot)||(m > lo_mem_stat_max))
+  {@+cur_val_level=sa_type(m);
+  if (cur_val_level < glue_val) cur_val=sa_int(m);
+  else cur_val=sa_ptr(m);
+  }
+else{@+scan_register_num();cur_val_level=m-mem_bot;
+  if (cur_val > 255)
+    {@+find_sa_element(cur_val_level, cur_val, false);
+    if (cur_ptr==null)
+      if (cur_val_level < glue_val) cur_val=0;
+      else cur_val=zero_glue;
+    else if (cur_val_level < glue_val) cur_val=sa_int(cur_ptr);
+    else cur_val=sa_ptr(cur_ptr);
+    }
+  else
+  switch (cur_val_level) {
+case int_val: cur_val=count(cur_val);@+break;
+case dimen_val:
+  cur_hfactor=dimen_hfactor(cur_val);
+  cur_vfactor=dimen_vfactor(cur_val);
+  cur_val=dimen(cur_val);@+break;
+case glue_val: cur_val=skip(cur_val);@+break;
+case mu_val: cur_val=mu_skip(cur_val);
+}  /*there are no other cases*/
+  }
+}
+
+@ @<Complain that \.{\\the} can't do this; give zero result@>=
+{@+print_err("You can't use `");print_cmd_chr(cur_cmd, cur_chr);
+ at .You can't use x after ...@>
+print("' after ");print_esc("the");
+help1("I'm forgetting what you said and using zero instead.");
+error();
+if (level!=tok_val) scanned_result(0, dimen_val)@;
+else scanned_result(0, int_val);
+}
+
+@ When a |glue_val| changes to a |dimen_val|, we use the width component
+of the glue; there is no need to decrease the reference count, since it
+has not yet been increased.  When a |dimen_val| changes to an |int_val|,
+we use scaled points so that the value doesn't actually change. And when a
+|mu_val| changes to a |glue_val|, the value doesn't change either.
+
+@<Convert \(c)|cur_val| to a lower level@>=
+{@+if (cur_val_level==glue_val) cur_val=width(cur_val);
+else if (cur_val_level==mu_val) mu_error();
+decr(cur_val_level);
+}
+
+@ If |cur_val| points to a glue specification at this point, the reference
+count for the glue does not yet include the reference by |cur_val|.
+If |negative| is |true|, |cur_val_level| is known to be | <= mu_val|.
+
+@<Fix the reference count, if any,...@>=
+if (negative)
+  if (cur_val_level >= glue_val)
+    {@+cur_val=new_spec(cur_val);
+    @<Negate all three glue components of |cur_val|@>;
+    }
+  else {@+ negate(cur_val);@+ negate(cur_hfactor); @+negate(cur_vfactor); @+}
+else if ((cur_val_level >= glue_val)&&(cur_val_level <= mu_val))
+  add_glue_ref(cur_val)
+
+@ @<Negate all three...@>=
+{@+negate(width(cur_val));
+negate(stretch(cur_val));
+negate(shrink(cur_val));
+}
+
+@ Our next goal is to write the |scan_int| procedure, which scans anything that
+\TeX\ treats as an integer. But first we might as well look at some simple
+applications of |scan_int| that have already been made inside of
+|scan_something_internal|.
+
+@ @<Declare procedures that scan restricted classes of integers@>=
+static void scan_eight_bit_int(void)
+{@+scan_int();
+if ((cur_val < 0)||(cur_val > 255))
+  {@+print_err("Bad register code");
+ at .Bad register code@>
+  help2("A register number must be between 0 and 255.",@/
+    "I changed this one to zero.");int_error(cur_val);cur_val=0;
+  }
+}
+
+@ @<Declare procedures that scan restricted classes of integers@>=
+static void scan_char_num(void)
+{@+scan_int();
+if ((cur_val < 0)||(cur_val > 255))
+  {@+print_err("Bad character code");
+ at .Bad character code@>
+  help2("A character number must be between 0 and 255.",@/
+    "I changed this one to zero.");int_error(cur_val);cur_val=0;
+  }
+}
+
+@ While we're at it, we might as well deal with similar routines that
+will be needed later.
+
+@<Declare procedures that scan restricted classes of integers@>=
+static void scan_four_bit_int(void)
+{@+scan_int();
+if ((cur_val < 0)||(cur_val > 15))
+  {@+print_err("Bad number");
+ at .Bad number@>
+  help2("Since I expected to read a number between 0 and 15,",@/
+    "I changed this one to zero.");int_error(cur_val);cur_val=0;
+  }
+}
+
+@ @<Declare procedures that scan restricted classes of integers@>=
+static void scan_fifteen_bit_int(void)
+{@+scan_int();
+if ((cur_val < 0)||(cur_val > 077777))
+  {@+print_err("Bad mathchar");
+ at .Bad mathchar@>
+  help2("A mathchar number must be between 0 and 32767.",@/
+    "I changed this one to zero.");int_error(cur_val);cur_val=0;
+  }
+}
+
+@ @<Declare procedures that scan restricted classes of integers@>=
+static void scan_twenty_seven_bit_int(void)
+{@+scan_int();
+if ((cur_val < 0)||(cur_val > 0777777777))
+  {@+print_err("Bad delimiter code");
+ at .Bad delimiter code@>
+  help2("A numeric delimiter code must be between 0 and 2^{27}-1.",@/
+    "I changed this one to zero.");int_error(cur_val);cur_val=0;
+  }
+}
+
+@ An integer number can be preceded by any number of spaces and `\.+' or
+`\.-' signs. Then comes either a decimal constant (i.e., radix 10), an
+octal constant (i.e., radix 8, preceded by~\.\'), a hexadecimal constant
+(radix 16, preceded by~\."), an alphabetic constant (preceded by~\.\`), or
+an internal variable. After scanning is complete,
+|cur_val| will contain the answer, which must be at most
+$2^{31}-1=2147483647$ in absolute value. The value of |radix| is set to
+10, 8, or 16 in the cases of decimal, octal, or hexadecimal constants,
+otherwise |radix| is set to zero. An optional space follows a constant.
+
+ at d octal_token (other_token+'\'') /*apostrophe, indicates an octal constant*/
+ at d hex_token (other_token+'"') /*double quote, indicates a hex constant*/
+ at d alpha_token (other_token+'`') /*reverse apostrophe, precedes alpha constants*/
+ at d point_token (other_token+'.') /*decimal point*/
+ at d continental_point_token (other_token+',') /*decimal point, Eurostyle*/
+
+@<Glob...@>=
+static small_number @!radix; /*|scan_int| sets this to 8, 10, 16, or zero*/
+
+@ We initialize the following global variables just in case |expand|
+comes into action before any of the basic scanning routines has assigned
+them a value.
+
+@<Set init...@>=
+cur_val=0;cur_val_level=int_val;radix=0;cur_order=normal;
+
+@ The |scan_int| routine is used also to scan the integer part of a
+fraction; for example, the `\.3' in `\.{3.14159}' will be found by
+|scan_int|. The |scan_dimen| routine assumes that |cur_tok==point_token|
+after the integer part of such a fraction has been scanned by |scan_int|,
+and that the decimal point has been backed up to be scanned again.
+
+ at p static void scan_int(void) /*sets |cur_val| to an integer*/
+{@+
+bool negative; /*should the answer be negated?*/
+int @!m; /*|@t$2^{31}$@>/radix|, the threshold of danger*/
+small_number @!d; /*the digit just scanned*/
+bool @!vacuous; /*have no digits appeared?*/
+bool @!OK_so_far; /*has an error message been issued?*/
+radix=0;OK_so_far=true;@/
+@<Get the next non-blank non-sign token; set |negative| appropriately@>;
+if (cur_tok==alpha_token) @<Scan an alphabetic character code into |cur_val|@>@;
+else if ((cur_cmd >= min_internal)&&(cur_cmd <= max_internal))
+  scan_something_internal(int_val, false);
+else@<Scan a numeric constant@>;
+if (negative) negate(cur_val);
+}
+
+@ @<Get the next non-blank non-sign token...@>=
+negative=false;
+@/do at +{@<Get the next non-blank non-call token@>;
+if (cur_tok==other_token+'-')
+  {@+negative=!negative;cur_tok=other_token+'+';
+  }
+}@+ while (!(cur_tok!=other_token+'+'))
+
+@ A space is ignored after an alphabetic character constant, so that
+such constants behave like numeric ones.
+
+@<Scan an alphabetic character code into |cur_val|@>=
+{@+get_token(); /*suppress macro expansion*/
+if (cur_tok < cs_token_flag)
+  {@+cur_val=cur_chr;
+  if (cur_cmd <= right_brace)
+    if (cur_cmd==right_brace) incr(align_state);
+    else decr(align_state);
+  }
+else if (cur_tok < cs_token_flag+single_base)
+  cur_val=cur_tok-cs_token_flag-active_base;
+else cur_val=cur_tok-cs_token_flag-single_base;
+if (cur_val > 255)
+  {@+print_err("Improper alphabetic constant");
+ at .Improper alphabetic constant@>
+  help2("A one-character control sequence belongs after a ` mark.",@/
+    "So I'm essentially inserting \\0 here.");
+  cur_val='0';back_error();
+  }
+else@<Scan an optional space@>;
+}
+
+@ @<Scan an optional space@>=
+{@+get_x_token();if (cur_cmd!=spacer) back_input();
+}
+
+@ @<Scan a numeric constant@>=
+{@+radix=10;m=214748364;
+if (cur_tok==octal_token)
+  {@+radix=8;m=02000000000;get_x_token();
+  }
+else if (cur_tok==hex_token)
+  {@+radix=16;m=01000000000;get_x_token();
+  }
+vacuous=true;cur_val=0;@/
+@<Accumulate the constant until |cur_tok| is not a suitable digit@>;
+if (vacuous) @<Express astonishment that no number was here@>@;
+else if (cur_cmd!=spacer) back_input();
+}
+
+@ @d infinity 017777777777 /*the largest positive value that \TeX\ knows*/
+ at d zero_token (other_token+'0') /*zero, the smallest digit*/
+ at d A_token (letter_token+'A') /*the smallest special hex digit*/
+ at d other_A_token (other_token+'A') /*special hex digit of type |other_char|*/
+
+@<Accumulate the constant...@>=
+loop at +{@+if ((cur_tok < zero_token+radix)&&(cur_tok >= zero_token)&&
+    (cur_tok <= zero_token+9)) d=cur_tok-zero_token;
+  else if (radix==16)
+    if ((cur_tok <= A_token+5)&&(cur_tok >= A_token)) d=cur_tok-A_token+10;
+    else if ((cur_tok <= other_A_token+5)&&(cur_tok >= other_A_token))
+      d=cur_tok-other_A_token+10;
+    else goto done;
+  else goto done;
+  vacuous=false;
+  if ((cur_val >= m)&&((cur_val > m)||(d > 7)||(radix!=10)))
+    {@+if (OK_so_far)
+      {@+print_err("Number too big");
+ at .Number too big@>
+      help2("I can only go up to 2147483647='17777777777=\"7FFFFFFF,",@/
+        "so I'm using that number instead of yours.");
+      error();cur_val=infinity;OK_so_far=false;
+      }
+    }
+  else cur_val=cur_val*radix+d;
+  get_x_token();
+  }
+done:
+
+@ @<Express astonishment...@>=
+{@+print_err("Missing number, treated as zero");
+ at .Missing number...@>
+help3("A number should have been here; I inserted `0'.",@/
+  "(If you can't figure out why I needed to see a number,",@/
+  "look up `weird error' in the index to The TeXbook.)");
+@:TeXbook}{\sl The \TeX book@>
+back_error();
+}
+
+@ The |scan_dimen| routine is similar to |scan_int|, but it sets |cur_val| to
+a |scaled| value, i.e., an integral number of sp. One of its main tasks
+is therefore to interpret the abbreviations for various kinds of units and
+to convert measurements to scaled points.
+
+There are three parameters: |mu| is |true| if the finite units must be
+`\.{mu}', while |mu| is |false| if `\.{mu}' units are disallowed;
+|inf| is |true| if the infinite units `\.{fil}', `\.{fill}', `\.{filll}'
+are permitted; and |shortcut| is |true| if |cur_val| already contains
+an integer and only the units need to be considered.
+
+The order of infinity that was found in the case of infinite glue is returned
+in the global variable |cur_order|.
+
+@<Glob...@>=
+static glue_ord @!cur_order; /*order of infinity found by |scan_dimen|*/
+
+@ Constructions like `\.{-\'77 pt}' are legal dimensions, so |scan_dimen|
+may begin with |scan_int|. This explains why it is convenient to use
+|scan_int| also for the integer part of a decimal fraction.
+
+Several branches of |scan_dimen| work with |cur_val| as an integer and
+with an auxiliary fraction |f|, so that the actual quantity of interest is
+$|cur_val|+|f|/2^{16}$. At the end of the routine, this ``unpacked''
+representation is put into the single word |cur_val|, which suddenly
+switches significance from |int| to |scaled|.
+
+ at d scan_normal_dimen scan_dimen(false, false, false)
+
+ at p static void scan_dimen(bool @!mu, bool @!inf, bool @!shortcut)
+   /*sets |cur_val| to a dimension*/
+{@+
+bool negative; /*should the answer be negated?*/
+int @!f; /*numerator of a fraction whose denominator is $2^{16}$*/
+@<Local variables for dimension calculations@>@;
+f=0;arith_error=false;cur_order=normal;negative=false;
+cur_hfactor=cur_vfactor=0;
+if (!shortcut)
+  {@+@<Get the next non-blank non-sign...@>;
+  if ((cur_cmd >= min_internal)&&(cur_cmd <= max_internal))
+    @<Fetch an internal dimension and |goto attach_sign|, or fetch an internal integer@>@;
+  else{@+back_input();
+    if (cur_tok==continental_point_token) cur_tok=point_token;
+    if (cur_tok!=point_token) scan_int();
+    else{@+radix=10;cur_val=0;
+      }
+    if (cur_tok==continental_point_token) cur_tok=point_token;
+    if ((radix==10)&&(cur_tok==point_token)) @<Scan decimal fraction@>;
+    }
+  }
+if (cur_val < 0)  /*in this case |f==0|*/
+  {@+negative=!negative;negate(cur_val);
+  }
+@<Scan units and set |cur_val| to $x\cdot(|cur_val|+f/2^{16})$, where there are |x|
+sp per unit; |goto attach_sign| if the units are internal@>;
+@<Scan an optional space@>;
+attach_sign:
+if (arith_error||(abs(cur_val) >= 010000000000)||
+(abs(cur_hfactor) >= 010000000000) || (abs(cur_vfactor) >= 010000000000))
+  @<Report that this dimension is out of range@>;
+if (negative) @/{@+ negate(cur_val);@+ negate(cur_hfactor); @+negate(cur_vfactor);@+ }
+}
+
+@ @<Fetch an internal dimension and |goto attach_sign|...@>=
+if (mu)
+  {@+scan_something_internal(mu_val, false);
+  @<Coerce glue to a dimension@>;
+  if (cur_val_level==mu_val) goto attach_sign;
+  if (cur_val_level!=int_val) mu_error();
+  }
+else{@+scan_something_internal(dimen_val, false);
+  if (cur_val_level==dimen_val) goto attach_sign;
+  }
+
+@ @<Local variables for dimension calculations@>=
+int @!num, @!denom; /*conversion ratio for the scanned units*/
+int @!k, @!kk; /*number of digits in a decimal fraction*/
+pointer @!p, @!q; /*top of decimal digit stack*/
+scaled @!v; /*an internal dimension*/
+int @!save_cur_val; /*temporary storage of |cur_val|*/
+
+@ The following code is executed when |scan_something_internal| was
+called asking for |mu_val|, when we really wanted a ``mudimen'' instead
+of ``muglue.''
+
+@<Coerce glue to a dimension@>=
+if (cur_val_level >= glue_val)
+  {@+v=width(cur_val);delete_glue_ref(cur_val);cur_val=v;
+  }
+
+@ When the following code is executed, we have |cur_tok==point_token|, but this
+token has been backed up using |back_input|; we must first discard it.
+
+It turns out that a decimal point all by itself is equivalent to `\.{0.0}'.
+Let's hope people don't use that fact.
+
+@<Scan decimal fraction@>=
+{@+k=0;p=null;get_token(); /*|point_token| is being re-scanned*/
+loop at +{@+get_x_token();
+  if ((cur_tok > zero_token+9)||(cur_tok < zero_token)) goto done1;
+  if (k < 17)  /*digits for |k >= 17| cannot affect the result*/
+    {@+q=get_avail();link(q)=p;info(q)=cur_tok-zero_token;
+    p=q;incr(k);
+    }
+  }
+done1: for (kk=k; kk>=1; kk--)
+  {@+dig[kk-1]=info(p);q=p;p=link(p);free_avail(q);
+  }
+f=round_decimals(k);
+if (cur_cmd!=spacer) back_input();
+}
+
+@ Now comes the harder part: At this point in the program, |cur_val| is a
+nonnegative integer and $f/2^{16}$ is a nonnegative fraction less than 1;
+we want to multiply the sum of these two quantities by the appropriate
+factor, based on the specified units, in order to produce a |scaled|
+result, and we want to do the calculation with fixed point arithmetic that
+does not overflow.
+
+@<Scan units and set |cur_val| to $x\cdot(|cur_val|+f/2^{16})$...@>=
+if (inf) @<Scan for \(f)\.{fil} units; |goto attach_fraction| if found@>;
+@<Scan for \(u)units that are internal dimensions; |goto attach_sign| with |cur_val|
+set if found@>;
+if (mu) @<Scan for \(m)\.{mu} units and |goto attach_fraction|@>;
+if (scan_keyword("true")) @<Adjust \(f)for the magnification ratio@>;
+ at .true@>
+if (scan_keyword("pt")) goto attach_fraction; /*the easy case*/
+ at .pt@>
+@<Scan for \(a)all other units and adjust |cur_val| and |f| accordingly; |goto done|
+in the case of scaled points@>;
+attach_fraction: if (cur_val >= 040000) arith_error=true;
+else cur_val=cur_val*unity+f;
+done:
+
+@ A specification like `\.{filllll}' or `\.{fill L L L}' will lead to two
+error messages (one for each additional keyword \.{"l"}).
+
+@<Scan for \(f)\.{fil} units...@>=
+if (scan_keyword("fil"))
+ at .fil@>
+  {@+cur_order=fil;
+  while (scan_keyword("l"))
+    {@+if (cur_order==filll)
+      {@+print_err("Illegal unit of measure (");
+ at .Illegal unit of measure@>
+      print("replaced by filll)");
+      help1("I dddon't go any higher than filll.");error();
+      }
+    else incr(cur_order);
+    }
+  goto attach_fraction;
+  }
+
+@ @<Scan for \(u)units that are internal dimensions...@>=
+save_cur_val=cur_val;
+if (has_factor)
+{ print_err("Factor is not constant. Linear component ignored");
+  cur_hfactor=cur_vfactor=0;
+}
+@<Get the next non-blank non-call...@>;
+if ((cur_cmd < min_internal)||(cur_cmd > max_internal)) back_input();
+else{@+if (mu)
+    {@+scan_something_internal(mu_val, false);@<Coerce glue...@>;
+    if (cur_val_level!=mu_val) mu_error();
+    }
+  else scan_something_internal(dimen_val, false);
+  v=cur_val;goto found;
+  }
+if (mu) goto not_found;
+if (scan_keyword("em")) v=(@<The em width for |cur_font|@>);
+ at .em@>
+else if (scan_keyword("ex")) v=(@<The x-height for |cur_font|@>);
+ at .ex@>
+else goto not_found;
+@<Scan an optional space@>;
+found:
+if (has_factor)
+{ cur_hfactor=nx_plus_y(save_cur_val, cur_hfactor, xn_over_d(cur_hfactor, f, unity));
+  cur_vfactor=nx_plus_y(save_cur_val, cur_vfactor, xn_over_d(cur_vfactor, f, unity));
+}
+  cur_val=nx_plus_y(save_cur_val, v, xn_over_d(v, f, unity));
+goto attach_sign;
+not_found:
+
+@ @<Scan for \(m)\.{mu} units and |goto attach_fraction|@>=
+if (scan_keyword("mu")) goto attach_fraction;
+ at .mu@>
+else{@+print_err("Illegal unit of measure (");print("mu inserted)");
+ at .Illegal unit of measure@>
+  help4("The unit of measurement in math glue must be mu.",@/
+    "To recover gracefully from this error, it's best to",@/
+    "delete the erroneous units; e.g., type `2' to delete",@/
+    "two letters. (See Chapter 27 of The TeXbook.)");
+@:TeXbook}{\sl The \TeX book@>
+  error();goto attach_fraction;
+  }
+
+@ @<Adjust \(f)for the magnification ratio@>=
+{@+prepare_mag();
+if (mag!=1000)
+  {@+cur_val=xn_over_d(cur_val, 1000, mag);
+  f=(1000*f+0200000*rem)/mag;
+  cur_val=cur_val+(f/0200000);f=f%0200000;
+  }
+}
+
+@ The necessary conversion factors can all be specified exactly as
+fractions whose numerator and denominator sum to 32768 or less.
+According to the definitions here, $\rm2660\,dd\approx1000.33297\,mm$;
+this agrees well with the value $\rm1000.333\,mm$ cited by Bosshard
+@^Bosshard, Hans Rudolf@>
+in {\sl Technische Grundlagen zur Satzherstellung\/} (Bern, 1980).
+
+ at d set_conversion(A, B) @+{@+num=A;denom=B;}
+
+@<Scan for \(a)all other units and adjust |cur_val| and |f|...@>=
+if (scan_keyword("in")) set_conversion(7227, 100)@;
+ at .in@>
+else if (scan_keyword("pc")) set_conversion(12, 1)@;
+ at .pc@>
+else if (scan_keyword("cm")) set_conversion(7227, 254)@;
+ at .cm@>
+else if (scan_keyword("mm")) set_conversion(7227, 2540)@;
+ at .mm@>
+else if (scan_keyword("bp")) set_conversion(7227, 7200)@;
+ at .bp@>
+else if (scan_keyword("dd")) set_conversion(1238, 1157)@;
+ at .dd@>
+else if (scan_keyword("cc")) set_conversion(14856, 1157)@;
+ at .cc@>
+else if (scan_keyword("sp")) goto done;
+ at .sp@>
+else@<Complain about unknown unit and |goto done2|@>;
+cur_val=xn_over_d(cur_val, num, denom);
+f=(num*f+0200000*rem)/denom;@/
+cur_val=cur_val+(f/0200000);f=f%0200000;
+done2:
+
+@ @<Complain about unknown unit...@>=
+{@+print_err("Illegal unit of measure (");print("pt inserted)");
+ at .Illegal unit of measure@>
+help6("Dimensions can be in units of em, ex, in, pt, pc,",@/
+  "cm, mm, dd, cc, bp, or sp; but yours is a new one!",@/
+  "I'll assume that you meant to say pt, for printer's points.",@/
+  "To recover gracefully from this error, it's best to",@/
+  "delete the erroneous units; e.g., type `2' to delete",@/
+  "two letters. (See Chapter 27 of The TeXbook.)");
+@:TeXbook}{\sl The \TeX book@>
+error();goto done2;
+}
+
+
+@ @<Report that this dimension is out of range@>=
+{@+print_err("Dimension too large");
+ at .Dimension too large@>
+help2("I can't work with sizes bigger than about 19 feet.",@/
+  "Continue and I'll use the largest value I can.");@/
+error();cur_val=max_dimen;arith_error=false;
+}
+
+@ The final member of \TeX's value-scanning trio is |scan_glue|, which
+makes |cur_val| point to a glue specification. The reference count of that
+glue spec will take account of the fact that |cur_val| is pointing to~it.
+
+The |level| parameter should be either |glue_val| or |mu_val|.
+
+Since |scan_dimen| was so much more complex than |scan_int|, we might expect
+|scan_glue| to be even worse. But fortunately, it is very simple, since
+most of the work has already been done.
+
+ at p static void scan_glue(small_number @!level)
+   /*sets |cur_val| to a glue spec pointer*/
+{@+
+bool negative; /*should the answer be negated?*/
+pointer @!q; /*new glue specification*/
+bool @!mu; /*does |level==mu_val|?*/
+mu=(level==mu_val);@<Get the next non-blank non-sign...@>;
+if ((cur_cmd >= min_internal)&&(cur_cmd <= max_internal))
+  {@+scan_something_internal(level, negative);
+  if (cur_val_level >= glue_val)
+    {@+if (cur_val_level!=level) mu_error();
+    return;
+    }
+  if (cur_val_level==int_val) scan_dimen(mu, false, true);
+  else if (level==mu_val) mu_error();
+  }
+else{@+back_input();scan_dimen(mu, false, false);
+  if (negative) { negate(cur_val); negate(cur_hfactor); negate(cur_vfactor);}
+  }
+@<Create a new glue specification whose width is |cur_val|; scan for its stretch and
+shrink components@>;
+}
+@#
+@<Declare procedures needed for expressions@>@;
+
+@ @<Create a new glue specification whose width is |cur_val|...@>=
+q=new_spec(zero_glue);width(q)=cur_val;
+if (scan_keyword("plus"))
+ at .plus@>
+  {@+scan_dimen(mu, true, false);
+  stretch(q)=cur_val;stretch_order(q)=cur_order;
+  }
+if (scan_keyword("minus"))
+ at .minus@>
+  {@+scan_dimen(mu, true, false);
+  shrink(q)=cur_val;shrink_order(q)=cur_order;
+  }
+cur_val=q
+
+@ Here's a similar procedure that returns a pointer to a rule node. This
+routine is called just after \TeX\ has seen \.{\\hrule} or \.{\\vrule};
+therefore |cur_cmd| will be either |hrule| or |vrule|. The idea is to store
+the default rule dimensions in the node, then to override them if
+`\.{height}' or `\.{width}' or `\.{depth}' specifications are
+found (in any order).
+
+ at d default_rule 26214 /*0.4\thinspace pt*/
+
+ at p static pointer scan_rule_spec(void)
+{@+
+pointer q; /*the rule node being created*/
+q=new_rule(); /*|width|, |depth|, and |height| all equal |null_flag| now*/
+if (cur_cmd==vrule) width(q)=default_rule;
+else{@+height(q)=default_rule;depth(q)=0;
+  }
+reswitch: if (scan_keyword("width"))
+ at .width@>
+  {@+scan_normal_dimen;width(q)=cur_val;goto reswitch;
+  }
+if (scan_keyword("height"))
+ at .height@>
+  {@+scan_normal_dimen;height(q)=cur_val;goto reswitch;
+  }
+if (scan_keyword("depth"))
+ at .depth@>
+  {@+scan_normal_dimen;depth(q)=cur_val;goto reswitch;
+  }
+return q;
+}
+
+@* Building token lists.
+The token lists for macros and for other things like \.{\\mark} and \.{\\output}
+and \.{\\write} are produced by a procedure called |scan_toks|.
+
+Before we get into the details of |scan_toks|, let's consider a much
+simpler task, that of converting the current string into a token list.
+The |str_toks| function does this; it classifies spaces as type |spacer|
+and everything else as type |other_char|.
+
+The token list created by |str_toks| begins at |link(temp_head)| and ends
+at the value |p| that is returned. (If |p==temp_head|, the list is empty.)
+
+ at p @t\4@>@<Declare \eTeX\ procedures for token lists@>@;@/
+static pointer str_toks(pool_pointer @!b)
+   /*converts |str_pool[b dotdot pool_ptr-1]| to a token list*/
+{@+pointer p; /*tail of the token list*/
+pointer @!q; /*new node being added to the token list via |store_new_token|*/
+halfword @!t; /*token being appended*/
+pool_pointer @!k; /*index into |str_pool|*/
+str_room(1);
+p=temp_head;link(p)=null;k=b;
+while (k < pool_ptr)
+  {@+t=so(str_pool[k]);
+  if (t==' ') t=space_token;
+  else t=other_token+t;
+  fast_store_new_token(t);
+  incr(k);
+  }
+pool_ptr=b;return p;
+}
+
+@ The main reason for wanting |str_toks| is the next function,
+|the_toks|, which has similar input/output characteristics.
+
+This procedure is supposed to scan something like `\.{\\skip\\count12}',
+i.e., whatever can follow `\.{\\the}', and it constructs a token list
+containing something like `\.{-3.0pt minus 0.5fill}'.
+
+ at p static pointer the_toks(void)
+{@+
+int old_setting; /*holds |selector| setting*/
+pointer @!p, @!q, @!r; /*used for copying a token list*/
+pool_pointer @!b; /*base of temporary string*/
+small_number @!c; /*value of |cur_chr|*/
+@<Handle \.{\\unexpanded} or \.{\\detokenize} and |return|@>;@/
+get_x_token();scan_something_internal(tok_val, false);
+if (cur_val_level >= ident_val) @<Copy the token list@>@;
+else{@+old_setting=selector;selector=new_string;b=pool_ptr;
+  switch (cur_val_level) {
+  case int_val: print_int(cur_val);@+break;
+  case dimen_val: {@+print_scaled(cur_val);print("pt");
+    } @+break;
+  case glue_val: {@+print_spec(cur_val,"pt");delete_glue_ref(cur_val);
+    } @+break;
+  case mu_val: {@+print_spec(cur_val,"mu");delete_glue_ref(cur_val);
+    }
+  }  /*there are no other cases*/
+  selector=old_setting;return str_toks(b);
+  }
+}
+
+@ @<Copy the token list@>=
+{@+p=temp_head;link(p)=null;
+if (cur_val_level==ident_val) store_new_token(cs_token_flag+cur_val)@;
+else if (cur_val!=null)
+  {@+r=link(cur_val); /*do not copy the reference count*/
+  while (r!=null)
+    {@+fast_store_new_token(info(r));r=link(r);
+    }
+  }
+return p;
+}
+
+@ Here's part of the |expand| subroutine that we are now ready to complete:
+
+ at p static void ins_the_toks(void)
+{@+link(garbage)=the_toks();ins_list(link(temp_head));
+}
+
+@ The primitives \.{\\number}, \.{\\romannumeral}, \.{\\string}, \.{\\meaning},
+\.{\\fontname}, and \.{\\jobname} are defined as follows.
+
+ at d number_code 0 /*command code for \.{\\number}*/
+ at d roman_numeral_code 1 /*command code for \.{\\romannumeral}*/
+ at d string_code 2 /*command code for \.{\\string}*/
+ at d meaning_code 3 /*command code for \.{\\meaning}*/
+ at d font_name_code 4 /*command code for \.{\\fontname}*/
+ at d job_name_code 5 /*command code for \.{\\jobname}*/
+ at d etex_convert_base (job_name_code+1) /*base for \eTeX's command codes*/
+ at d eTeX_revision_code etex_convert_base /*command code for \.{\\eTeXrevision}*/
+ at d etex_convert_codes (etex_convert_base+1) /*end of \eTeX's command codes*/
+ at d eTeX_last_convert_cmd_mod etex_convert_codes
+
+@<Put each...@>=
+primitive("number", convert, number_code);@/
+@!@:number\_}{\.{\\number} primitive@>
+primitive("romannumeral", convert, roman_numeral_code);@/
+@!@:roman\_numeral\_}{\.{\\romannumeral} primitive@>
+primitive("string", convert, string_code);@/
+@!@:string\_}{\.{\\string} primitive@>
+primitive("meaning", convert, meaning_code);@/
+@!@:meaning\_}{\.{\\meaning} primitive@>
+primitive("fontname", convert, font_name_code);@/
+@!@:font\_name\_}{\.{\\fontname} primitive@>
+primitive("jobname", convert, job_name_code);@/
+@!@:job\_name\_}{\.{\\jobname} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case convert: switch (chr_code) {
+  case number_code: print_esc("number");@+break;
+  case roman_numeral_code: print_esc("romannumeral");@+break;
+  case string_code: print_esc("string");@+break;
+  case meaning_code: print_esc("meaning");@+break;
+  case font_name_code: print_esc("fontname");@+break;
+  case job_name_code: print_esc("jobname");@+break;
+  case eTeX_revision_code: print_esc("eTeXrevision");@+break;
+  @/@<Cases of |convert| for |print_cmd_chr|@>@/
+  } @+break;
+
+@ The procedure |conv_toks| uses |str_toks| to insert the token list
+for |convert| functions into the scanner; `\.{\\outer}' control sequences
+are allowed to follow `\.{\\string}' and `\.{\\meaning}'.
+
+ at p static void conv_toks(void)
+{@+int old_setting; /*holds |selector| setting*/
+int @!c; /*desired type of conversion*/
+small_number @!save_scanner_status; /*|scanner_status| upon entry*/
+pool_pointer @!b; /*base of temporary string*/
+int @!i, @!k, @!l; /*general purpose index*/
+pool_pointer @!m, @!n; /*general purpose pool pointer*/
+bool @!r; /*general purpose refraction i.e. changing the way*/
+str_number @!s, @!t; /*general purpose; de dicto*/
+c=cur_chr;@<Scan the argument for command |c|@>;
+old_setting=selector;selector=new_string;b=pool_ptr;
+@<Print the result of command |c|@>;
+selector=old_setting;link(garbage)=str_toks(b);ins_list(link(temp_head));
+}
+
+@ @<Scan the argument for command |c|@>=
+switch (c) {
+case number_code: case roman_numeral_code: scan_int();@+break;
+case string_code: case meaning_code: {@+save_scanner_status=scanner_status;
+  scanner_status=normal;get_token();scanner_status=save_scanner_status;
+  } @+break;
+case font_name_code: scan_font_ident();@+break;
+case job_name_code: if (job_name==0) open_log_file();@+break;
+case eTeX_revision_code: do_nothing;@+break;
+@/@<Cases of `Scan the argument for command |c|'@>@/
+}  /*there are no other cases*/
+
+@ @<Print the result of command |c|@>=
+switch (c) {
+case number_code: print_int(cur_val);@+break;
+case roman_numeral_code: print_roman_int(cur_val);@+break;
+case string_code: if (cur_cs!=0) sprint_cs(cur_cs);
+  else print_char(cur_chr);@+break;
+case meaning_code: print_meaning();@+break;
+case font_name_code: {@+printn(font_name[cur_val]);
+  if (font_size[cur_val]!=font_dsize[cur_val])
+    {@+print(" at ");print_scaled(font_size[cur_val]);
+    print("pt");
+    }
+  } @+break;
+case eTeX_revision_code: print(eTeX_revision);@+break;
+case job_name_code: printn(job_name);@+break;
+@/@<Cases of `Print the result of command |c|'@>@/
+}  /*there are no other cases*/
+
+@ Now we can't postpone the difficulties any longer; we must bravely tackle
+|scan_toks|. This function returns a pointer to the tail of a new token
+list, and it also makes |def_ref| point to the reference count at the
+head of that list.
+
+There are two boolean parameters, |macro_def| and |xpand|. If |macro_def|
+is true, the goal is to create the token list for a macro definition;
+otherwise the goal is to create the token list for some other \TeX\
+primitive: \.{\\mark}, \.{\\output}, \.{\\everypar}, \.{\\lowercase},
+\.{\\uppercase}, \.{\\message}, \.{\\errmessage}, \.{\\write}, or
+\.{\\special}. In the latter cases a left brace must be scanned next; this
+left brace will not be part of the token list, nor will the matching right
+brace that comes at the end. If |xpand| is false, the token list will
+simply be copied from the input using |get_token|. Otherwise all expandable
+tokens will be expanded until unexpandable tokens are left, except that
+the results of expanding `\.{\\the}' are not expanded further.
+If both |macro_def| and |xpand| are true, the expansion applies
+only to the macro body (i.e., to the material following the first
+|left_brace| character).
+
+The value of |cur_cs| when |scan_toks| begins should be the |eqtb|
+address of the control sequence to display in ``runaway'' error
+messages.
+
+ at p static pointer scan_toks(bool @!macro_def, bool @!xpand)
+{@+
+halfword t; /*token representing the highest parameter number*/
+halfword @!s; /*saved token*/
+pointer @!p; /*tail of the token list being built*/
+pointer @!q; /*new node being added to the token list via |store_new_token|*/
+halfword @!unbalance; /*number of unmatched left braces*/
+halfword @!hash_brace; /*possible `\.{\#\{}' token*/
+if (macro_def) scanner_status=defining;
+ at +else scanner_status=absorbing;
+warning_index=cur_cs;def_ref=get_avail();token_ref_count(def_ref)=null;
+p=def_ref;hash_brace=0;t=zero_token;
+if (macro_def) @<Scan and build the parameter part of the macro definition@>@;
+else scan_left_brace(); /*remove the compulsory left brace*/
+@<Scan and build the body of the token list; |goto found| when finished@>;
+found: scanner_status=normal;
+if (hash_brace!=0) store_new_token(hash_brace);
+return p;
+}
+ at t\4@>@<Declare \Prote\ procedures for token lists@>@;@/
+
+@ @<Scan and build the parameter part...@>=
+{@+loop{@+resume: get_token(); /*set |cur_cmd|, |cur_chr|, |cur_tok|*/
+  if (cur_tok < right_brace_limit) goto done1;
+  if (cur_cmd==mac_param)
+    @<If the next character is a parameter number, make |cur_tok| a |match| token;
+but if it is a left brace, store `|left_brace|, |end_match|', set |hash_brace|, and
+|goto done|@>;
+  store_new_token(cur_tok);
+  }
+done1: store_new_token(end_match_token);
+if (cur_cmd==right_brace)
+  @<Express shock at the missing left brace; |goto found|@>;
+done: ;}
+
+@ @<Express shock...@>=
+{@+print_err("Missing { inserted");incr(align_state);
+ at .Missing \{ inserted@>
+help2("Where was the left brace? You said something like `\\def\\a}',",@/
+  "which I'm going to interpret as `\\def\\a{}'.");error();goto found;
+}
+
+@ @<If the next character is a parameter number...@>=
+{@+s=match_token+cur_chr;get_token();
+if (cur_tok < left_brace_limit)
+  {@+hash_brace=cur_tok;
+  store_new_token(cur_tok);store_new_token(end_match_token);
+  goto done;
+  }
+if (t==zero_token+9)
+  {@+print_err("You already have nine parameters");
+ at .You already have nine...@>
+  help2("I'm going to ignore the # sign you just used,",@/
+    "as well as the token that followed it.");error();goto resume;
+  }
+else{@+incr(t);
+  if (cur_tok!=t)
+    {@+print_err("Parameters must be numbered consecutively");
+ at .Parameters...consecutively@>
+    help2("I've inserted the digit you should have used after the #.",@/
+      "Type `1' to delete what you did use.");back_error();
+    }
+  cur_tok=s;
+  }
+}
+
+@ @<Scan and build the body of the token list; |goto found| when finished@>=
+unbalance=1;
+loop at +{@+if (xpand) @<Expand the next part of the input@>@;
+  else get_token();
+  if (cur_tok < right_brace_limit)
+    if (cur_cmd < right_brace) incr(unbalance);
+    else{@+decr(unbalance);
+      if (unbalance==0) goto found;
+      }
+  else if (cur_cmd==mac_param)
+    if (macro_def) @<Look for parameter number or \.{\#\#}@>;
+  store_new_token(cur_tok);
+  }
+
+@ Here we insert an entire token list created by |the_toks| without
+expanding it further.
+
+@<Expand the next part of the input@>=
+{@+loop{@+get_next();
+  if (cur_cmd >= call)
+    if (info(link(cur_chr))==protected_token)
+      {@+cur_cmd=relax;cur_chr=no_expand_flag;
+      }
+  if (cur_cmd <= max_command) goto done2;
+  if (cur_cmd!=the) expand();
+  else{@+q=the_toks();
+    if (link(temp_head)!=null)
+      {@+link(p)=link(temp_head);p=q;
+      }
+    }
+  }
+done2: x_token();
+}
+
+@ @<Look for parameter number...@>=
+{@+s=cur_tok;
+if (xpand) get_x_token();else get_token();
+if (cur_cmd!=mac_param)
+  if ((cur_tok <= zero_token)||(cur_tok > t))
+    {@+print_err("Illegal parameter number in definition of ");
+ at .Illegal parameter number...@>
+    sprint_cs(warning_index);
+    help3("You meant to type ## instead of #, right?",@/
+    "Or maybe a } was forgotten somewhere earlier, and things",@/
+    "are all screwed up? I'm going to assume that you meant ##.");
+    back_error();cur_tok=s;
+    }
+  else cur_tok=out_param_token-'0'+cur_chr;
+}
+
+@ Another way to create a token list is via the \.{\\read} command. The
+sixteen files potentially usable for reading appear in the following
+global variables. The value of |read_open[n]| will be |closed| if
+stream number |n| has not been opened or if it has been fully read;
+|just_open| if an \.{\\openin} but not a \.{\\read} has been done;
+and |normal| if it is open and ready to read the next line.
+
+ at d closed 2 /*not open, or at end of file*/
+ at d just_open 1 /*newly opened, first line not yet read*/
+
+@<Glob...@>=
+static alpha_file @!read_file[16]; /*used for \.{\\read}*/
+static int8_t @!read_open[17]; /*state of |read_file[n]|*/
+
+@ @<Set init...@>=
+for (k=0; k<=16; k++) read_open[k]=closed;
+
+@ The |read_toks| procedure constructs a token list like that for any
+macro definition, and makes |cur_val| point to it. Parameter |r| points
+to the control sequence that will receive this token list.
+
+ at p static void read_toks(int @!n, pointer @!r, halfword @!j)
+{@+
+pointer p; /*tail of the token list*/
+pointer @!q; /*new node being added to the token list via |store_new_token|*/
+int @!s; /*saved value of |align_state|*/
+small_number @!m; /*stream number*/
+scanner_status=defining;warning_index=r;
+def_ref=get_avail();token_ref_count(def_ref)=null;
+p=def_ref; /*the reference count*/
+store_new_token(end_match_token);
+if ((n < 0)||(n > 15)) m=16;@+else m=n;
+s=align_state;align_state=1000000; /*disable tab marks, etc.*/
+@/do at +{@<Input and store tokens from the next line of the file@>;
+}@+ while (!(align_state==1000000));
+cur_val=def_ref;scanner_status=normal;align_state=s;
+}
+
+@ @<Input and store tokens from the next line of the file@>=
+begin_file_reading();name=m+1;
+if (read_open[m]==closed) @<Input for \.{\\read} from the terminal@>;
+else if (read_open[m]==just_open) @<Input the first line of |read_file[m]|@>@;
+else@<Input the next line of |read_file[m]|@>;
+limit=last;
+if (end_line_char_inactive) decr(limit);
+else buffer[limit]=end_line_char;
+first=limit+1;loc=start;state=new_line;@/
+@<Handle \.{\\readline} and |goto done|@>;@/
+loop at +{@+get_token();
+  if (cur_tok==0) goto done;
+     /*|cur_cmd==cur_chr==0| will occur at the end of the line*/
+  if (align_state < 1000000)  /*unmatched `\.\}' aborts the line*/
+    {@+@/do at +{get_token();}@+ while (!(cur_tok==0));
+    align_state=1000000;goto done;
+    }
+  store_new_token(cur_tok);
+  }
+done: end_file_reading()
+
+@ Here we input on-line into the |buffer| array, prompting the user explicitly
+if |n >= 0|.  The value of |n| is set negative so that additional prompts
+will not be given in the case of multi-line input.
+
+@<Input for \.{\\read} from the terminal@>=
+if (interaction > nonstop_mode)
+  if (n < 0) prompt_input("")@;
+  else{@+wake_up_terminal;
+    print_ln();sprint_cs(r);prompt_input("=");n=-1;
+    }
+else fatal_error("*** (cannot \\read from terminal in nonstop modes)")
+ at .cannot \\read@>
+
+@ The first line of a file must be treated specially, since |input_ln|
+must be told not to start with |get|.
+@^system dependencies@>
+
+@<Input the first line of |read_file[m]|@>=
+if (input_ln(&read_file[m], false)) read_open[m]=normal;
+else{@+a_close(&read_file[m]);read_open[m]=closed;
+  }
+
+@ An empty line is appended at the end of a |read_file|.
+@^empty line at end of file@>
+
+@<Input the next line of |read_file[m]|@>=
+{@+if (!input_ln(&read_file[m], true))
+  {@+a_close(&read_file[m]);read_open[m]=closed;
+  if (align_state!=1000000)
+    {@+runaway();
+    print_err("File ended within ");print_esc("read");
+ at .File ended within \\read@>
+    help1("This \\read has unbalanced braces.");
+    align_state=1000000;limit=0;error();
+    }
+  }
+}
+
+@* Conditional processing.
+We consider now the way \TeX\ handles various kinds of \.{\\if} commands.
+
+ at d unless_code 32 /*amount added for `\.{\\unless}' prefix*/
+@#
+ at d if_char_code 0 /* `\.{\\if}' */
+ at d if_cat_code 1 /* `\.{\\ifcat}' */
+ at d if_int_code 2 /* `\.{\\ifnum}' */
+ at d if_dim_code 3 /* `\.{\\ifdim}' */
+ at d if_odd_code 4 /* `\.{\\ifodd}' */
+ at d if_vmode_code 5 /* `\.{\\ifvmode}' */
+ at d if_hmode_code 6 /* `\.{\\ifhmode}' */
+ at d if_mmode_code 7 /* `\.{\\ifmmode}' */
+ at d if_inner_code 8 /* `\.{\\ifinner}' */
+ at d if_void_code 9 /* `\.{\\ifvoid}' */
+ at d if_hbox_code 10 /* `\.{\\ifhbox}' */
+ at d if_vbox_code 11 /* `\.{\\ifvbox}' */
+ at d ifx_code 12 /* `\.{\\ifx}' */
+ at d if_eof_code 13 /* `\.{\\ifeof}' */
+ at d if_true_code 14 /* `\.{\\iftrue}' */
+ at d if_false_code 15 /* `\.{\\iffalse}' */
+ at d if_case_code 16 /* `\.{\\ifcase}' */
+
+@<Put each...@>=
+primitive("if", if_test, if_char_code);
+@!@:if\_char\_}{\.{\\if} primitive@>
+primitive("ifcat", if_test, if_cat_code);
+@!@:if\_cat\_code\_}{\.{\\ifcat} primitive@>
+primitive("ifnum", if_test, if_int_code);
+@!@:if\_int\_}{\.{\\ifnum} primitive@>
+primitive("ifdim", if_test, if_dim_code);
+@!@:if\_dim\_}{\.{\\ifdim} primitive@>
+primitive("ifodd", if_test, if_odd_code);
+@!@:if\_odd\_}{\.{\\ifodd} primitive@>
+primitive("ifvmode", if_test, if_vmode_code);
+@!@:if\_vmode\_}{\.{\\ifvmode} primitive@>
+primitive("ifhmode", if_test, if_hmode_code);
+@!@:if\_hmode\_}{\.{\\ifhmode} primitive@>
+primitive("ifmmode", if_test, if_mmode_code);
+@!@:if\_mmode\_}{\.{\\ifmmode} primitive@>
+primitive("ifinner", if_test, if_inner_code);
+@!@:if\_inner\_}{\.{\\ifinner} primitive@>
+primitive("ifvoid", if_test, if_void_code);
+@!@:if\_void\_}{\.{\\ifvoid} primitive@>
+primitive("ifhbox", if_test, if_hbox_code);
+@!@:if\_hbox\_}{\.{\\ifhbox} primitive@>
+primitive("ifvbox", if_test, if_vbox_code);
+@!@:if\_vbox\_}{\.{\\ifvbox} primitive@>
+primitive("ifx", if_test, ifx_code);
+@!@:ifx\_}{\.{\\ifx} primitive@>
+primitive("ifeof", if_test, if_eof_code);
+@!@:if\_eof\_}{\.{\\ifeof} primitive@>
+primitive("iftrue", if_test, if_true_code);
+@!@:if\_true\_}{\.{\\iftrue} primitive@>
+primitive("iffalse", if_test, if_false_code);
+@!@:if\_false\_}{\.{\\iffalse} primitive@>
+primitive("ifcase", if_test, if_case_code);
+@!@:if\_case\_}{\.{\\ifcase} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case if_test: {@+if (chr_code >= unless_code) print_esc("unless");
+switch (chr_code%unless_code) {
+  case if_cat_code: print_esc("ifcat");@+break;
+  case if_int_code: print_esc("ifnum");@+break;
+  case if_dim_code: print_esc("ifdim");@+break;
+  case if_odd_code: print_esc("ifodd");@+break;
+  case if_vmode_code: print_esc("ifvmode");@+break;
+  case if_hmode_code: print_esc("ifhmode");@+break;
+  case if_mmode_code: print_esc("ifmmode");@+break;
+  case if_inner_code: print_esc("ifinner");@+break;
+  case if_void_code: print_esc("ifvoid");@+break;
+  case if_hbox_code: print_esc("ifhbox");@+break;
+  case if_vbox_code: print_esc("ifvbox");@+break;
+  case ifx_code: print_esc("ifx");@+break;
+  case if_eof_code: print_esc("ifeof");@+break;
+  case if_true_code: print_esc("iftrue");@+break;
+  case if_false_code: print_esc("iffalse");@+break;
+  case if_case_code: print_esc("ifcase");@+break;
+  @/@<Cases of |if_test| for |print_cmd_chr|@>@/
+  default:print_esc("if");
+  }
+} @+break;
+
+@ Conditions can be inside conditions, and this nesting has a stack
+that is independent of the |save_stack|.
+
+Four global variables represent the top of the condition stack:
+|cond_ptr| points to pushed-down entries, if any; |if_limit| specifies
+the largest code of a |fi_or_else| command that is syntactically legal;
+|cur_if| is the name of the current type of conditional; and |if_line|
+is the line number at which it began.
+
+If no conditions are currently in progress, the condition stack has the
+special state |cond_ptr==null|, |if_limit==normal|, |cur_if==0|, |if_line==0|.
+Otherwise |cond_ptr| points to a two-word node; the |type|, |subtype|, and
+|link| fields of the first word contain |if_limit|, |cur_if|, and
+|cond_ptr| at the next level, and the second word contains the
+corresponding |if_line|.
+
+ at d if_node_size 2 /*number of words in stack entry for conditionals*/
+ at d if_line_field(A) mem[A+1].i
+ at d if_code 1 /*code for \.{\\if...} being evaluated*/
+ at d fi_code 2 /*code for \.{\\fi}*/
+ at d else_code 3 /*code for \.{\\else}*/
+ at d or_code 4 /*code for \.{\\or}*/
+
+@<Glob...@>=
+static pointer @!cond_ptr; /*top of the condition stack*/
+static int @!if_limit; /*upper bound on |fi_or_else| codes*/
+static small_number @!cur_if; /*type of conditional being worked on*/
+static int @!if_line; /*line where that conditional began*/
+
+@ @<Set init...@>=
+cond_ptr=null;if_limit=normal;cur_if=0;if_line=0;
+
+@ @<Put each...@>=
+primitive("fi", fi_or_else, fi_code);
+@!@:fi\_}{\.{\\fi} primitive@>
+text(frozen_fi)=text(cur_val);eqtb[frozen_fi]=eqtb[cur_val];
+primitive("or", fi_or_else, or_code);
+@!@:or\_}{\.{\\or} primitive@>
+primitive("else", fi_or_else, else_code);
+@!@:else\_}{\.{\\else} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case fi_or_else: if (chr_code==fi_code) print_esc("fi");
+  else if (chr_code==or_code) print_esc("or");
+  else print_esc("else");@+break;
+
+@ When we skip conditional text, we keep track of the line number
+where skipping began, for use in error messages.
+
+@<Glob...@>=
+static int @!skip_line; /*skipping began here*/
+
+@ Here is a procedure that ignores text until coming to an \.{\\or},
+\.{\\else}, or \.{\\fi} at the current level of $\.{\\if}\ldots\.{\\fi}$
+nesting. After it has acted, |cur_chr| will indicate the token that
+was found, but |cur_tok| will not be set (because this makes the
+procedure run faster).
+
+ at p static void pass_text(void)
+{@+
+int l; /*level of $\.{\\if}\ldots\.{\\fi}$ nesting*/
+small_number @!save_scanner_status; /*|scanner_status| upon entry*/
+save_scanner_status=scanner_status;scanner_status=skipping;l=0;
+skip_line=line;
+loop at +{@+get_next();
+  if (cur_cmd==fi_or_else)
+    {@+if (l==0) goto done;
+    if (cur_chr==fi_code) decr(l);
+    }
+  else if (cur_cmd==if_test) incr(l);
+  }
+done: scanner_status=save_scanner_status;
+if (tracing_ifs > 0) show_cur_cmd_chr();
+}
+
+@ When we begin to process a new \.{\\if}, we set |if_limit=if_code|; then
+if\/ \.{\\or} or \.{\\else} or \.{\\fi} occurs before the current \.{\\if}
+condition has been evaluated, \.{\\relax} will be inserted.
+For example, a sequence of commands like `\.{\\ifvoid1\\else...\\fi}'
+would otherwise require something after the `\.1'.
+
+@<Push the condition stack@>=
+{@+p=get_node(if_node_size);link(p)=cond_ptr;type(p)=if_limit;
+subtype(p)=cur_if;if_line_field(p)=if_line;
+cond_ptr=p;cur_if=cur_chr;if_limit=if_code;if_line=line;
+}
+
+@ @<Pop the condition stack@>=
+{@+if (if_stack[in_open]==cond_ptr) if_warning();
+   /*conditionals possibly not properly nested with files*/
+p=cond_ptr;if_line=if_line_field(p);
+cur_if=subtype(p);if_limit=type(p);cond_ptr=link(p);
+free_node(p, if_node_size);
+}
+
+@ Here's a procedure that changes the |if_limit| code corresponding to
+a given value of |cond_ptr|.
+
+ at p static void change_if_limit(small_number @!l, pointer @!p)
+{@+
+pointer q;
+if (p==cond_ptr) if_limit=l; /*that's the easy case*/
+else{@+q=cond_ptr;
+  loop at +{@+if (q==null) confusion("if");
+@:this can't happen if}{\quad if@>
+    if (link(q)==p)
+      {@+type(q)=l;return;
+      }
+    q=link(q);
+    }
+  }
+}
+
+@ A condition is started when the |expand| procedure encounters
+an |if_test| command; in that case |expand| reduces to |conditional|,
+which is a recursive procedure.
+@^recursion@>
+
+ at p static void conditional(void)
+{@+
+bool b; /*is the condition true?*/
+int @!r; /*relation to be evaluated*/
+int @!m, @!n; /*to be tested against the second operand*/
+pointer @!p, @!q; /*for traversing token lists in \.{\\ifx} tests*/
+small_number @!save_scanner_status; /*|scanner_status| upon entry*/
+pointer @!save_cond_ptr; /*|cond_ptr| corresponding to this conditional*/
+small_number @!this_if; /*type of this conditional*/
+bool @!is_unless; /*was this if preceded by `\.{\\unless}' ?*/
+if (tracing_ifs > 0) if (tracing_commands <= 1) show_cur_cmd_chr();
+@<Push the condition stack@>;@+save_cond_ptr=cond_ptr;
+is_unless=(cur_chr >= unless_code);this_if=cur_chr%unless_code;@/
+@<Either process \.{\\ifcase} or set |b| to the value of a boolean condition@>;
+if (is_unless) b=!b;
+if (tracing_commands > 1) @<Display the value of |b|@>;
+if (b)
+  {@+change_if_limit(else_code, save_cond_ptr);
+  return; /*wait for \.{\\else} or \.{\\fi}*/
+  }
+@<Skip to \.{\\else} or \.{\\fi}, then |goto common_ending|@>;
+common_ending: if (cur_chr==fi_code) @<Pop the condition stack@>@;
+else if_limit=fi_code; /*wait for \.{\\fi}*/
+}
+
+@ In a construction like `\.{\\if\\iftrue abc\\else d\\fi}', the first
+\.{\\else} that we come to after learning that the \.{\\if} is false is
+not the \.{\\else} we're looking for. Hence the following curious
+logic is needed.
+
+@ @<Skip to \.{\\else} or \.{\\fi}...@>=
+loop at +{@+pass_text();
+  if (cond_ptr==save_cond_ptr)
+    {@+if (cur_chr!=or_code) goto common_ending;
+    print_err("Extra ");print_esc("or");
+ at .Extra \\or@>
+    help1("I'm ignoring this; it doesn't match any \\if.");
+    error();
+    }
+  else if (cur_chr==fi_code) @<Pop the condition stack@>;
+  }
+
+@ @<Either process \.{\\ifcase} or set |b|...@>=
+switch (this_if) {
+case if_char_code: case if_cat_code: @<Test if two characters match@>@;@+break;
+case if_int_code: case if_dim_code: @<Test relation between integers or dimensions@>@;@+break;
+case if_odd_code: @<Test if an integer is odd@>@;@+break;
+case if_vmode_code: b=(abs(mode)==vmode);@+break;
+case if_hmode_code: b=(abs(mode)==hmode);@+break;
+case if_mmode_code: b=(abs(mode)==mmode);@+break;
+case if_inner_code: b=(mode < 0);@+break;
+case if_void_code: case if_hbox_code: case if_vbox_code: @<Test box register status@>@;@+break;
+case ifx_code: @<Test if two tokens match@>@;@+break;
+case if_eof_code: {@+scan_four_bit_int();b=(read_open[cur_val]==closed);
+  } @+break;
+case if_true_code: b=true;@+break;
+case if_false_code: b=false;@+break;
+@/@<Cases for |conditional|@>@/
+case if_case_code: @<Select the appropriate case and |return| or |goto common_ending|@>;
+}  /*there are no other cases*/
+
+@ @<Display the value of |b|@>=
+{@+begin_diagnostic();
+if (b) print("{true}");@+else print("{false}");
+end_diagnostic(false);
+}
+
+@ Here we use the fact that |'<'|, |'='|, and |'>'| are consecutive ASCII
+codes.
+@^ASCII code@>
+
+@<Test relation between integers or dimensions@>=
+{@+if (this_if==if_int_code) scan_int();@+else scan_normal_dimen;
+n=cur_val;@<Get the next non-blank non-call...@>;
+if ((cur_tok >= other_token+'<')&&(cur_tok <= other_token+'>'))
+  r=cur_tok-other_token;
+else{@+print_err("Missing = inserted for ");
+ at .Missing = inserted@>
+  print_cmd_chr(if_test, this_if);
+  help1("I was expecting to see `<', `=', or `>'. Didn't.");
+  back_error();r='=';
+  }
+if (this_if==if_int_code) scan_int();@+else scan_normal_dimen;
+switch (r) {
+case '<': b=(n < cur_val);@+break;
+case '=': b=(n==cur_val);@+break;
+case '>': b=(n > cur_val);
+}
+}
+
+@ @<Test if an integer is odd@>=
+{@+scan_int();b=odd(cur_val);
+}
+
+@ @<Test box register status@>=
+{@+scan_register_num();fetch_box(p);
+if (this_if==if_void_code) b=(p==null);
+else if (p==null) b=false;
+else if (this_if==if_hbox_code) b=(type(p)==hlist_node);
+else b=(type(p)==vlist_node);
+}
+
+@ An active character will be treated as category 13 following
+\.{\\if\\noexpand} or following \.{\\ifcat\\noexpand}. We use the fact that
+active characters have the smallest tokens, among all control sequences.
+
+ at d get_x_token_or_active_char @t@>@;
+  {@+get_x_token();
+  if (cur_cmd==relax) if (cur_chr==no_expand_flag)
+    {@+cur_cmd=active_char;
+    cur_chr=cur_tok-cs_token_flag-active_base;
+    }
+  }
+
+@<Test if two characters match@>=
+{@+get_x_token_or_active_char;
+if ((cur_cmd > active_char)||(cur_chr > 255))  /*not a character*/
+  {@+m=relax;n=256;
+  }
+else{@+m=cur_cmd;n=cur_chr;
+  }
+get_x_token_or_active_char;
+if ((cur_cmd > active_char)||(cur_chr > 255))
+  {@+cur_cmd=relax;cur_chr=256;
+  }
+if (this_if==if_char_code) b=(n==cur_chr);@+else b=(m==cur_cmd);
+}
+
+@ Note that `\.{\\ifx}' will declare two macros different if one is \\{long}
+or \\{outer} and the other isn't, even though the texts of the macros are
+the same.
+
+We need to reset |scanner_status|, since \.{\\outer} control sequences
+are allowed, but we might be scanning a macro definition or preamble.
+
+@<Test if two tokens match@>=
+{@+save_scanner_status=scanner_status;scanner_status=normal;
+get_next();n=cur_cs;p=cur_cmd;q=cur_chr;
+get_next();if (cur_cmd!=p) b=false;
+else if (cur_cmd < call) b=(cur_chr==q);
+else@<Test if two macro texts match@>;
+scanner_status=save_scanner_status;
+}
+
+@ Note also that `\.{\\ifx}' decides that macros \.{\\a} and \.{\\b} are
+different in examples like this:
+$$\vbox{\halign{\.{#}\hfil&\qquad\.{#}\hfil\cr
+  {}\\def\\a\{\\c\}&
+  {}\\def\\c\{\}\cr
+  {}\\def\\b\{\\d\}&
+  {}\\def\\d\{\}\cr}}$$
+
+@<Test if two macro texts match@>=
+{@+p=link(cur_chr);q=link(equiv(n)); /*omit reference counts*/
+if (p==q) b=true;
+else{@+while ((p!=null)&&(q!=null))
+    if (info(p)!=info(q)) p=null;
+    else{@+p=link(p);q=link(q);
+      }
+  b=((p==null)&&(q==null));
+  }
+}
+
+@ @<Select the appropriate case and |return| or |goto common_ending|@>=
+{@+scan_int();n=cur_val; /*|n| is the number of cases to pass*/
+if (tracing_commands > 1)
+  {@+begin_diagnostic();print("{case ");print_int(n);print_char('}');
+  end_diagnostic(false);
+  }
+while (n!=0)
+  {@+pass_text();
+  if (cond_ptr==save_cond_ptr)
+    if (cur_chr==or_code) decr(n);
+    else goto common_ending;
+  else if (cur_chr==fi_code) @<Pop the condition stack@>;
+  }
+change_if_limit(or_code, save_cond_ptr);
+return; /*wait for \.{\\or}, \.{\\else}, or \.{\\fi}*/
+}
+
+@ The processing of conditionals is complete except for the following
+code, which is actually part of |expand|. It comes into play when
+\.{\\or}, \.{\\else}, or \.{\\fi} is scanned.
+
+@<Terminate the current conditional and skip to \.{\\fi}@>=
+{@+if (tracing_ifs > 0) if (tracing_commands <= 1) show_cur_cmd_chr();
+if (cur_chr > if_limit)
+  if (if_limit==if_code) insert_relax(); /*condition not yet evaluated*/
+  else{@+print_err("Extra ");print_cmd_chr(fi_or_else, cur_chr);
+ at .Extra \\or@>
+ at .Extra \\else@>
+ at .Extra \\fi@>
+    help1("I'm ignoring this; it doesn't match any \\if.");
+    error();
+    }
+else{@+while (cur_chr!=fi_code) pass_text(); /*skip to \.{\\fi}*/
+  @<Pop the condition stack@>;
+  }
+}
+
+@* File names.
+It's time now to fret about file names.  Besides the fact that different
+operating systems treat files in different ways, we must cope with the
+fact that completely different naming conventions are used by different
+groups of people. The following programs show what is required for one
+particular operating system; similar routines for other systems are not
+difficult to devise.
+@^fingers@>
+@^system dependencies@>
+
+\TeX\ assumes that a file name has three parts: the name proper; its
+``extension''; and a ``file area'' where it is found in an external file
+system.  The extension of an input file or a write file is assumed to be
+`\.{.tex}' unless otherwise specified; it is `\.{.log}' on the
+transcript file that records each run of \TeX; it is `\.{.tfm}' on the font
+metric files that describe characters in the fonts \TeX\ uses; it is
+`\.{.dvi}' on the output files that specify typesetting information; and it
+is `\.{.fmt}' on the format files written by \.{INITEX} to initialize \TeX.
+The file area can be arbitrary on input files, but files are usually
+output to the user's current area.  If an input file cannot be
+found on the specified area, \TeX\ will look for it on a special system
+area; this special area is intended for commonly used input files like
+\.{webmac.tex}.
+
+Simple uses of \TeX\ refer only to file names that have no explicit
+extension or area. For example, a person usually says `\.{\\input} \.{paper}'
+or `\.{\\font\\tenrm} \.= \.{helvetica}' instead of `\.{\\input}
+\.{paper.new}' or `\.{\\font\\tenrm} \.= \.{<csd.knuth>test}'. Simple file
+names are best, because they make the \TeX\ source files portable;
+whenever a file name consists entirely of letters and digits, it should be
+treated in the same way by all implementations of \TeX. However, users
+need the ability to refer to other files in their environment, especially
+when responding to error messages concerning unopenable files; therefore
+we want to let them use the syntax that appears in their favorite
+operating system.
+
+The following procedures don't allow spaces to be part of
+file names; but some users seem to like names that are spaced-out.
+System-dependent changes to allow such things should probably
+be made with reluctance, and only when an entire file name that
+includes spaces is ``quoted'' somehow.
+
+@ In order to isolate the system-dependent aspects of file names, the
+@^system dependencies@>
+system-independent parts of \TeX\ are expressed in terms
+of three system-dependent
+procedures called |begin_name|, |more_name|, and |end_name|. In
+essence, if the user-specified characters of the file name are $c_1\ldots c_n$,
+the system-independent driver program does the operations
+$$|begin_name|;\,|more_name|(c_1);\,\ldots\,;\,|more_name|(c_n);
+\,|end_name|.$$
+These three procedures communicate with each other via global variables.
+Afterwards the file name will appear in the string pool as three strings
+called |cur_name|\penalty10000\hskip-.05em,
+|cur_area|, and |cur_ext|; the latter two are null (i.e.,
+|""|), unless they were explicitly specified by the user.
+
+Actually the situation is slightly more complicated, because \TeX\ needs
+to know when the file name ends. The |more_name| routine is a function
+(with side effects) that returns |true| on the calls |more_name|$(c_1)$,
+\dots, |more_name|$(c_{n-1})$. The final call |more_name|$(c_n)$
+returns |false|; or, it returns |true| and the token following $c_n$ is
+something like `\.{\\hbox}' (i.e., not a character). In other words,
+|more_name| is supposed to return |true| unless it is sure that the
+file name has been completely scanned; and |end_name| is supposed to be able
+to finish the assembly of |cur_name|, |cur_area|, and |cur_ext| regardless of
+whether $|more_name|(c_n)$ returned |true| or |false|.
+
+@<Glob...@>=
+static str_number @!cur_name; /*name of file just scanned*/
+static char *@!cur_area; /*file area just scanned, or \.{""}*/
+static char *@!cur_ext; /*file extension just scanned, or \.{""}*/
+
+@ The file names we shall deal with for illustrative purposes have the
+following structure:  If the name contains `\.>' or `\.:', the file area
+consists of all characters up to and including the final such character;
+otherwise the file area is null.  If the remaining file name contains
+`\..', the file extension consists of all such characters from the first
+remaining `\..' to the end, otherwise the file extension is null.
+@^system dependencies@>
+
+We can scan such file names easily by using two global variables that keep track
+of the occurrences of area and extension delimiters:
+
+@<Glob...@>=
+static pool_pointer @!area_delimiter; /*the most recent `\.>' or `\.:', if any*/
+static pool_pointer @!ext_delimiter; /*the relevant `\..', if any*/
+static int @!cur_file_name_length;
+
+@ Input files that can't be found in the user's area may appear in a standard
+system area called |TEX_area|. Font metric files whose areas are not given
+explicitly are assumed to appear in a standard system area called
+|TEX_font_area|.  These system area names will, of course, vary from place
+to place.
+@^system dependencies@>
+
+ at d TEX_area "TeXinputs/"
+ at .TeXinputs@>
+ at d TEX_font_area "TeXfonts/"
+ at .TeXfonts@>
+
+@ Here now is the first of the system-dependent routines for file name scanning.
+@^system dependencies@>
+
+The filename is scanned into |cur_file_name|; |cur_ext| and |cur_aire|
+will point into this buffer.
+
+ at d MAX_CUR_FILE_NAME 1024
+
+ at p static char cur_file_name[MAX_CUR_FILE_NAME+1];
+static void begin_name(void)
+{@+area_delimiter=ext_delimiter=cur_file_name_length=0;
+}
+
+@ And here's the second. The string pool might change as the file name is
+being scanned, since a new \.{\\csname} might be entered; therefore we keep
+|area_delimiter| and |ext_delimiter| relative to the beginning of the current
+string, instead of assigning an absolute address like |pool_ptr| to them.
+@^system dependencies@>
+
+ at p static bool more_name(ASCII_code @!c)
+{@+if (c==' ') return false;
+  if (cur_file_name_length>= MAX_CUR_FILE_NAME )
+  { overflow("file name length", MAX_CUR_FILE_NAME);
+    return false;
+  }
+  else
+  { /*contribute |c| to the current string*/
+    cur_file_name[cur_file_name_length]=c;
+    if (c=='/')
+    {@+area_delimiter=cur_file_name_length;ext_delimiter=0;
+    }
+    else if (c=='.') ext_delimiter=cur_file_name_length;
+    cur_file_name_length++;
+    return true;
+  }
+}
+
+@ The third.
+@^system dependencies@>
+
+ at p static void end_name(void)
+{@+int i=0;
+  if (str_ptr+1 > max_strings)
+  overflow("number of strings", max_strings-init_str_ptr);
+@:TeX capacity exceeded number of strings}{\quad number of strings@>
+cur_file_name[cur_file_name_length]=0;
+if (area_delimiter==0) cur_area=cur_file_name+cur_file_name_length;
+else @+cur_area=cur_file_name,i=area_delimiter+1;
+if (ext_delimiter==0) ext_delimiter=cur_file_name_length;
+cur_ext=cur_file_name+ext_delimiter;
+for (;i<ext_delimiter;i++) append_char(cur_file_name[i]);
+if (area_delimiter!=0) cur_file_name[area_delimiter+1]=0;
+cur_name=make_string();
+}
+
+static void set_cur_area_ext(str_number a, str_number e)
+{ int i;
+  if (length(a)+length(e)+2>=MAX_CUR_FILE_NAME)
+  { overflow("file name length", MAX_CUR_FILE_NAME);
+    return;
+  }
+  cur_file_name_length=0;
+  area_delimiter=0;
+  for(i=str_start[a]; i<str_start[a+1];i++) cur_file_name[cur_file_name_length++]=str_pool[i];
+  cur_file_name[cur_file_name_length++]=0;
+  cur_area=cur_file_name;
+  cur_ext=cur_file_name+cur_file_name_length;
+  for(i=str_start[e]; i<str_start[e+1];i++) cur_file_name[cur_file_name_length++]=str_pool[i];
+  cur_file_name[cur_file_name_length++]=0;
+}
+
+@ Conversely, here is a routine that takes three strings and prints a file
+name that might have produced them. (The routine is system dependent, because
+some operating systems put the file area last instead of first.)
+@^system dependencies@>
+
+@<Basic printing...@>=
+static void print_file_name(int @!n, char *@!a, char *@!e)
+{@+print(a);slow_print(n);print(e);
+}
+
+static void printn_file_name(int @!n, int @!a, int @!e)
+{@+slow_print(a);slow_print(n);slow_print(e);
+}
+
+@ Another system-dependent routine is needed to convert three internal
+\TeX\ strings
+into the |name_of_file| value that is used to open files. The present code
+allows both lowercase and uppercase letters in the file name.
+@^system dependencies@>
+
+ at d append_to_name(A) {@+c=A;incr(k);
+  if (k <= file_name_size) name_of_file[k]=xchr[c];
+  }
+
+ at p static void pack_file_name(str_number @!n, char *@!a, char *@!e)
+{@+int k; /*number of positions filled in |name_of_file|*/
+ASCII_code @!c; /*character being packed*/
+int @!j; /*index into |str_pool|*/
+k=0;
+while(*a!=0) append_to_name(so(*a++));
+for (j=str_start[n]; j<=str_start[n+1]-1; j++) append_to_name(so(str_pool[j]));
+while(*e!=0) append_to_name(so(*e++));
+if (k <= file_name_size) name_length=k;@+else name_length=file_name_size;
+name_of_file[name_length+1]=0;
+}
+
+
+@ The global variable |TEX_format_default| is no longer needed
+to supply the text for default system areas
+and extensions related to format files.
+
+@ Consequently there is no initialization of |TEX_format_default| either.
+
+@ And there is no need to check the length of |TEX_format_default|.
+
+@ The |format_extension|, however, is needed later on
+to create the format name from the job name.
+
+ at d format_extension ".fmt"
+
+@ This part of the program
+becomes active when a ``virgin'' \TeX\ is trying to get going, just after
+the preliminary initialization, or when the user is substituting another
+format file by typing `\.\&' after the initial `\.{**}' prompt.  The buffer
+contains the first line of input in |buffer[loc dotdot(last-1)]|, where
+|loc < last| and |buffer[loc]!=' '|.
+
+k\TeX\ uses the {\tt kpathsearch} library to implement access to files.
+To do so we declare |open_fmt_file| here and postpone the
+actual implementation.
+
+@<Declare the function called |open_fmt_file|@>=
+static bool open_fmt_file(void);
+
+@ Operating systems often make it possible to determine the exact name (and
+possible version number) of a file that has been opened. The following routine,
+which simply makes a \TeX\ string from the value of |name_of_file|, should
+ideally be changed to deduce the full name of file~|f|, which is the file
+most recently opened, if it is possible to do this in a \PASCAL\ program.
+@^system dependencies@>
+
+This routine might be called after string memory has overflowed, hence
+we dare not use `|str_room|'.
+
+ at p static str_number make_name_string(void)
+{@+int k; /*index into |name_of_file|*/
+if ((pool_ptr+name_length > pool_size)||(str_ptr==max_strings)||
+ (cur_length > 0))
+  return'?';
+else{@+for (k=1; k<=name_length; k++) append_char(xord[name_of_file[k]]);
+  return make_string();
+  }
+}
+static str_number a_make_name_string(alpha_file *f)
+{@+return make_name_string();
+}
+static str_number b_make_name_string(byte_file *f)
+{@+return make_name_string();
+}
+#ifdef @!INIT
+static str_number w_make_name_string(word_file *f)
+{@+return make_name_string();
+}
+#endif
+
+@ Now let's consider the ``driver''
+routines by which \TeX\ deals with file names
+in a system-independent manner.  First comes a procedure that looks for a
+file name in the input by calling |get_x_token| for the information.
+
+ at p static void scan_file_name(void)
+{@+
+name_in_progress=true;begin_name();
+@<Get the next non-blank non-call...@>;
+loop at +{@+if ((cur_cmd > other_char)||(cur_chr > 255))  /*not a character*/
+    {@+back_input();goto done;
+    }
+  if (!more_name(cur_chr)) goto done;
+  get_x_token();
+  }
+done: end_name();name_in_progress=false;
+}
+
+@ The global variable |name_in_progress| is used to prevent recursive
+use of |scan_file_name|, since the |begin_name| and other procedures
+communicate via global variables. Recursion would arise only by
+devious tricks like `\.{\\input\\input f}'; such attempts at sabotage
+must be thwarted. Furthermore, |name_in_progress| prevents \.{\\input}
+@^recursion@>
+from being initiated when a font size specification is being scanned.
+
+Another global variable, |job_name|, contains the file name that was first
+\.{\\input} by the user. This name is extended by `\.{.log}' and `\.{.dvi}'
+and `\.{.fmt}' in the names of \TeX's output files.
+
+@<Glob...@>=
+static bool @!name_in_progress; /*is a file name being scanned?*/
+static str_number @!job_name; /*principal file name*/
+static bool @!log_opened; /*has the transcript file been opened?*/
+
+@ Initially |job_name==0|; it becomes nonzero as soon as the true name is known.
+We have |job_name==0| if and only if the `\.{log}' file has not been opened,
+except of course for a short time just after |job_name| has become nonzero.
+
+@<Initialize the output...@>=
+job_name=0;name_in_progress=false;log_opened=false;
+
+@ Here is a routine that manufactures the output file names, assuming that
+|job_name!=0|. It ignores and changes the current settings of |cur_area|
+and |cur_ext|.
+
+ at d pack_cur_name pack_file_name(cur_name, cur_area, cur_ext)
+
+ at p static void pack_job_name(char *@!s) /*|s==".log"|, |".dvi"|, or
+  |format_extension|*/
+{@+cur_area="";cur_ext=s;
+cur_name=job_name;pack_cur_name;
+}
+
+@ If some trouble arises when \TeX\ tries to open a file, the following
+routine calls upon the user to supply another file name. Parameter~|s|
+is used in the error message to identify the type of file; parameter~|e|
+is the default extension if none is given. Upon exit from the routine,
+variables |cur_name|, |cur_area|, |cur_ext|, and |name_of_file| are
+ready for another attempt at file opening.
+
+ at p static void prompt_file_name(char *@!s, char *@!e)
+{@+
+int k; /*index into |buffer|*/
+if (interaction==scroll_mode) wake_up_terminal;
+if (strcmp(s,"input file name")==0) print_err("I can't find file `");
+ at .I can't find file x@>
+else print_err("I can't write on file `");
+ at .I can't write on file x@>
+print_file_name(cur_name, cur_area, cur_ext);print("'.");
+if (strcmp(e,".tex")==0) show_context();
+print_nl("Please type another ");print(s);
+ at .Please type...@>
+if (interaction < scroll_mode)
+  fatal_error("*** (job aborted, file error in nonstop mode)");
+ at .job aborted, file error...@>
+clear_terminal;prompt_input(": ");@<Scan file name in the buffer@>;
+if (cur_ext[0]==0) cur_ext=e;
+pack_cur_name;
+}
+
+@ @<Scan file name in the buffer@>=
+{@+begin_name();k=first;
+while ((buffer[k]==' ')&&(k < last)) incr(k);
+loop at +{@+if (k==last) goto done;
+  if (!more_name(buffer[k])) goto done;
+  incr(k);
+  }
+done: end_name();
+}
+
+@ Here's an example of how these conventions are used. Whenever it is time to
+ship out a box of stuff, we shall use the macro |ensure_dvi_open|.
+
+ at d ensure_dvi_open if (output_file_name==0)
+  {@+if (job_name==0) open_log_file();
+  pack_job_name(".dvi");
+  while (!b_open_out(&dvi_file))
+    prompt_file_name("file name for output",".dvi");
+  output_file_name=b_make_name_string(&dvi_file);
+  }
+
+@<Glob...@>=
+static byte_file @!dvi_file; /*the device-independent output goes here*/
+static str_number @!output_file_name; /*full name of the output file*/
+static str_number @!log_name; /*full name of the log file*/
+
+@ @<Initialize the output...@>=output_file_name=0;
+
+@ The |open_log_file| routine is used to open the transcript file and to help
+it catch up to what has previously been printed on the terminal.
+
+ at p static void open_log_file(void)
+{@+int old_setting; /*previous |selector| setting*/
+int @!k; /*index into |months| and |buffer|*/
+int @!l; /*end of first input line*/
+char @!months[]=" JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"; /*abbreviations of month names*/
+old_setting=selector;
+if (job_name==0) job_name=s_no(c_job_name?c_job_name:"texput"); /* k\TeX\ */
+ at .texput@>
+pack_job_name(".log");
+while (!a_open_out(&log_file)) @<Try to get a different log file name@>;
+log_name=a_make_name_string(&log_file);
+selector=log_only;log_opened=true;
+@<Print the banner line, including the date and time@>;
+input_stack[input_ptr]=cur_input; /*make sure bottom level is in memory*/
+print_nl("**");
+ at .**@>
+l=input_stack[0].limit_field; /*last position of first line*/
+if (buffer[l]==end_line_char) decr(l);
+for (k=1; k<=l; k++) printn(buffer[k]);
+print_ln(); /*now the transcript file contains the first line of input*/
+selector=old_setting+2; /*|log_only| or |term_and_log|*/
+}
+
+@ Sometimes |open_log_file| is called at awkward moments when \TeX\ is
+unable to print error messages or even to |show_context|.
+The |prompt_file_name| routine can result in a |fatal_error|, but the |error|
+routine will not be invoked because |log_opened| will be false.
+
+The normal idea of |batch_mode| is that nothing at all should be written
+on the terminal. However, in the unusual case that
+no log file could be opened, we make an exception and allow
+an explanatory message to be seen.
+
+Incidentally, the program always refers to the log file as a `\.{transcript
+file}', because some systems cannot use the extension `\.{.log}' for
+this file.
+
+@<Try to get a different log file name@>=
+{@+selector=term_only;
+prompt_file_name("transcript file name",".log");
+}
+
+@ @<Print the banner...@>=
+{@+wlog("%s",banner);
+slow_print(format_ident);print("  ");
+print_int(sys_day);print_char(' ');
+for (k=3*sys_month-2; k<=3*sys_month; k++) wlog("%c",months[k]);
+print_char(' ');print_int(sys_year);print_char(' ');
+print_two(sys_time/60);print_char(':');print_two(sys_time%60);
+if (eTeX_ex)
+  {@+;wlog_cr;wlog("entering extended mode");
+  }
+if (Prote_ex)
+  {@+;wlog_cr;wlog("entering Prote mode");
+  }
+}
+
+@ Let's turn now to the procedure that is used to initiate file reading
+when an `\.{\\input}' command is being processed.
+Beware: For historic reasons, this code foolishly conserves a tiny bit
+of string pool space; but that can confuse the interactive `\.E' option.
+@^system dependencies@>
+
+ at p static void start_input(void) /*\TeX\ will \.{\\input} something*/
+{@+
+scan_file_name(); /*set |cur_name| to desired file name*/
+if (cur_ext[0]==0) cur_ext=".tex";
+pack_cur_name;
+loop at +{@+begin_file_reading(); /*set up |cur_file| and new level of input*/
+  if (a_open_in(&cur_file)) goto done;
+  end_file_reading(); /*remove the level that didn't work*/
+  prompt_file_name("input file name",".tex");
+  }
+done: name=a_make_name_string(&cur_file);@/
+source_filename_stack[in_open]=name; /* k\TeX\ */
+if (job_name==0)
+  {@+if (c_job_name==NULL) job_name=cur_name;
+     else job_name=s_no(c_job_name); open_log_file(); /* k\TeX\ */
+  }  /*|open_log_file| doesn't |show_context|, so |limit|
+    and |loc| needn't be set to meaningful values yet*/
+if (term_offset+length(name) > max_print_line-2) print_ln();
+else if ((term_offset > 0)||(file_offset > 0)) print_char(' ');
+print_char('(');incr(open_parens);slow_print(name);update_terminal;
+state=new_line;
+if (name==str_ptr-1)  /*conserve string pool space (but see note above)*/
+  {@+flush_string;name=cur_name;
+  }
+@<Read the first line of the new file@>;
+}
+
+@ Here we have to remember to tell the |input_ln| routine not to
+start with a |get|. If the file is empty, it is considered to
+contain a single blank line.
+@^system dependencies@>
+@^empty line at end of file@>
+
+@<Read the first line...@>=
+{@+line=1;
+if (input_ln(&cur_file, false)) do_nothing;
+firm_up_the_line();
+if (end_line_char_inactive) decr(limit);
+else buffer[limit]=end_line_char;
+first=limit+1;loc=start;
+}
+
+@* Font metric data.
+\TeX\ gets its knowledge about fonts from font metric files, also called
+\.{TFM} files; the `\.T' in `\.{TFM}' stands for \TeX,
+but other programs know about them too.
+@:TFM files}{\.{TFM} files@>
+@^font metric files@>
+
+The information in a \.{TFM} file appears in a sequence of 8-bit bytes.
+Since the number of bytes is always a multiple of 4, we could
+also regard the file as a sequence of 32-bit words, but \TeX\ uses the
+byte interpretation. The format of \.{TFM} files was designed by
+Lyle Ramshaw in 1980. The intent is to convey a lot of different kinds
+@^Ramshaw, Lyle Harold@>
+of information in a compact but useful form.
+
+@<Glob...@>=
+static byte_file @!tfm_file;
+
+@ The first 24 bytes (6 words) of a \.{TFM} file contain twelve 16-bit
+integers that give the lengths of the various subsequent portions
+of the file. These twelve integers are, in order:
+$$\vbox{\halign{\hfil#&$\null=\null$#\hfil\cr
+|lf|&length of the entire file, in words;\cr
+|lh|&length of the header data, in words;\cr
+|bc|&smallest character code in the font;\cr
+|ec|&largest character code in the font;\cr
+|nw|&number of words in the width table;\cr
+|nh|&number of words in the height table;\cr
+|nd|&number of words in the depth table;\cr
+|ni|&number of words in the italic correction table;\cr
+|nl|&number of words in the lig/kern table;\cr
+|nk|&number of words in the kern table;\cr
+|ne|&number of words in the extensible character table;\cr
+|np|&number of font parameter words.\cr}}$$
+They are all nonnegative and less than $2^{15}$. We must have |bc-1 <= ec <= 255|,
+and
+$$\hbox{|lf==6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np|.}$$
+Note that a font may contain as many as 256 characters (if |bc==0| and |ec==255|),
+and as few as 0 characters (if |bc==ec+1|).
+
+Incidentally, when two or more 8-bit bytes are combined to form an integer of
+16 or more bits, the most significant bytes appear first in the file.
+This is called BigEndian order.
+@!@^BigEndian order@>
+
+@ The rest of the \.{TFM} file may be regarded as a sequence of ten data
+arrays having the informal specification
+$$\def\arr$[#1]#2${\&{array} $[#1]$ \&{of} #2}
+\def\PB#1{\arr#1}
+\vbox{\halign{\hfil\\{#}&$\,:\,$#\hfil\cr
+header&|[0 dotdot lh-1]@t\\{stuff}@>|\cr
+char\_info&|[bc dotdot ec]char_info_word|\cr
+width&|[0 dotdot nw-1]fix_word|\cr
+height&|[0 dotdot nh-1]fix_word|\cr
+depth&|[0 dotdot nd-1]fix_word|\cr
+italic&|[0 dotdot ni-1]fix_word|\cr
+lig\_kern&|[0 dotdot nl-1]lig_kern_command|\cr
+kern&|[0 dotdot nk-1]fix_word|\cr
+exten&|[0 dotdot ne-1]extensible_recipe|\cr
+param&|[1 dotdot np]fix_word|\cr}}$$
+The most important data type used here is a |@!fix_word|, which is
+a 32-bit representation of a binary fraction. A |fix_word| is a signed
+quantity, with the two's complement of the entire word used to represent
+negation. Of the 32 bits in a |fix_word|, exactly 12 are to the left of the
+binary point; thus, the largest |fix_word| value is $2048-2^{-20}$, and
+the smallest is $-2048$. We will see below, however, that all but two of
+the |fix_word| values must lie between $-16$ and $+16$.
+
+@ The first data array is a block of header information, which contains
+general facts about the font. The header must contain at least two words,
+|header[0]| and |header[1]|, whose meaning is explained below.
+Additional header information of use to other software routines might
+also be included, but \TeX82 does not need to know about such details.
+For example, 16 more words of header information are in use at the Xerox
+Palo Alto Research Center; the first ten specify the character coding
+scheme used (e.g., `\.{XEROX text}' or `\.{TeX math symbols}'), the next five
+give the font identifier (e.g., `\.{HELVETICA}' or `\.{CMSY}'), and the
+last gives the ``face byte.'' The program that converts \.{DVI} files
+to Xerox printing format gets this information by looking at the \.{TFM}
+file, which it needs to read anyway because of other information that
+is not explicitly repeated in \.{DVI}~format.
+
+\yskip\hang|header[0]| is a 32-bit check sum that \TeX\ will copy into
+the \.{DVI} output file. Later on when the \.{DVI} file is printed,
+possibly on another computer, the actual font that gets used is supposed
+to have a check sum that agrees with the one in the \.{TFM} file used by
+\TeX. In this way, users will be warned about potential incompatibilities.
+(However, if the check sum is zero in either the font file or the \.{TFM}
+file, no check is made.)  The actual relation between this check sum and
+the rest of the \.{TFM} file is not important; the check sum is simply an
+identification number with the property that incompatible fonts almost
+always have distinct check sums.
+@^check sum@>
+
+\yskip\hang|header[1]| is a |fix_word| containing the design size of
+the font, in units of \TeX\ points. This number must be at least 1.0; it is
+fairly arbitrary, but usually the design size is 10.0 for a ``10 point''
+font, i.e., a font that was designed to look best at a 10-point size,
+whatever that really means. When a \TeX\ user asks for a font
+`\.{at} $\delta$ \.{pt}', the effect is to override the design size
+and replace it by $\delta$, and to multiply the $x$ and~$y$ coordinates
+of the points in the font image by a factor of $\delta$ divided by the
+design size.  {\sl All other dimensions in the\/ \.{TFM} file are
+|fix_word|\kern-1pt\ numbers in design-size units}, with the exception of
+|param[1]| (which denotes the slant ratio). Thus, for example, the value
+of |param[6]|, which defines the \.{em} unit, is often the |fix_word| value
+$2^{20}=1.0$, since many fonts have a design size equal to one em.
+The other dimensions must be less than 16 design-size units in absolute
+value; thus, |header[1]| and |param[1]| are the only |fix_word|
+entries in the whole \.{TFM} file whose first byte might be something
+besides 0 or 255.
+
+@ Next comes the |char_info| array, which contains one |@!char_info_word|
+per character. Each word in this part of the file contains six fields
+packed into four bytes as follows.
+
+\yskip\hang first byte: |@!width_index| (8 bits)\par
+\hang second byte: |@!height_index| (4 bits) times 16, plus |@!depth_index|
+  (4~bits)\par
+\hang third byte: |@!italic_index| (6 bits) times 4, plus |@!tag|
+  (2~bits)\par
+\hang fourth byte: |@!rem| (8 bits)\par
+\yskip\noindent
+The actual width of a character is \\{width}|[width_index]|, in design-size
+units; this is a device for compressing information, since many characters
+have the same width. Since it is quite common for many characters
+to have the same height, depth, or italic correction, the \.{TFM} format
+imposes a limit of 16 different heights, 16 different depths, and
+64 different italic corrections.
+
+@!@^italic correction@>
+The italic correction of a character has two different uses.
+(a)~In ordinary text, the italic correction is added to the width only if
+the \TeX\ user specifies `\.{\\/}' after the character.
+(b)~In math formulas, the italic correction is always added to the width,
+except with respect to the positioning of subscripts.
+
+Incidentally, the relation $\\{width}[0]=\\{height}[0]=\\{depth}[0]=
+\\{italic}[0]=0$ should always hold, so that an index of zero implies a
+value of zero.  The |width_index| should never be zero unless the
+character does not exist in the font, since a character is valid if and
+only if it lies between |bc| and |ec| and has a nonzero |width_index|.
+
+@ The |tag| field in a |char_info_word| has four values that explain how to
+interpret the |rem| field.
+
+\yskip\hangg|tag==0| (|no_tag|) means that |rem| is unused.\par
+\hangg|tag==1| (|lig_tag|) means that this character has a ligature/kerning
+program starting at position |rem| in the |lig_kern| array.\par
+\hangg|tag==2| (|list_tag|) means that this character is part of a chain of
+characters of ascending sizes, and not the largest in the chain.  The
+|rem| field gives the character code of the next larger character.\par
+\hangg|tag==3| (|ext_tag|) means that this character code represents an
+extensible character, i.e., a character that is built up of smaller pieces
+so that it can be made arbitrarily large. The pieces are specified in
+|@!exten[rem]|.\par
+\yskip\noindent
+Characters with |tag==2| and |tag==3| are treated as characters with |tag==0|
+unless they are used in special circumstances in math formulas. For example,
+the \.{\\sum} operation looks for a |list_tag|, and the \.{\\left}
+operation looks for both |list_tag| and |ext_tag|.
+
+ at d no_tag 0 /*vanilla character*/
+ at d lig_tag 1 /*character has a ligature/kerning program*/
+ at d list_tag 2 /*character has a successor in a charlist*/
+ at d ext_tag 3 /*character is extensible*/
+
+@ The |lig_kern| array contains instructions in a simple programming language
+that explains what to do for special letter pairs. Each word in this array is a
+|@!lig_kern_command| of four bytes.
+
+\yskip\hang first byte: |skip_byte|, indicates that this is the final program
+  step if the byte is 128 or more, otherwise the next step is obtained by
+  skipping this number of intervening steps.\par
+\hang second byte: |next_char|, ``if |next_char| follows the current character,
+  then perform the operation and stop, otherwise continue.''\par
+\hang third byte: |op_byte|, indicates a ligature step if less than~128,
+  a kern step otherwise.\par
+\hang fourth byte: |rem|.\par
+\yskip\noindent
+In a kern step, an
+additional space equal to |kern[256*(op_byte-128)+rem]| is inserted
+between the current character and |next_char|. This amount is
+often negative, so that the characters are brought closer together
+by kerning; but it might be positive.
+
+There are eight kinds of ligature steps, having |op_byte| codes $4a+2b+c$ where
+$0\le a\le b+c$ and $0\le b,c\le1$. The character whose code is
+|rem| is inserted between the current character and |next_char|;
+then the current character is deleted if $b=0$, and |next_char| is
+deleted if $c=0$; then we pass over $a$~characters to reach the next
+current character (which may have a ligature/kerning program of its own).
+
+If the very first instruction of the |lig_kern| array has |skip_byte==255|,
+the |next_char| byte is the so-called boundary character of this font;
+the value of |next_char| need not lie between |bc| and~|ec|.
+If the very last instruction of the |lig_kern| array has |skip_byte==255|,
+there is a special ligature/kerning program for a boundary character at the
+left, beginning at location |256*op_byte+rem|.
+The interpretation is that \TeX\ puts implicit boundary characters
+before and after each consecutive string of characters from the same font.
+These implicit characters do not appear in the output, but they can affect
+ligatures and kerning.
+
+If the very first instruction of a character's |lig_kern| program has
+|skip_byte > 128|, the program actually begins in location
+|256*op_byte+rem|. This feature allows access to large |lig_kern|
+arrays, because the first instruction must otherwise
+appear in a location | <= 255|.
+
+Any instruction with |skip_byte > 128| in the |lig_kern| array must satisfy
+the condition
+$$\hbox{|256*op_byte+rem < nl|.}$$
+If such an instruction is encountered during
+normal program execution, it denotes an unconditional halt; no ligature
+or kerning command is performed.
+
+ at d stop_flag qi(128) /*value indicating `\.{STOP}' in a lig/kern program*/
+ at d kern_flag qi(128) /*op code for a kern step*/
+ at d skip_byte(A) A.b0
+ at d next_char(A) A.b1
+ at d op_byte(A) A.b2
+ at d rem_byte(A) A.b3
+
+@ Extensible characters are specified by an |@!extensible_recipe|, which
+consists of four bytes called |@!top|, |@!mid|, |@!bot|, and |@!rep| (in this
+order). These bytes are the character codes of individual pieces used to
+build up a large symbol.  If |top|, |mid|, or |bot| are zero, they are not
+present in the built-up result. For example, an extensible vertical line is
+like an extensible bracket, except that the top and bottom pieces are missing.
+
+Let $T$, $M$, $B$, and $R$ denote the respective pieces, or an empty box
+if the piece isn't present. Then the extensible characters have the form
+$TR^kMR^kB$ from top to bottom, for some |k >= 0|, unless $M$ is absent;
+in the latter case we can have $TR^kB$ for both even and odd values of~|k|.
+The width of the extensible character is the width of $R$; and the
+height-plus-depth is the sum of the individual height-plus-depths of the
+components used, since the pieces are butted together in a vertical list.
+
+ at d ext_top(A) A.b0 /*|top| piece in a recipe*/
+ at d ext_mid(A) A.b1 /*|mid| piece in a recipe*/
+ at d ext_bot(A) A.b2 /*|bot| piece in a recipe*/
+ at d ext_rep(A) A.b3 /*|rep| piece in a recipe*/
+
+@ The final portion of a \.{TFM} file is the |param| array, which is another
+sequence of |fix_word| values.
+
+\yskip\hang|param[1]==slant| is the amount of italic slant, which is used
+to help position accents. For example, |slant==.25| means that when you go
+up one unit, you also go .25 units to the right. The |slant| is a pure
+number; it's the only |fix_word| other than the design size itself that is
+not scaled by the design size.
+
+\hang|param[2]==space| is the normal spacing between words in text.
+Note that character |' '| in the font need not have anything to do with
+blank spaces.
+
+\hang|param[3]==space_stretch| is the amount of glue stretching between words.
+
+\hang|param[4]==space_shrink| is the amount of glue shrinking between words.
+
+\hang|param[5]==x_height| is the size of one ex in the font; it is also
+the height of letters for which accents don't have to be raised or lowered.
+
+\hang|param[6]==quad| is the size of one em in the font.
+
+\hang|param[7]==extra_space| is the amount added to |param[2]| at the
+ends of sentences.
+
+\yskip\noindent
+If fewer than seven parameters are present, \TeX\ sets the missing parameters
+to zero. Fonts used for math symbols are required to have
+additional parameter information, which is explained later.
+
+ at d slant_code 1
+ at d space_code 2
+ at d space_stretch_code 3
+ at d space_shrink_code 4
+ at d x_height_code 5
+ at d quad_code 6
+ at d extra_space_code 7
+
+@ So that is what \.{TFM} files hold. Since \TeX\ has to absorb such information
+about lots of fonts, it stores most of the data in a large array called
+|font_info|. Each item of |font_info| is a |memory_word|; the |fix_word|
+data gets converted into |scaled| entries, while everything else goes into
+words of type |four_quarters|.
+
+When the user defines \.{\\font\\f}, say, \TeX\ assigns an internal number
+to the user's font~\.{\\f}. Adding this number to |font_id_base| gives the
+|eqtb| location of a ``frozen'' control sequence that will always select
+the font.
+
+@<Types...@>=
+typedef uint8_t internal_font_number; /*|font| in a |char_node|*/
+typedef int32_t font_index; /*index into |font_info|*/
+
+@ Here now is the (rather formidable) array of font arrays.
+
+ at d non_char qi(256) /*a |halfword| code that can't match a real character*/
+ at d non_address 0 /*a spurious |bchar_label|*/
+
+@<Glob...@>=
+static memory_word @!font_info[font_mem_size+1];
+   /*the big collection of font data*/
+static font_index @!fmem_ptr; /*first unused word of |font_info|*/
+static internal_font_number @!font_ptr; /*largest internal font number in use*/
+static four_quarters @!font_check0[font_max-font_base+1], *const @!font_check = @!font_check0-font_base; /*check sum*/
+static scaled @!font_size0[font_max-font_base+1], *const @!font_size = @!font_size0-font_base; /*``at'' size*/
+static scaled @!font_dsize0[font_max-font_base+1], *const @!font_dsize = @!font_dsize0-font_base; /*``design'' size*/
+static font_index @!font_params0[font_max-font_base+1], *const @!font_params = @!font_params0-font_base; /*how many font
+  parameters are present*/
+static str_number @!font_name0[font_max-font_base+1], *const @!font_name = @!font_name0-font_base; /*name of the font*/
+static str_number @!font_area0[font_max-font_base+1], *const @!font_area = @!font_area0-font_base; /*area of the font*/
+static eight_bits @!font_bc0[font_max-font_base+1], *const @!font_bc = @!font_bc0-font_base;
+   /*beginning (smallest) character code*/
+static eight_bits @!font_ec0[font_max-font_base+1], *const @!font_ec = @!font_ec0-font_base;
+   /*ending (largest) character code*/
+static pointer @!font_glue0[font_max-font_base+1], *const @!font_glue = @!font_glue0-font_base;
+   /*glue specification for interword space, |null| if not allocated*/
+static bool @!font_used0[font_max-font_base+1], *const @!font_used = @!font_used0-font_base;
+   /*has a character from this font actually appeared in the output?*/
+static int @!hyphen_char0[font_max-font_base+1], *const @!hyphen_char = @!hyphen_char0-font_base;
+   /*current \.{\\hyphenchar} values*/
+static int @!skew_char0[font_max-font_base+1], *const @!skew_char = @!skew_char0-font_base;
+   /*current \.{\\skewchar} values*/
+static font_index @!bchar_label0[font_max-font_base+1], *const @!bchar_label = @!bchar_label0-font_base;
+   /*start of |lig_kern| program for left boundary character,
+  |non_address| if there is none*/
+static int16_t @!font_bchar0[font_max-font_base+1], *const @!font_bchar = @!font_bchar0-font_base;
+   /*boundary character, |non_char| if there is none*/
+static int16_t @!font_false_bchar0[font_max-font_base+1], *const @!font_false_bchar = @!font_false_bchar0-font_base;
+   /*|font_bchar| if it doesn't exist in the font, otherwise |non_char|*/
+
+@ Besides the arrays just enumerated, we have directory arrays that make it
+easy to get at the individual entries in |font_info|. For example, the
+|char_info| data for character |c| in font |f| will be in
+|font_info[char_base[f]+c].qqqq|; and if |w| is the |width_index|
+part of this word (the |b0| field), the width of the character is
+|font_info[width_base[f]+w].sc|. (These formulas assume that
+|min_quarterword| has already been added to |c| and to |w|, since \TeX\
+stores its quarterwords that way.)
+
+@<Glob...@>=
+static int @!char_base0[font_max-font_base+1], *const @!char_base = @!char_base0-font_base;
+   /*base addresses for |char_info|*/
+static int @!width_base0[font_max-font_base+1], *const @!width_base = @!width_base0-font_base;
+   /*base addresses for widths*/
+static int @!height_base0[font_max-font_base+1], *const @!height_base = @!height_base0-font_base;
+   /*base addresses for heights*/
+static int @!depth_base0[font_max-font_base+1], *const @!depth_base = @!depth_base0-font_base;
+   /*base addresses for depths*/
+static int @!italic_base0[font_max-font_base+1], *const @!italic_base = @!italic_base0-font_base;
+   /*base addresses for italic corrections*/
+static int @!lig_kern_base0[font_max-font_base+1], *const @!lig_kern_base = @!lig_kern_base0-font_base;
+   /*base addresses for ligature/kerning programs*/
+static int @!kern_base0[font_max-font_base+1], *const @!kern_base = @!kern_base0-font_base;
+   /*base addresses for kerns*/
+static int @!exten_base0[font_max-font_base+1], *const @!exten_base = @!exten_base0-font_base;
+   /*base addresses for extensible recipes*/
+static int @!param_base0[font_max-font_base+1], *const @!param_base = @!param_base0-font_base;
+   /*base addresses for font parameters*/
+
+@ @<Set init...@>=
+for (k=font_base; k<=font_max; k++) font_used[k]=false;
+
+@ \TeX\ always knows at least one font, namely the null font. It has no
+characters, and its seven parameters are all equal to zero.
+
+@<Initialize table...@>=
+font_ptr=null_font;fmem_ptr=7;
+font_name[null_font]=s_no("nullfont");font_area[null_font]=empty_string;
+hyphen_char[null_font]='-';skew_char[null_font]=-1;
+bchar_label[null_font]=non_address;
+font_bchar[null_font]=non_char;font_false_bchar[null_font]=non_char;
+font_bc[null_font]=1;font_ec[null_font]=0;
+font_size[null_font]=0;font_dsize[null_font]=0;
+char_base[null_font]=0;width_base[null_font]=0;
+height_base[null_font]=0;depth_base[null_font]=0;
+italic_base[null_font]=0;lig_kern_base[null_font]=0;
+kern_base[null_font]=0;exten_base[null_font]=0;
+font_glue[null_font]=null;font_params[null_font]=7;
+param_base[null_font]=-1;
+for (k=0; k<=6; k++) font_info[k].sc=0;
+
+@ @<Put each...@>=
+primitive("nullfont", set_font, null_font);
+@!@:null\_font\_}{\.{\\nullfont} primitive@>
+text(frozen_null_font)=text(cur_val);eqtb[frozen_null_font]=eqtb[cur_val];
+
+@ Of course we want to define macros that suppress the detail of how font
+information is actually packed, so that we don't have to write things like
+$$\hbox{|font_info[width_base[f]+font_info[char_base[f]+c].qqqq.b0].sc|}$$
+too often. The \.{WEB} definitions here make |char_info(f)(c)| the
+|four_quarters| word of font information corresponding to character
+|c| of font |f|. If |q| is such a word, |char_width(f)(q)| will be
+the character's width; hence the long formula above is at least
+abbreviated to
+$$\hbox{|char_width(f)(char_info(f)(c))|.}$$
+Usually, of course, we will fetch |q| first and look at several of its
+fields at the same time.
+
+The italic correction of a character will be denoted by
+|char_italic(f)(q)|, so it is analogous to |char_width|.  But we will get
+at the height and depth in a slightly different way, since we usually want
+to compute both height and depth if we want either one.  The value of
+|height_depth(q)| will be the 8-bit quantity
+$$b=|height_index|\times16+|depth_index|,$$ and if |b| is such a byte we
+will write |char_height(f)(b)| and |char_depth(f)(b)| for the height and
+depth of the character |c| for which |q==char_info(f)(c)|. Got that?
+
+The tag field will be called |char_tag(q)|; the remainder byte will be
+called |rem_byte(q)|, using a macro that we have already defined above.
+
+Access to a character's |width|, |height|, |depth|, and |tag| fields is
+part of \TeX's inner loop, so we want these macros to produce code that is
+as fast as possible under the circumstances.
+@^inner loop@>
+
+ at d char_info(A, B) font_info[char_base[A]+B].qqqq
+ at d char_width(A, B) font_info[width_base[A]+B.b0].sc
+ at d char_exists(A) (A.b0 > min_quarterword)
+ at d char_italic(A, B) font_info[italic_base[A]+(qo(B.b2))/4].sc
+ at d height_depth(A) qo(A.b1)
+ at d char_height(A, B) font_info[height_base[A]+(B)/16].sc
+ at d char_depth(A, B) font_info[depth_base[A]+(B)%16].sc
+ at d char_tag(A) ((qo(A.b2))%4)
+
+@ The global variable |null_character| is set up to be a word of
+|char_info| for a character that doesn't exist. Such a word provides a
+convenient way to deal with erroneous situations.
+
+@<Glob...@>=
+static four_quarters @!null_character; /*nonexistent character information*/
+
+@ @<Set init...@>=
+null_character.b0=min_quarterword;null_character.b1=min_quarterword;
+null_character.b2=min_quarterword;null_character.b3=min_quarterword;
+
+@ Here are some macros that help process ligatures and kerns.
+We write |char_kern(f)(j)| to find the amount of kerning specified by
+kerning command~|j| in font~|f|. If |j| is the |char_info| for a character
+with a ligature/kern program, the first instruction of that program is either
+|i==font_info[lig_kern_start(f)(j)]| or |font_info[lig_kern_restart(f)(i)]|,
+depending on whether or not |skip_byte(i) <= stop_flag|.
+
+The constant |kern_base_offset| should be simplified, for \PASCAL\ compilers
+that do not do local optimization.
+@^system dependencies@>
+
+ at d char_kern(A, B) font_info[kern_base[A]+256*op_byte(B)+rem_byte(B)].sc
+ at d kern_base_offset 256*(128+min_quarterword)
+ at d lig_kern_start(A, B) lig_kern_base[A]+B.b3 /*beginning of lig/kern program*/
+ at d lig_kern_restart(A, B) lig_kern_base[A]+256*op_byte(B)+rem_byte(B)+32768-kern_base_offset
+
+@ Font parameters are referred to as |slant(f)|, |space(f)|, etc.
+
+ at d param_end(A) param_base[A]].sc
+ at d param(A) font_info[A+param_end
+ at d slant param(slant_code) /*slant to the right, per unit distance upward*/
+ at d space param(space_code) /*normal space between words*/
+ at d space_stretch param(space_stretch_code) /*stretch between words*/
+ at d space_shrink param(space_shrink_code) /*shrink between words*/
+ at d x_height param(x_height_code) /*one ex*/
+ at d quad param(quad_code) /*one em*/
+ at d extra_space param(extra_space_code) /*additional space at end of sentence*/
+
+@<The em width for |cur_font|@>=quad(cur_font)
+
+@ @<The x-height for |cur_font|@>=x_height(cur_font)
+
+@ \TeX\ checks the information of a \.{TFM} file for validity as the
+file is being read in, so that no further checks will be needed when
+typesetting is going on. The somewhat tedious subroutine that does this
+is called |read_font_info|. It has four parameters: the user font
+identifier~|u|, the file name and area strings |nom| and |aire|, and the
+``at'' size~|s|. If |s|~is negative, it's the negative of a scale factor
+to be applied to the design size; |s==-1000| is the normal case.
+Otherwise |s| will be substituted for the design size; in this
+case, |s| must be positive and less than $2048\rm\,pt$
+(i.e., it must be less than $2^{27}$ when considered as an integer).
+
+The subroutine opens and closes a global file variable called |tfm_file|.
+It returns the value of the internal font number that was just loaded.
+If an error is detected, an error message is issued and no font
+information is stored; |null_font| is returned in this case.
+
+ at d abort goto bad_tfm /*do this when the \.{TFM} data is wrong*/
+
+ at p static internal_font_number read_font_info(pointer @!u, str_number @!nom, char *@!aire,
+  scaled @!s) /*input a \.{TFM} file*/
+{@+
+int k; /*index into |font_info|*/
+bool @!file_opened; /*was |tfm_file| successfully opened?*/
+halfword @!lf, @!lh, @!bc, @!ec, @!nw, @!nh, @!nd, @!ni, @!nl, @!nk, @!ne, @!np;
+   /*sizes of subfiles*/
+internal_font_number @!f; /*the new font's number*/
+internal_font_number @!g; /*the number to return*/
+eight_bits @!a, @!b, @!c, @!d; /*byte variables*/
+four_quarters @!qw;scaled @!sw; /*accumulators*/
+int @!bch_label; /*left boundary start location, or infinity*/
+int @!bchar; /*boundary character, or 256*/
+scaled @!z; /*the design size or the ``at'' size*/
+int @!alpha;int @!beta;
+   /*auxiliary quantities used in fixed-point multiplication*/
+g=null_font;@/
+@<Read and check the font data; |abort| if the \.{TFM} file is malformed; if there's
+no room for this font, say so and |goto done|; otherwise |incr(font_ptr)| and |goto
+done|@>;
+bad_tfm: @<Report that the font won't be loaded@>;
+done: if (file_opened) b_close(&tfm_file);
+return g;
+}
+
+@ There are programs called \.{TFtoPL} and \.{PLtoTF} that convert
+between the \.{TFM} format and a symbolic property-list format
+that can be easily edited. These programs contain extensive
+diagnostic information, so \TeX\ does not have to bother giving
+precise details about why it rejects a particular \.{TFM} file.
+ at .TFtoPL@> @.PLtoTF@>
+
+ at d start_font_error_message print_err("Font ");sprint_cs(u);
+  print_char('=');print_file_name(nom, aire,"");
+  if (s >= 0)
+    {@+print(" at ");print_scaled(s);print("pt");
+    }
+  else if (s!=-1000)
+    {@+print(" scaled ");print_int(-s);
+    }
+
+@<Report that the font won't be loaded@>=
+start_font_error_message;
+ at .Font x=xx not loadable...@>
+if (file_opened) print(" not loadable: Bad metric (TFM) file");
+else print(" not loadable: Metric (TFM) file not found");
+help5("I wasn't able to read the size data for this font,",@/
+"so I will ignore the font specification.",@/
+"[Wizards can fix TFM files using TFtoPL/PLtoTF.]",@/
+"You might try inserting a different font spec;",@/
+"e.g., type `I\\font<same font id>=<substitute font name>'.");
+error()
+
+@ @<Read and check...@>=
+@<Open |tfm_file| for input@>;
+@<Read the {\.{TFM}} size fields@>;
+@<Use size fields to allocate font information@>;
+@<Read the {\.{TFM}} header@>;
+@<Read character data@>;
+@<Read box dimensions@>;
+@<Read ligature/kern program@>;
+@<Read extensible character recipes@>;
+@<Read font parameters@>;
+@<Make final adjustments and |goto done|@>@;
+
+@ @<Open |tfm_file| for input@>=
+file_opened=false;
+pack_file_name(nom, "",".tfm"); /* k\TeX\ */
+if (!b_open_in(&tfm_file)) abort;
+file_opened=true
+
+@ Note: A malformed \.{TFM} file might be shorter than it claims to be;
+thus |eof(tfm_file)| might be true when |read_font_info| refers to
+|tfm_file.d| or when it says |get(tfm_file)|. If such circumstances
+cause system error messages, you will have to defeat them somehow,
+for example by defining |fget| to be `\ignorespaces|{@+get(tfm_file);|
+|if (eof(tfm_file)) abort;} |\unskip'.
+@^system dependencies@>
+
+ at d fget get(tfm_file)
+ at d fbyte tfm_file.d
+ at d read_sixteen(A) {@+A=fbyte;
+  if (A > 127) abort;
+  fget;A=A*0400+fbyte;
+  }
+ at d store_four_quarters(A) {@+fget;a=fbyte;qw.b0=qi(a);
+  fget;b=fbyte;qw.b1=qi(b);
+  fget;c=fbyte;qw.b2=qi(c);
+  fget;d=fbyte;qw.b3=qi(d);
+  A=qw;
+  }
+
+@ @<Read the {\.{TFM}} size fields@>=
+{@+read_sixteen(lf);
+fget;read_sixteen(lh);
+fget;read_sixteen(bc);
+fget;read_sixteen(ec);
+if ((bc > ec+1)||(ec > 255)) abort;
+if (bc > 255)  /*|bc==256| and |ec==255|*/
+  {@+bc=1;ec=0;
+  }
+fget;read_sixteen(nw);
+fget;read_sixteen(nh);
+fget;read_sixteen(nd);
+fget;read_sixteen(ni);
+fget;read_sixteen(nl);
+fget;read_sixteen(nk);
+fget;read_sixteen(ne);
+fget;read_sixteen(np);
+if (lf!=6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np) abort;
+if ((nw==0)||(nh==0)||(nd==0)||(ni==0)) abort;
+}
+
+@ The preliminary settings of the index-offset variables |char_base|,
+|width_base|, |lig_kern_base|, |kern_base|, and |exten_base| will be
+corrected later by subtracting |min_quarterword| from them; and we will
+subtract 1 from |param_base| too. It's best to forget about such anomalies
+until later.
+
+@<Use size fields to allocate font information@>=
+lf=lf-6-lh; /*|lf| words should be loaded into |font_info|*/
+if (np < 7) lf=lf+7-np; /*at least seven parameters will appear*/
+if ((font_ptr==font_max)||(fmem_ptr+lf > font_mem_size))
+  @<Apologize for not loading the font, |goto done|@>;
+f=font_ptr+1;
+char_base[f]=fmem_ptr-bc;
+width_base[f]=char_base[f]+ec+1;
+height_base[f]=width_base[f]+nw;
+depth_base[f]=height_base[f]+nh;
+italic_base[f]=depth_base[f]+nd;
+lig_kern_base[f]=italic_base[f]+ni;
+kern_base[f]=lig_kern_base[f]+nl-kern_base_offset;
+exten_base[f]=kern_base[f]+kern_base_offset+nk;
+param_base[f]=exten_base[f]+ne
+
+@ @<Apologize for not loading...@>=
+{@+start_font_error_message;
+print(" not loaded: Not enough room left");
+ at .Font x=xx not loaded...@>
+help4("I'm afraid I won't be able to make use of this font,",@/
+"because my memory for character-size data is too small.",@/
+"If you're really stuck, ask a wizard to enlarge me.",@/
+"Or maybe try `I\\font<same font id>=<name of loaded font>'.");
+error();goto done;
+}
+
+@ Only the first two words of the header are needed by \TeX82.
+
+@<Read the {\.{TFM}} header@>=
+{@+if (lh < 2) abort;
+store_four_quarters(font_check[f]);
+fget;read_sixteen(z); /*this rejects a negative design size*/
+fget;z=z*0400+fbyte;fget;z=(z*020)+(fbyte/020);
+if (z < unity) abort;
+while (lh > 2)
+  {@+fget;fget;fget;fget;decr(lh); /*ignore the rest of the header*/
+  }
+font_dsize[f]=z;
+if (s!=-1000)
+  if (s >= 0) z=s;
+  else z=xn_over_d(z,-s, 1000);
+font_size[f]=z;
+}
+
+@ @<Read character data@>=
+for (k=fmem_ptr; k<=width_base[f]-1; k++)
+  {@+store_four_quarters(font_info[k].qqqq);
+  if ((a >= nw)||(b/020 >= nh)||(b%020 >= nd)||
+    (c/4 >= ni)) abort;
+  switch (c%4) {
+  case lig_tag: if (d >= nl) abort;@+break;
+  case ext_tag: if (d >= ne) abort;@+break;
+  case list_tag: @<Check for charlist cycle@>@;@+break;
+  default:do_nothing; /*|no_tag|*/
+  }
+  }
+
+@ We want to make sure that there is no cycle of characters linked together
+by |list_tag| entries, since such a cycle would get \TeX\ into an endless
+loop. If such a cycle exists, the routine here detects it when processing
+the largest character code in the cycle.
+
+ at d check_byte_range(A) {@+if ((A < bc)||(A > ec)) abort;@+}
+ at d current_character_being_worked_on k+bc-fmem_ptr
+
+@<Check for charlist cycle@>=
+{@+check_byte_range(d);
+while (d < current_character_being_worked_on)
+  {@+qw=char_info(f, d);
+   /*N.B.: not |qi(d)|, since |char_base[f]| hasn't been adjusted yet*/
+  if (char_tag(qw)!=list_tag) goto not_found;
+  d=qo(rem_byte(qw)); /*next character on the list*/
+  }
+if (d==current_character_being_worked_on) abort; /*yes, there's a cycle*/
+not_found: ;}
+
+@ A |fix_word| whose four bytes are $(a,b,c,d)$ from left to right represents
+the number
+$$x=\left\{\vcenter{\halign{$#$,\hfil\qquad&if $#$\hfil\cr
+b\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=0;\cr
+-16+b\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=255.\cr}}\right.$$
+(No other choices of |a| are allowed, since the magnitude of a number in
+design-size units must be less than 16.)  We want to multiply this
+quantity by the integer~|z|, which is known to be less than $2^{27}$.
+If $|z|<2^{23}$, the individual multiplications $b\cdot z$,
+$c\cdot z$, $d\cdot z$ cannot overflow; otherwise we will divide |z| by 2,
+4, 8, or 16, to obtain a multiplier less than $2^{23}$, and we can
+compensate for this later. If |z| has thereby been replaced by
+$|z|^\prime=|z|/2^e$, let $\beta=2^{4-e}$; we shall compute
+$$\lfloor(b+c\cdot2^{-8}+d\cdot2^{-16})\,z^\prime/\beta\rfloor$$
+if $a=0$, or the same quantity minus $\alpha=2^{4+e}z^\prime$ if $a=255$.
+This calculation must be done exactly, in order to guarantee portability
+of \TeX\ between computers.
+
+ at d store_scaled(A) {@+fget;a=fbyte;fget;b=fbyte;
+  fget;c=fbyte;fget;d=fbyte;@/
+  sw=(((((d*z)/0400)+(c*z))/0400)+(b*z))/beta;
+  if (a==0) A=sw;@+else if (a==255) A=sw-alpha;@+else abort;
+  }
+
+@<Read box dimensions@>=
+{@+@<Replace |z| by $|z|^\prime$ and compute $\alpha,\beta$@>;
+for (k=width_base[f]; k<=lig_kern_base[f]-1; k++)
+  store_scaled(font_info[k].sc);
+if (font_info[width_base[f]].sc!=0) abort; /*\\{width}[0] must be zero*/
+if (font_info[height_base[f]].sc!=0) abort; /*\\{height}[0] must be zero*/
+if (font_info[depth_base[f]].sc!=0) abort; /*\\{depth}[0] must be zero*/
+if (font_info[italic_base[f]].sc!=0) abort; /*\\{italic}[0] must be zero*/
+}
+
+@ @<Replace |z|...@>=
+{@+alpha=16;
+while (z >= 040000000)
+  {@+z=z/2;alpha=alpha+alpha;
+  }
+beta=256/alpha;alpha=alpha*z;
+}
+
+@ @d check_existence(A) @t@>@;@/
+  {@+check_byte_range(A);
+  qw=char_info(f, A); /*N.B.: not |qi(A)|*/
+  if (!char_exists(qw)) abort;
+  }
+
+@<Read ligature/kern program@>=
+bch_label=077777;bchar=256;
+if (nl > 0)
+  {@+for (k=lig_kern_base[f]; k<=kern_base[f]+kern_base_offset-1; k++)
+    {@+store_four_quarters(font_info[k].qqqq);
+    if (a > 128)
+      {@+if (256*c+d >= nl) abort;
+      if (a==255) if (k==lig_kern_base[f]) bchar=b;
+      }
+    else{@+if (b!=bchar) check_existence(b);
+      if (c < 128) check_existence(d)@; /*check ligature*/
+      else if (256*(c-128)+d >= nk) abort; /*check kern*/
+      if (a < 128) if (k-lig_kern_base[f]+a+1 >= nl) abort;
+      }
+    }
+  if (a==255) bch_label=256*c+d;
+  }
+for (k=kern_base[f]+kern_base_offset; k<=exten_base[f]-1; k++)
+  store_scaled(font_info[k].sc);
+
+@ @<Read extensible character recipes@>=
+for (k=exten_base[f]; k<=param_base[f]-1; k++)
+  {@+store_four_quarters(font_info[k].qqqq);
+  if (a!=0) check_existence(a);
+  if (b!=0) check_existence(b);
+  if (c!=0) check_existence(c);
+  check_existence(d);
+  }
+
+@ We check to see that the \.{TFM} file doesn't end prematurely; but
+no error message is given for files having more than |lf| words.
+
+@<Read font parameters@>=
+{@+for (k=1; k<=np; k++)
+  if (k==1)  /*the |slant| parameter is a pure number*/
+    {@+fget;sw=fbyte;if (sw > 127) sw=sw-256;
+    fget;sw=sw*0400+fbyte;fget;sw=sw*0400+fbyte;
+    fget;font_info[param_base[f]].sc=
+      (sw*020)+(fbyte/020);
+    }
+  else store_scaled(font_info[param_base[f]+k-1].sc);
+if (eof(tfm_file)) abort;
+for (k=np+1; k<=7; k++) font_info[param_base[f]+k-1].sc=0;
+}
+
+@ Now to wrap it up, we have checked all the necessary things about the \.{TFM}
+file, and all we need to do is put the finishing touches on the data for
+the new font.
+
+ at d adjust(A) A[f]=qo(A[f])
+   /*correct for the excess |min_quarterword| that was added*/
+
+@<Make final adjustments...@>=
+if (np >= 7) font_params[f]=np;@+else font_params[f]=7;
+hyphen_char[f]=default_hyphen_char;skew_char[f]=default_skew_char;
+if (bch_label < nl) bchar_label[f]=bch_label+lig_kern_base[f];
+else bchar_label[f]=non_address;
+font_bchar[f]=qi(bchar);
+font_false_bchar[f]=qi(bchar);
+if (bchar <= ec) if (bchar >= bc)
+  {@+qw=char_info(f, bchar); /*N.B.: not |qi(bchar)|*/
+  if (char_exists(qw)) font_false_bchar[f]=non_char;
+  }
+font_name[f]=nom;
+font_area[f]=s_no(aire);
+font_bc[f]=bc;font_ec[f]=ec;font_glue[f]=null;
+adjust(char_base);adjust(width_base);adjust(lig_kern_base);
+adjust(kern_base);adjust(exten_base);
+decr(param_base[f]);
+fmem_ptr=fmem_ptr+lf;font_ptr=f;g=f;goto done
+
+@ Before we forget about the format of these tables, let's deal with two
+of \TeX's basic scanning routines related to font information.
+
+@<Declare procedures that scan font-related stuff@>=
+static void scan_font_ident(void)
+{@+internal_font_number f;
+halfword @!m;
+@<Get the next non-blank non-call...@>;
+if (cur_cmd==def_font) f=cur_font;
+else if (cur_cmd==set_font) f=cur_chr;
+else if (cur_cmd==def_family)
+  {@+m=cur_chr;scan_four_bit_int();f=equiv(m+cur_val);
+  }
+else{@+print_err("Missing font identifier");
+ at .Missing font identifier@>
+  help2("I was looking for a control sequence whose",@/
+  "current meaning has been defined by \\font.");
+  back_error();f=null_font;
+  }
+cur_val=f;
+}
+
+@ The following routine is used to implement `\.{\\fontdimen} |n| |f|'.
+The boolean parameter |writing| is set |true| if the calling program
+intends to change the parameter value.
+
+@<Declare procedures that scan font-related stuff@>=
+static void find_font_dimen(bool @!writing)
+   /*sets |cur_val| to |font_info| location*/
+{@+internal_font_number f;
+int @!n; /*the parameter number*/
+scan_int();n=cur_val;scan_font_ident();f=cur_val;
+if (n <= 0) cur_val=fmem_ptr;
+else{@+if (writing&&(n <= space_shrink_code)&&@|
+    (n >= space_code)&&(font_glue[f]!=null))
+    {@+delete_glue_ref(font_glue[f]);
+    font_glue[f]=null;
+    }
+  if (n > font_params[f])
+    if (f < font_ptr) cur_val=fmem_ptr;
+    else@<Increase the number of parameters in the last font@>@;
+  else cur_val=n+param_base[f];
+  }
+@<Issue an error message if |cur_val=fmem_ptr|@>;
+}
+
+@ @<Issue an error message if |cur_val=fmem_ptr|@>=
+if (cur_val==fmem_ptr)
+  {@+print_err("Font ");printn_esc(font_id_text(f));
+  print(" has only ");print_int(font_params[f]);
+  print(" fontdimen parameters");
+ at .Font x has only...@>
+  help2("To increase the number of font parameters, you must",@/
+    "use \\fontdimen immediately after the \\font is loaded.");
+  error();
+  }
+
+@ @<Increase the number of parameters...@>=
+{@+@/do at +{if (fmem_ptr==font_mem_size)
+  overflow("font memory", font_mem_size);
+@:TeX capacity exceeded font memory}{\quad font memory@>
+font_info[fmem_ptr].sc=0;incr(fmem_ptr);incr(font_params[f]);
+}@+ while (!(n==font_params[f]));
+cur_val=fmem_ptr-1; /*this equals |param_base[f]+font_params[f]|*/
+}
+
+@ When \TeX\ wants to typeset a character that doesn't exist, the
+character node is not created; thus the output routine can assume
+that characters exist when it sees them. The following procedure
+prints a warning message unless the user has suppressed it.
+
+ at p static void char_warning(internal_font_number @!f, eight_bits @!c)
+{@+int old_setting; /*saved value of |tracing_online|*/
+if (tracing_lost_chars > 0)
+ {@+old_setting=tracing_online;
+ if (eTeX_ex&&(tracing_lost_chars > 1)) tracing_online=1;
+  {@+begin_diagnostic();
+  print_nl("Missing character: There is no ");
+ at .Missing character@>
+  print_ASCII(c);print(" in font ");
+  slow_print(font_name[f]);print_char('!');end_diagnostic(false);
+  }
+ tracing_online=old_setting;
+ }
+}
+
+@ Here is a function that returns a pointer to a character node for a
+given character in a given font. If that character doesn't exist,
+|null| is returned instead.
+
+ at p static pointer new_character(internal_font_number @!f, eight_bits @!c)
+{@+
+pointer p; /*newly allocated node*/
+if (font_bc[f] <= c) if (font_ec[f] >= c)
+  if (char_exists(char_info(f, qi(c))))
+    {@+p=get_avail();font(p)=f;character(p)=qi(c);
+    return p;
+    }
+char_warning(f, c);
+return null;
+}
+
+@* Device-independent file format.
+The most important output produced by a run of \TeX\ is the ``device
+independent'' (\.{DVI}) file that specifies where characters and rules
+are to appear on printed pages. The form of these files was designed by
+David R. Fuchs in 1979. Almost any reasonable typesetting device can be
+@^Fuchs, David Raymond@>
+@:DVI\_files}{\.{DVI} files@>
+driven by a program that takes \.{DVI} files as input, and dozens of such
+\.{DVI}-to-whatever programs have been written. Thus, it is possible to
+print the output of \TeX\ on many different kinds of equipment, using \TeX\
+as a device-independent ``front end.''
+
+A \.{DVI} file is a stream of 8-bit bytes, which may be regarded as a
+series of commands in a machine-like language. The first byte of each command
+is the operation code, and this code is followed by zero or more bytes
+that provide parameters to the command. The parameters themselves may consist
+of several consecutive bytes; for example, the `|set_rule|' command has two
+parameters, each of which is four bytes long. Parameters are usually
+regarded as nonnegative integers; but four-byte-long parameters,
+and shorter parameters that denote distances, can be
+either positive or negative. Such parameters are given in two's complement
+notation. For example, a two-byte-long distance parameter has a value between
+$-2^{15}$ and $2^{15}-1$. As in \.{TFM} files, numbers that occupy
+more than one byte position appear in BigEndian order.
+
+A \.{DVI} file consists of a ``preamble,'' followed by a sequence of one
+or more ``pages,'' followed by a ``postamble.'' The preamble is simply a
+|pre| command, with its parameters that define the dimensions used in the
+file; this must come first.  Each ``page'' consists of a |bop| command,
+followed by any number of other commands that tell where characters are to
+be placed on a physical page, followed by an |eop| command. The pages
+appear in the order that \TeX\ generated them. If we ignore |nop| commands
+and \\{fnt\_def} commands (which are allowed between any two commands in
+the file), each |eop| command is immediately followed by a |bop| command,
+or by a |post| command; in the latter case, there are no more pages in the
+file, and the remaining bytes form the postamble.  Further details about
+the postamble will be explained later.
+
+Some parameters in \.{DVI} commands are ``pointers.'' These are four-byte
+quantities that give the location number of some other byte in the file;
+the first byte is number~0, then comes number~1, and so on. For example,
+one of the parameters of a |bop| command points to the previous |bop|;
+this makes it feasible to read the pages in backwards order, in case the
+results are being directed to a device that stacks its output face up.
+Suppose the preamble of a \.{DVI} file occupies bytes 0 to 99. Now if the
+first page occupies bytes 100 to 999, say, and if the second
+page occupies bytes 1000 to 1999, then the |bop| that starts in byte 1000
+points to 100 and the |bop| that starts in byte 2000 points to 1000. (The
+very first |bop|, i.e., the one starting in byte 100, has a pointer of~$-1$.)
+
+@ The \.{DVI} format is intended to be both compact and easily interpreted
+by a machine. Compactness is achieved by making most of the information
+implicit instead of explicit. When a \.{DVI}-reading program reads the
+commands for a page, it keeps track of several quantities: (a)~The current
+font |f| is an integer; this value is changed only
+by \\{fnt} and \\{fnt\_num} commands. (b)~The current position on the page
+is given by two numbers called the horizontal and vertical coordinates,
+|h| and |v|. Both coordinates are zero at the upper left corner of the page;
+moving to the right corresponds to increasing the horizontal coordinate, and
+moving down corresponds to increasing the vertical coordinate. Thus, the
+coordinates are essentially Cartesian, except that vertical directions are
+flipped; the Cartesian version of |(h, v)| would be |(h,-v)|.  (c)~The
+current spacing amounts are given by four numbers |w|, |x|, |y|, and |z|,
+where |w| and~|x| are used for horizontal spacing and where |y| and~|z|
+are used for vertical spacing. (d)~There is a stack containing
+|(h, v, w, x, y, z)| values; the \.{DVI} commands |push| and |pop| are used to
+change the current level of operation. Note that the current font~|f| is
+not pushed and popped; the stack contains only information about
+positioning.
+
+The values of |h|, |v|, |w|, |x|, |y|, and |z| are signed integers having up
+to 32 bits, including the sign. Since they represent physical distances,
+there is a small unit of measurement such that increasing |h| by~1 means
+moving a certain tiny distance to the right. The actual unit of
+measurement is variable, as explained below; \TeX\ sets things up so that
+its \.{DVI} output is in sp units, i.e., scaled points, in agreement with
+all the |scaled| dimensions in \TeX's data structures.
+
+@ Here is a list of all the commands that may appear in a \.{DVI} file. Each
+command is specified by its symbolic name (e.g., |bop|), its opcode byte
+(e.g., 139), and its parameters (if any). The parameters are followed
+by a bracketed number telling how many bytes they occupy; for example,
+`|p[4]|' means that parameter |p| is four bytes long.
+
+\yskip\hang|set_char_0| 0. Typeset character number~0 from font~|f|
+such that the reference point of the character is at |(h, v)|. Then
+increase |h| by the width of that character. Note that a character may
+have zero or negative width, so one cannot be sure that |h| will advance
+after this command; but |h| usually does increase.
+
+\yskip\hang\\{set\_char\_1} through \\{set\_char\_127} (opcodes 1 to 127).
+Do the operations of |set_char_0|; but use the character whose number
+matches the opcode, instead of character~0.
+
+\yskip\hang|set1| 128 |c[1]|. Same as |set_char_0|, except that character
+number~|c| is typeset. \TeX82 uses this command for characters in the
+range |128 <= c < 256|.
+
+\yskip\hang|@!set2| 129 |c[2]|. Same as |set1|, except that |c|~is two
+bytes long, so it is in the range |0 <= c < 65536|. \TeX82 never uses this
+command, but it should come in handy for extensions of \TeX\ that deal
+with oriental languages.
+@^oriental characters@>@^Chinese characters@>@^Japanese characters@>
+
+\yskip\hang|@!set3| 130 |c[3]|. Same as |set1|, except that |c|~is three
+bytes long, so it can be as large as $2^{24}-1$. Not even the Chinese
+language has this many characters, but this command might prove useful
+in some yet unforeseen extension.
+
+\yskip\hang|@!set4| 131 |c[4]|. Same as |set1|, except that |c|~is four
+bytes long. Imagine that.
+
+\yskip\hang|set_rule| 132 |a[4]| |b[4]|. Typeset a solid black rectangle
+of height~|a| and width~|b|, with its bottom left corner at |(h, v)|. Then
+set |h=h+b|. If either |a <= 0| or |b <= 0|, nothing should be typeset. Note
+that if |b < 0|, the value of |h| will decrease even though nothing else happens.
+See below for details about how to typeset rules so that consistency with
+\MF\ is guaranteed.
+
+\yskip\hang|@!put1| 133 |c[1]|. Typeset character number~|c| from font~|f|
+such that the reference point of the character is at |(h, v)|. (The `put'
+commands are exactly like the `set' commands, except that they simply put out a
+character or a rule without moving the reference point afterwards.)
+
+\yskip\hang|@!put2| 134 |c[2]|. Same as |set2|, except that |h| is not changed.
+
+\yskip\hang|@!put3| 135 |c[3]|. Same as |set3|, except that |h| is not changed.
+
+\yskip\hang|@!put4| 136 |c[4]|. Same as |set4|, except that |h| is not changed.
+
+\yskip\hang|put_rule| 137 |a[4]| |b[4]|. Same as |set_rule|, except that
+|h| is not changed.
+
+\yskip\hang|nop| 138. No operation, do nothing. Any number of |nop|'s
+may occur between \.{DVI} commands, but a |nop| cannot be inserted between
+a command and its parameters or between two parameters.
+
+\yskip\hang|bop| 139 $c_0[4]$ $c_1[4]$ $\ldots$ $c_9[4]$ $p[4]$. Beginning
+of a page: Set |(h, v, w, x, y, z)=(0, 0, 0, 0, 0, 0)| and set the stack empty. Set
+the current font |f| to an undefined value.  The ten $c_i$ parameters hold
+the values of \.{\\count0} $\ldots$ \.{\\count9} in \TeX\ at the time
+\.{\\shipout} was invoked for this page; they can be used to identify
+pages, if a user wants to print only part of a \.{DVI} file. The parameter
+|p| points to the previous |bop| in the file; the first
+|bop| has $p=-1$.
+
+\yskip\hang|eop| 140.  End of page: Print what you have read since the
+previous |bop|. At this point the stack should be empty. (The \.{DVI}-reading
+programs that drive most output devices will have kept a buffer of the
+material that appears on the page that has just ended. This material is
+largely, but not entirely, in order by |v| coordinate and (for fixed |v|) by
+|h|~coordinate; so it usually needs to be sorted into some order that is
+appropriate for the device in question.)
+
+\yskip\hang|push| 141. Push the current values of |(h, v, w, x, y, z)| onto the
+top of the stack; do not change any of these values. Note that |f| is
+not pushed.
+
+\yskip\hang|pop| 142. Pop the top six values off of the stack and assign
+them respectively to |(h, v, w, x, y, z)|. The number of pops should never
+exceed the number of pushes, since it would be highly embarrassing if the
+stack were empty at the time of a |pop| command.
+
+\yskip\hang|right1| 143 |b[1]|. Set |h=h+b|, i.e., move right |b| units.
+The parameter is a signed number in two's complement notation, |-128 <= b < 128|;
+if |b < 0|, the reference point moves left.
+
+\yskip\hang|@!right2| 144 |b[2]|. Same as |right1|, except that |b| is a
+two-byte quantity in the range |-32768 <= b < 32768|.
+
+\yskip\hang|@!right3| 145 |b[3]|. Same as |right1|, except that |b| is a
+three-byte quantity in the range |@t$-2^{23}$@> <= b < @t$2^{23}$@>|.
+
+\yskip\hang|@!right4| 146 |b[4]|. Same as |right1|, except that |b| is a
+four-byte quantity in the range |@t$-2^{31}$@> <= b < @t$2^{31}$@>|.
+
+\yskip\hang|w0| 147. Set |h=h+w|; i.e., move right |w| units. With luck,
+this parameterless command will usually suffice, because the same kind of motion
+will occur several times in succession; the following commands explain how
+|w| gets particular values.
+
+\yskip\hang|w1| 148 |b[1]|. Set |w=b| and |h=h+b|. The value of |b| is a
+signed quantity in two's complement notation, |-128 <= b < 128|. This command
+changes the current |w|~spacing and moves right by |b|.
+
+\yskip\hang|@!w2| 149 |b[2]|. Same as |w1|, but |b| is two bytes long,
+|-32768 <= b < 32768|.
+
+\yskip\hang|@!w3| 150 |b[3]|. Same as |w1|, but |b| is three bytes long,
+|@t$-2^{23}$@> <= b < @t$2^{23}$@>|.
+
+\yskip\hang|@!w4| 151 |b[4]|. Same as |w1|, but |b| is four bytes long,
+|@t$-2^{31}$@> <= b < @t$2^{31}$@>|.
+
+\yskip\hang|x0| 152. Set |h=h+x|; i.e., move right |x| units. The `|x|'
+commands are like the `|w|' commands except that they involve |x| instead
+of |w|.
+
+\yskip\hang|x1| 153 |b[1]|. Set |x=b| and |h=h+b|. The value of |b| is a
+signed quantity in two's complement notation, |-128 <= b < 128|. This command
+changes the current |x|~spacing and moves right by |b|.
+
+\yskip\hang|@!x2| 154 |b[2]|. Same as |x1|, but |b| is two bytes long,
+|-32768 <= b < 32768|.
+
+\yskip\hang|@!x3| 155 |b[3]|. Same as |x1|, but |b| is three bytes long,
+|@t$-2^{23}$@> <= b < @t$2^{23}$@>|.
+
+\yskip\hang|@!x4| 156 |b[4]|. Same as |x1|, but |b| is four bytes long,
+|@t$-2^{31}$@> <= b < @t$2^{31}$@>|.
+
+\yskip\hang|down1| 157 |a[1]|. Set |v=v+a|, i.e., move down |a| units.
+The parameter is a signed number in two's complement notation, |-128 <= a < 128|;
+if |a < 0|, the reference point moves up.
+
+\yskip\hang|@!down2| 158 |a[2]|. Same as |down1|, except that |a| is a
+two-byte quantity in the range |-32768 <= a < 32768|.
+
+\yskip\hang|@!down3| 159 |a[3]|. Same as |down1|, except that |a| is a
+three-byte quantity in the range |@t$-2^{23}$@> <= a < @t$2^{23}$@>|.
+
+\yskip\hang|@!down4| 160 |a[4]|. Same as |down1|, except that |a| is a
+four-byte quantity in the range |@t$-2^{31}$@> <= a < @t$2^{31}$@>|.
+
+\yskip\hang|y0| 161. Set |v=v+y|; i.e., move down |y| units. With luck,
+this parameterless command will usually suffice, because the same kind of motion
+will occur several times in succession; the following commands explain how
+|y| gets particular values.
+
+\yskip\hang|y1| 162 |a[1]|. Set |y=a| and |v=v+a|. The value of |a| is a
+signed quantity in two's complement notation, |-128 <= a < 128|. This command
+changes the current |y|~spacing and moves down by |a|.
+
+\yskip\hang|@!y2| 163 |a[2]|. Same as |y1|, but |a| is two bytes long,
+|-32768 <= a < 32768|.
+
+\yskip\hang|@!y3| 164 |a[3]|. Same as |y1|, but |a| is three bytes long,
+|@t$-2^{23}$@> <= a < @t$2^{23}$@>|.
+
+\yskip\hang|@!y4| 165 |a[4]|. Same as |y1|, but |a| is four bytes long,
+|@t$-2^{31}$@> <= a < @t$2^{31}$@>|.
+
+\yskip\hang|z0| 166. Set |v=v+z|; i.e., move down |z| units. The `|z|' commands
+are like the `|y|' commands except that they involve |z| instead of |y|.
+
+\yskip\hang|z1| 167 |a[1]|. Set |z=a| and |v=v+a|. The value of |a| is a
+signed quantity in two's complement notation, |-128 <= a < 128|. This command
+changes the current |z|~spacing and moves down by |a|.
+
+\yskip\hang|@!z2| 168 |a[2]|. Same as |z1|, but |a| is two bytes long,
+|-32768 <= a < 32768|.
+
+\yskip\hang|@!z3| 169 |a[3]|. Same as |z1|, but |a| is three bytes long,
+|@t$-2^{23}$@> <= a < @t$2^{23}$@>|.
+
+\yskip\hang|@!z4| 170 |a[4]|. Same as |z1|, but |a| is four bytes long,
+|@t$-2^{31}$@> <= a < @t$2^{31}$@>|.
+
+\yskip\hang|fnt_num_0| 171. Set |f=0|. Font 0 must previously have been
+defined by a \\{fnt\_def} instruction, as explained below.
+
+\yskip\hang\\{fnt\_num\_1} through \\{fnt\_num\_63} (opcodes 172 to 234). Set
+|f=1|, \dots, \hbox{|f=63|}, respectively.
+
+\yskip\hang|fnt1| 235 |k[1]|. Set |f=k|. \TeX82 uses this command for font
+numbers in the range |64 <= k < 256|.
+
+\yskip\hang|@!fnt2| 236 |k[2]|. Same as |fnt1|, except that |k|~is two
+bytes long, so it is in the range |0 <= k < 65536|. \TeX82 never generates this
+command, but large font numbers may prove useful for specifications of
+color or texture, or they may be used for special fonts that have fixed
+numbers in some external coding scheme.
+
+\yskip\hang|@!fnt3| 237 |k[3]|. Same as |fnt1|, except that |k|~is three
+bytes long, so it can be as large as $2^{24}-1$.
+
+\yskip\hang|@!fnt4| 238 |k[4]|. Same as |fnt1|, except that |k|~is four
+bytes long; this is for the really big font numbers (and for the negative ones).
+
+\yskip\hang|xxx1| 239 |k[1]| |x[k]|. This command is undefined in
+general; it functions as a $(k+2)$-byte |nop| unless special \.{DVI}-reading
+programs are being used. \TeX82 generates |xxx1| when a short enough
+\.{\\special} appears, setting |k| to the number of bytes being sent. It
+is recommended that |x| be a string having the form of a keyword followed
+by possible parameters relevant to that keyword.
+
+\yskip\hang|@!xxx2| 240 |k[2]| |x[k]|. Like |xxx1|, but |0 <= k < 65536|.
+
+\yskip\hang|@!xxx3| 241 |k[3]| |x[k]|. Like |xxx1|, but |0 <= k < @t$2^{24}$@>|.
+
+\yskip\hang|xxx4| 242 |k[4]| |x[k]|. Like |xxx1|, but |k| can be ridiculously
+large. \TeX82 uses |xxx4| when sending a string of length 256 or more.
+
+\yskip\hang|fnt_def1| 243 |k[1]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
+Define font |k|, where |0 <= k < 256|; font definitions will be explained shortly.
+
+\yskip\hang|@!fnt_def2| 244 |k[2]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
+Define font |k|, where |0 <= k < 65536|.
+
+\yskip\hang|@!fnt_def3| 245 |k[3]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
+Define font |k|, where |0 <= k < @t$2^{24}$@>|.
+
+\yskip\hang|@!fnt_def4| 246 |k[4]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
+Define font |k|, where |@t$-2^{31}$@> <= k < @t$2^{31}$@>|.
+
+\yskip\hang|pre| 247 |i[1]| |num[4]| |den[4]| |mag[4]| |k[1]| |x[k]|.
+Beginning of the preamble; this must come at the very beginning of the
+file. Parameters |i|, |num|, |den|, |mag|, |k|, and |x| are explained below.
+
+\yskip\hang|post| 248. Beginning of the postamble, see below.
+
+\yskip\hang|post_post| 249. Ending of the postamble, see below.
+
+\yskip\noindent Commands 250--255 are undefined at the present time.
+
+@ @d set_char_0 0 /*typeset character 0 and move right*/
+ at d set1 128 /*typeset a character and move right*/
+ at d set_rule 132 /*typeset a rule and move right*/
+ at d put_rule 137 /*typeset a rule*/
+ at d nop 138 /*no operation*/
+ at d bop 139 /*beginning of page*/
+ at d eop 140 /*ending of page*/
+ at d push 141 /*save the current positions*/
+ at d pop 142 /*restore previous positions*/
+ at d right1 143 /*move right*/
+ at d w0 147 /*move right by |w|*/
+ at d w1 148 /*move right and set |w|*/
+ at d x0 152 /*move right by |x|*/
+ at d x1 153 /*move right and set |x|*/
+ at d down1 157 /*move down*/
+ at d y0 161 /*move down by |y|*/
+ at d y1 162 /*move down and set |y|*/
+ at d z0 166 /*move down by |z|*/
+ at d z1 167 /*move down and set |z|*/
+ at d fnt_num_0 171 /*set current font to 0*/
+ at d fnt1 235 /*set current font*/
+ at d xxx1 239 /*extension to \.{DVI} primitives*/
+ at d xxx4 242 /*potentially long extension to \.{DVI} primitives*/
+ at d fnt_def1 243 /*define the meaning of a font number*/
+ at d pre 247 /*preamble*/
+ at d post 248 /*postamble beginning*/
+ at d post_post 249 /*postamble ending*/
+
+@ The preamble contains basic information about the file as a whole. As
+stated above, there are six parameters:
+$$\hbox{|@!i[1]| |@!num[4]| |@!den[4]| |@!mag[4]| |@!k[1]| |@!x[k]|.}$$
+The |i| byte identifies \.{DVI} format; currently this byte is always set
+to~2. (The value |i==3| is currently used for an extended format that
+allows a mixture of right-to-left and left-to-right typesetting.
+Some day we will set |i==4|, when \.{DVI} format makes another
+incompatible change---perhaps in the year 2048.)
+
+The next two parameters, |num| and |den|, are positive integers that define
+the units of measurement; they are the numerator and denominator of a
+fraction by which all dimensions in the \.{DVI} file could be multiplied
+in order to get lengths in units of $10^{-7}$ meters. Since $\rm 7227{pt} =
+254{cm}$, and since \TeX\ works with scaled points where there are $2^{16}$
+sp in a point, \TeX\ sets
+$|num|/|den|=(254\cdot10^5)/(7227\cdot2^{16})=25400000/473628672$.
+@^sp@>
+
+The |mag| parameter is what \TeX\ calls \.{\\mag}, i.e., 1000 times the
+desired magnification. The actual fraction by which dimensions are
+multiplied is therefore $|mag|\cdot|num|/1000|den|$. Note that if a \TeX\
+source document does not call for any `\.{true}' dimensions, and if you
+change it only by specifying a different \.{\\mag} setting, the \.{DVI}
+file that \TeX\ creates will be completely unchanged except for the value
+of |mag| in the preamble and postamble. (Fancy \.{DVI}-reading programs allow
+users to override the |mag|~setting when a \.{DVI} file is being printed.)
+
+Finally, |k| and |x| allow the \.{DVI} writer to include a comment, which is not
+interpreted further. The length of comment |x| is |k|, where |0 <= k < 256|.
+
+ at d id_byte 2 /*identifies the kind of \.{DVI} files described here*/
+
+@ Font definitions for a given font number |k| contain further parameters
+$$\hbox{|c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.}$$
+The four-byte value |c| is the check sum that \TeX\ found in the \.{TFM}
+file for this font; |c| should match the check sum of the font found by
+programs that read this \.{DVI} file.
+@^check sum@>
+
+Parameter |s| contains a fixed-point scale factor that is applied to
+the character widths in font |k|; font dimensions in \.{TFM} files and
+other font files are relative to this quantity, which is called the
+``at size'' elsewhere in this documentation. The value of |s| is
+always positive and less than $2^{27}$. It is given in the same units
+as the other \.{DVI} dimensions, i.e., in sp when \TeX82 has made the
+file.  Parameter |d| is similar to |s|; it is the ``design size,'' and
+(like~|s|) it is given in \.{DVI} units. Thus, font |k| is to be used
+at $|mag|\cdot s/1000d$ times its normal size.
+
+The remaining part of a font definition gives the external name of the font,
+which is an ASCII string of length |a+l|. The number |a| is the length
+of the ``area'' or directory, and |l| is the length of the font name itself;
+the standard local system font area is supposed to be used when |a==0|.
+The |n| field contains the area in its first |a| bytes.
+
+Font definitions must appear before the first use of a particular font number.
+Once font |k| is defined, it must not be defined again; however, we
+shall see below that font definitions appear in the postamble as well as
+in the pages, so in this sense each font number is defined exactly twice,
+if at all. Like |nop| commands, font definitions can
+appear before the first |bop|, or between an |eop| and a |bop|.
+
+@ Sometimes it is desirable to make horizontal or vertical rules line up
+precisely with certain features in characters of a font. It is possible to
+guarantee the correct matching between \.{DVI} output and the characters
+generated by \MF\ by adhering to the following principles: (1)~The \MF\
+characters should be positioned so that a bottom edge or left edge that is
+supposed to line up with the bottom or left edge of a rule appears at the
+reference point, i.e., in row~0 and column~0 of the \MF\ raster. This
+ensures that the position of the rule will not be rounded differently when
+the pixel size is not a perfect multiple of the units of measurement in
+the \.{DVI} file. (2)~A typeset rule of height $a>0$ and width $b>0$
+should be equivalent to a \MF-generated character having black pixels in
+precisely those raster positions whose \MF\ coordinates satisfy
+|0 <= x < @t$\alpha$@>b| and |0 <= y < @t$\alpha$@>a|, where $\alpha$ is the number
+of pixels per \.{DVI} unit.
+@:METAFONT}{\MF@>
+@^alignment of rules with characters@>
+@^rules aligning with characters@>
+
+@ The last page in a \.{DVI} file is followed by `|post|'; this command
+introduces the postamble, which summarizes important facts that \TeX\ has
+accumulated about the file, making it possible to print subsets of the data
+with reasonable efficiency. The postamble has the form
+$$\vbox{\halign{\hbox{#\hfil}\cr
+  |post| |p[4]| |num[4]| |den[4]| |mag[4]| |l[4]| |u[4]| |s[2]| |t[2]|\cr
+  $\langle\,$font definitions$\,\rangle$\cr
+  |post_post| |q[4]| |i[1]| 223's$[{\G}4]$\cr}}$$
+Here |p| is a pointer to the final |bop| in the file. The next three
+parameters, |num|, |den|, and |mag|, are duplicates of the quantities that
+appeared in the preamble.
+
+Parameters |l| and |u| give respectively the height-plus-depth of the tallest
+page and the width of the widest page, in the same units as other dimensions
+of the file. These numbers might be used by a \.{DVI}-reading program to
+position individual ``pages'' on large sheets of film or paper; however,
+the standard convention for output on normal size paper is to position each
+page so that the upper left-hand corner is exactly one inch from the left
+and the top. Experience has shown that it is unwise to design \.{DVI}-to-printer
+software that attempts cleverly to center the output; a fixed position of
+the upper left corner is easiest for users to understand and to work with.
+Therefore |l| and~|u| are often ignored.
+
+Parameter |s| is the maximum stack depth (i.e., the largest excess of
+|push| commands over |pop| commands) needed to process this file. Then
+comes |t|, the total number of pages (|bop| commands) present.
+
+The postamble continues with font definitions, which are any number of
+\\{fnt\_def} commands as described above, possibly interspersed with |nop|
+commands. Each font number that is used in the \.{DVI} file must be defined
+exactly twice: Once before it is first selected by a \\{fnt} command, and once
+in the postamble.
+
+@ The last part of the postamble, following the |post_post| byte that
+signifies the end of the font definitions, contains |q|, a pointer to the
+|post| command that started the postamble.  An identification byte, |i|,
+comes next; this currently equals~2, as in the preamble.
+
+The |i| byte is followed by four or more bytes that are all equal to
+the decimal number 223 (i.e., 0337 in octal). \TeX\ puts out four to seven of
+these trailing bytes, until the total length of the file is a multiple of
+four bytes, since this works out best on machines that pack four bytes per
+word; but any number of 223's is allowed, as long as there are at least four
+of them. In effect, 223 is a sort of signature that is added at the very end.
+@^Fuchs, David Raymond@>
+
+This curious way to finish off a \.{DVI} file makes it feasible for
+\.{DVI}-reading programs to find the postamble first, on most computers,
+even though \TeX\ wants to write the postamble last. Most operating
+systems permit random access to individual words or bytes of a file, so
+the \.{DVI} reader can start at the end and skip backwards over the 223's
+until finding the identification byte. Then it can back up four bytes, read
+|q|, and move to byte |q| of the file. This byte should, of course,
+contain the value 248 (|post|); now the postamble can be read, so the
+\.{DVI} reader can discover all the information needed for typesetting the
+pages. Note that it is also possible to skip through the \.{DVI} file at
+reasonably high speed to locate a particular page, if that proves
+desirable. This saves a lot of time, since \.{DVI} files used in production
+jobs tend to be large.
+
+Unfortunately, however, standard \PASCAL\ does not include the ability to
+@^system dependencies@>
+access a random position in a file, or even to determine the length of a file.
+Almost all systems nowadays provide the necessary capabilities, so \.{DVI}
+format has been designed to work most efficiently with modern operating systems.
+But if \.{DVI} files have to be processed under the restrictions of standard
+\PASCAL, one can simply read them from front to back, since the necessary
+header information is present in the preamble and in the font definitions.
+(The |l| and |u| and |s| and |t| parameters, which appear only in the
+postamble, are ``frills'' that are handy but not absolutely necessary.)
+
+@* Shipping pages out.
+After considering \TeX's eyes and stomach, we come now to the bowels.
+@^bowels@>
+
+The |ship_out| procedure is given a pointer to a box; its mission is
+to describe that box in \.{DVI} form, outputting a ``page'' to |dvi_file|.
+The \.{DVI} coordinates $(h,v)=(0,0)$ should correspond to the upper left
+corner of the box being shipped.
+
+Since boxes can be inside of boxes inside of boxes, the main work of
+|ship_out| is done by two mutually recursive routines, |hlist_out|
+and |vlist_out|, which traverse the hlists and vlists inside of horizontal
+and vertical boxes.
+
+As individual pages are being processed, we need to accumulate
+information about the entire set of pages, since such statistics must be
+reported in the postamble. The global variables |total_pages|, |max_v|,
+|max_h|, |max_push|, and |last_bop| are used to record this information.
+
+The variable |doing_leaders| is |true| while leaders are being output.
+The variable |dead_cycles| contains the number of times an output routine
+has been initiated since the last |ship_out|.
+
+A few additional global variables are also defined here for use in
+|vlist_out| and |hlist_out|. They could have been local variables, but
+that would waste stack space when boxes are deeply nested, since the
+values of these variables are not needed during recursive calls.
+@^recursion@>
+
+@<Glob...@>=
+static int @!total_pages; /*the number of pages that have been shipped out*/
+static scaled @!max_v; /*maximum height-plus-depth of pages shipped so far*/
+static scaled @!max_h; /*maximum width of pages shipped so far*/
+static int @!max_push; /*deepest nesting of |push| commands encountered so far*/
+static int @!last_bop; /*location of previous |bop| in the \.{DVI} output*/
+static int @!dead_cycles; /*recent outputs that didn't ship anything out*/
+static bool @!doing_leaders; /*are we inside a leader box?*/
+@#
+static quarterword @!c, @!f; /*character and font in current |char_node|*/
+static scaled @!rule_ht, @!rule_dp, @!rule_wd; /*size of current rule being output*/
+static pointer @!g; /*current glue specification*/
+static int @!lq, @!lr; /*quantities used in calculations for leaders*/
+
+@ @<Set init...@>=
+total_pages=0;max_v=0;max_h=0;max_push=0;last_bop=-1;
+doing_leaders=false;dead_cycles=0;cur_s=-1;
+
+@ The \.{DVI} bytes are output to a buffer instead of being written directly
+to the output file. This makes it possible to reduce the overhead of
+subroutine calls, thereby measurably speeding up the computation, since
+output of \.{DVI} bytes is part of \TeX's inner loop. And it has another
+advantage as well, since we can change instructions in the buffer in order to
+make the output more compact. For example, a `|down2|' command can be
+changed to a `|y2|', thereby making a subsequent `|y0|' command possible,
+saving two bytes.
+
+The output buffer is divided into two parts of equal size; the bytes found
+in |dvi_buf[0 dotdot half_buf-1]| constitute the first half, and those in
+|dvi_buf[half_buf dotdot dvi_buf_size-1]| constitute the second. The global
+variable |dvi_ptr| points to the position that will receive the next
+output byte. When |dvi_ptr| reaches |dvi_limit|, which is always equal
+to one of the two values |half_buf| or |dvi_buf_size|, the half buffer that
+is about to be invaded next is sent to the output and |dvi_limit| is
+changed to its other value. Thus, there is always at least a half buffer's
+worth of information present, except at the very beginning of the job.
+
+Bytes of the \.{DVI} file are numbered sequentially starting with 0;
+the next byte to be generated will be number |dvi_offset+dvi_ptr|.
+A byte is present in the buffer only if its number is | >= dvi_gone|.
+
+@<Types...@>=
+typedef int16_t dvi_index; /*an index into the output buffer*/
+
+@ Some systems may find it more efficient to make |dvi_buf| a ||
+array, since output of four bytes at once may be facilitated.
+@^system dependencies@>
+
+@<Glob...@>=
+static eight_bits @!dvi_buf[dvi_buf_size+1]; /*buffer for \.{DVI} output*/
+static dvi_index @!half_buf; /*half of |dvi_buf_size|*/
+static dvi_index @!dvi_limit; /*end of the current half buffer*/
+static dvi_index @!dvi_ptr; /*the next available buffer address*/
+static int @!dvi_offset; /*|dvi_buf_size| times the number of times the
+  output buffer has been fully emptied*/
+static int @!dvi_gone; /*the number of bytes already output to |dvi_file|*/
+
+@ Initially the buffer is all in one piece; we will output half of it only
+after it first fills up.
+
+@<Set init...@>=
+half_buf=dvi_buf_size/2;dvi_limit=dvi_buf_size;dvi_ptr=0;
+dvi_offset=0;dvi_gone=0;
+
+@ The actual output of |dvi_buf[a dotdot b]| to |dvi_file| is performed by calling
+|write_dvi(a, b)|. For best results, this procedure should be optimized to
+run as fast as possible on each particular system, since it is part of
+\TeX's inner loop. It is safe to assume that |a| and |b+1| will both be
+multiples of 4 when |write_dvi(a, b)| is called; therefore it is possible on
+many machines to use efficient methods to pack four bytes per word and to
+output an array of words with one system call.
+@^system dependencies@>
+@^inner loop@>
+@^defecation@>
+
+ at p static void write_dvi(dvi_index @!a, dvi_index @!b)
+{@+int k;
+for (k=a; k<=b; k++) pascal_write(dvi_file, "%c", dvi_buf[k]);
+}
+
+@ To put a byte in the buffer without paying the cost of invoking a procedure
+each time, we use the macro |dvi_out|.
+
+ at d dvi_out(A) @+{@+dvi_buf[dvi_ptr]=A;incr(dvi_ptr);
+  if (dvi_ptr==dvi_limit) dvi_swap();
+  }
+
+ at p static void dvi_swap(void) /*outputs half of the buffer*/
+{@+if (dvi_limit==dvi_buf_size)
+  {@+write_dvi(0, half_buf-1);dvi_limit=half_buf;
+  dvi_offset=dvi_offset+dvi_buf_size;dvi_ptr=0;
+  }
+else{@+write_dvi(half_buf, dvi_buf_size-1);dvi_limit=dvi_buf_size;
+  }
+dvi_gone=dvi_gone+half_buf;
+}
+
+@ Here is how we clean out the buffer when \TeX\ is all through; |dvi_ptr|
+will be a multiple of~4.
+
+@<Empty the last bytes out of |dvi_buf|@>=
+if (dvi_limit==half_buf) write_dvi(half_buf, dvi_buf_size-1);
+if (dvi_ptr > 0) write_dvi(0, dvi_ptr-1)
+
+@ The |dvi_four| procedure outputs four bytes in two's complement notation,
+without risking arithmetic overflow.
+
+ at p static void dvi_four(int @!x)
+{@+if (x >= 0) dvi_out(x/0100000000)@;
+else{@+x=x+010000000000;
+  x=x+010000000000;
+  dvi_out((x/0100000000)+128);
+  }
+x=x%0100000000;dvi_out(x/0200000);
+x=x%0200000;dvi_out(x/0400);
+dvi_out(x%0400);
+}
+
+@ A mild optimization of the output is performed by the |dvi_pop|
+routine, which issues a |pop| unless it is possible to cancel a
+`|push| |pop|' pair. The parameter to |dvi_pop| is the byte address
+following the old |push| that matches the new |pop|.
+
+ at p static void dvi_pop(int @!l)
+{@+if ((l==dvi_offset+dvi_ptr)&&(dvi_ptr > 0)) decr(dvi_ptr);
+else dvi_out(pop);
+}
+
+@ Here's a procedure that outputs a font definition. Since \TeX82 uses at
+most 256 different fonts per job, |fnt_def1| is always used as the command code.
+
+ at p static void dvi_font_def(internal_font_number @!f)
+{@+int k; /*index into |str_pool|*/
+dvi_out(fnt_def1);
+dvi_out(f-font_base-1);@/
+dvi_out(qo(font_check[f].b0));
+dvi_out(qo(font_check[f].b1));
+dvi_out(qo(font_check[f].b2));
+dvi_out(qo(font_check[f].b3));@/
+dvi_four(font_size[f]);
+dvi_four(font_dsize[f]);@/
+dvi_out(length(font_area[f]));
+dvi_out(length(font_name[f]));
+@<Output the font name whose internal number is |f|@>;
+}
+
+@ @<Output the font name whose internal number is |f|@>=
+for (k=str_start[font_area[f]]; k<=str_start[font_area[f]+1]-1; k++)
+  dvi_out(so(str_pool[k]));
+for (k=str_start[font_name[f]]; k<=str_start[font_name[f]+1]-1; k++)
+  dvi_out(so(str_pool[k]))
+
+@ Versions of \TeX\ intended for small computers might well choose to omit
+the ideas in the next few parts of this program, since it is not really
+necessary to optimize the \.{DVI} code by making use of the |w0|, |x0|,
+|y0|, and |z0| commands. Furthermore, the algorithm that we are about to
+describe does not pretend to give an optimum reduction in the length
+of the \.{DVI} code; after all, speed is more important than compactness.
+But the method is surprisingly effective, and it takes comparatively little
+time.
+
+We can best understand the basic idea by first considering a simpler problem
+that has the same essential characteristics. Given a sequence of digits,
+say $3\,1\,4\,1\,5\,9\,2\,6\,5\,3\,5\,8\,9$, we want to assign subscripts
+$d$, $y$, or $z$ to each digit so as to maximize the number of ``$y$-hits''
+and ``$z$-hits''; a $y$-hit is an instance of two appearances of the same
+digit with the subscript $y$, where no $y$'s intervene between the two
+appearances, and a $z$-hit is defined similarly. For example, the sequence
+above could be decorated with subscripts as follows:
+$$3_z\,1_y\,4_d\,1_y\,5_y\,9_d\,2_d\,6_d\,5_y\,3_z\,5_y\,8_d\,9_d.$$
+There are three $y$-hits ($1_y\ldots1_y$ and $5_y\ldots5_y\ldots5_y$) and
+one $z$-hit ($3_z\ldots3_z$); there are no $d$-hits, since the two appearances
+of $9_d$ have $d$'s between them, but we don't count $d$-hits so it doesn't
+matter how many there are. These subscripts are analogous to the \.{DVI}
+commands called \\{down}, $y$, and $z$, and the digits are analogous to
+different amounts of vertical motion; a $y$-hit or $z$-hit corresponds to
+the opportunity to use the one-byte commands |y0| or |z0| in a \.{DVI} file.
+
+\TeX's method of assigning subscripts works like this: Append a new digit,
+say $\delta$, to the right of the sequence. Now look back through the
+sequence until one of the following things happens: (a)~You see
+$\delta_y$ or $\delta_z$, and this was the first time you encountered a
+$y$ or $z$ subscript, respectively.  Then assign $y$ or $z$ to the new
+$\delta$; you have scored a hit. (b)~You see $\delta_d$, and no $y$
+subscripts have been encountered so far during this search.  Then change
+the previous $\delta_d$ to $\delta_y$ (this corresponds to changing a
+command in the output buffer), and assign $y$ to the new $\delta$; it's
+another hit.  (c)~You see $\delta_d$, and a $y$ subscript has been seen
+but not a $z$.  Change the previous $\delta_d$ to $\delta_z$ and assign
+$z$ to the new $\delta$. (d)~You encounter both $y$ and $z$ subscripts
+before encountering a suitable $\delta$, or you scan all the way to the
+front of the sequence. Assign $d$ to the new $\delta$; this assignment may
+be changed later.
+
+The subscripts $3_z\,1_y\,4_d\ldots\,$ in the example above were, in fact,
+produced by this procedure, as the reader can verify. (Go ahead and try it.)
+
+@ In order to implement such an idea, \TeX\ maintains a stack of pointers
+to the \\{down}, $y$, and $z$ commands that have been generated for the
+current page. And there is a similar stack for \\{right}, |w|, and |x|
+commands. These stacks are called the down stack and right stack, and their
+top elements are maintained in the variables |down_ptr| and |right_ptr|.
+
+Each entry in these stacks contains four fields: The |width| field is
+the amount of motion down or to the right; the |location| field is the
+byte number of the \.{DVI} command in question (including the appropriate
+|dvi_offset|); the |link| field points to the next item below this one
+on the stack; and the |info| field encodes the options for possible change
+in the \.{DVI} command.
+
+ at d movement_node_size 3 /*number of words per entry in the down and right stacks*/
+ at d location(A) mem[A+2].i /*\.{DVI} byte number for a movement command*/
+
+@<Glob...@>=
+static pointer @!down_ptr, @!right_ptr; /*heads of the down and right stacks*/
+
+@ @<Set init...@>=
+down_ptr=null;right_ptr=null;
+
+@ Here is a subroutine that produces a \.{DVI} command for some specified
+downward or rightward motion. It has two parameters: |w| is the amount
+of motion, and |o| is either |down1| or |right1|. We use the fact that
+the command codes have convenient arithmetic properties: |y1-down1==w1-right1|
+and |z1-down1==x1-right1|.
+
+ at p static void movement(scaled @!w, eight_bits @!o)
+{@+
+small_number mstate; /*have we seen a |y| or |z|?*/
+pointer @!p, @!q; /*current and top nodes on the stack*/
+int @!k; /*index into |dvi_buf|, modulo |dvi_buf_size|*/
+q=get_node(movement_node_size); /*new node for the top of the stack*/
+width(q)=w;location(q)=dvi_offset+dvi_ptr;
+if (o==down1)
+  {@+link(q)=down_ptr;down_ptr=q;
+  }
+else{@+link(q)=right_ptr;right_ptr=q;
+  }
+@<Look at the other stack entries until deciding what sort of \.{DVI} command to generate;
+|goto found| if node |p| is a ``hit''@>;
+@<Generate a |down| or |right| command for |w| and |return|@>;
+found: @<Generate a |y0| or |z0| command in order to reuse a previous appearance of~|w|@>;
+}
+
+@ The |info| fields in the entries of the down stack or the right stack
+have six possible settings: |y_here| or |z_here| mean that the \.{DVI}
+command refers to |y| or |z|, respectively (or to |w| or |x|, in the
+case of horizontal motion); |yz_OK| means that the \.{DVI} command is
+\\{down} (or \\{right}) but can be changed to either |y| or |z| (or
+to either |w| or |x|); |y_OK| means that it is \\{down} and can be changed
+to |y| but not |z|; |z_OK| is similar; and |d_fixed| means it must stay
+\\{down}.
+
+The four settings |yz_OK|, |y_OK|, |z_OK|, |d_fixed| would not need to
+be distinguished from each other if we were simply solving the
+digit-subscripting problem mentioned above. But in \TeX's case there is
+a complication because of the nested structure of |push| and |pop|
+commands. Suppose we add parentheses to the digit-subscripting problem,
+redefining hits so that $\delta_y\ldots \delta_y$ is a hit if all $y$'s between
+the $\delta$'s are enclosed in properly nested parentheses, and if the
+parenthesis level of the right-hand $\delta_y$ is deeper than or equal to
+that of the left-hand one. Thus, `(' and `)' correspond to `|push|'
+and `|pop|'. Now if we want to assign a subscript to the final 1 in the
+sequence
+$$2_y\,7_d\,1_d\,(\,8_z\,2_y\,8_z\,)\,1$$
+we cannot change the previous $1_d$ to $1_y$, since that would invalidate
+the $2_y\ldots2_y$ hit. But we can change it to $1_z$, scoring a hit
+since the intervening $8_z$'s are enclosed in parentheses.
+
+The program below removes movement nodes that are introduced after a |push|,
+before it outputs the corresponding |pop|.
+
+ at d y_here 1 /*|info| when the movement entry points to a |y| command*/
+ at d z_here 2 /*|info| when the movement entry points to a |z| command*/
+ at d yz_OK 3 /*|info| corresponding to an unconstrained \\{down} command*/
+ at d y_OK 4 /*|info| corresponding to a \\{down} that can't become a |z|*/
+ at d z_OK 5 /*|info| corresponding to a \\{down} that can't become a |y|*/
+ at d d_fixed 6 /*|info| corresponding to a \\{down} that can't change*/
+
+@ When the |movement| procedure gets to the label |found|, the value of
+|info(p)| will be either |y_here| or |z_here|. If it is, say, |y_here|,
+the procedure generates a |y0| command (or a |w0| command), and marks
+all |info| fields between |q| and |p| so that |y| is not OK in that range.
+
+@<Generate a |y0| or |z0| command...@>=
+info(q)=info(p);
+if (info(q)==y_here)
+  {@+dvi_out(o+y0-down1); /*|y0| or |w0|*/
+  while (link(q)!=p)
+    {@+q=link(q);
+    switch (info(q)) {
+    case yz_OK: info(q)=z_OK;@+break;
+    case y_OK: info(q)=d_fixed;@+break;
+    default:do_nothing;
+    }
+    }
+  }
+else{@+dvi_out(o+z0-down1); /*|z0| or |x0|*/
+  while (link(q)!=p)
+    {@+q=link(q);
+    switch (info(q)) {
+    case yz_OK: info(q)=y_OK;@+break;
+    case z_OK: info(q)=d_fixed;@+break;
+    default:do_nothing;
+    }
+    }
+  }
+
+@ @<Generate a |down| or |right|...@>=
+info(q)=yz_OK;
+if (abs(w) >= 040000000)
+  {@+dvi_out(o+3); /*|down4| or |right4|*/
+  dvi_four(w);return;
+  }
+if (abs(w) >= 0100000)
+  {@+dvi_out(o+2); /*|down3| or |right3|*/
+  if (w < 0) w=w+0100000000;
+  dvi_out(w/0200000);w=w%0200000;goto label2;
+  }
+if (abs(w) >= 0200)
+  {@+dvi_out(o+1); /*|down2| or |right2|*/
+  if (w < 0) w=w+0200000;
+  goto label2;
+  }
+dvi_out(o); /*|down1| or |right1|*/
+if (w < 0) w=w+0400;
+goto label1;
+label2: dvi_out(w/0400);
+label1: dvi_out(w%0400);return
+
+@ As we search through the stack, we are in one of three states,
+|y_seen|, |z_seen|, or |none_seen|, depending on whether we have
+encountered |y_here| or |z_here| nodes. These states are encoded as
+multiples of 6, so that they can be added to the |info| fields for quick
+decision-making.
+@^inner loop@>
+
+ at d none_seen 0 /*no |y_here| or |z_here| nodes have been encountered yet*/
+ at d y_seen 6 /*we have seen |y_here| but not |z_here|*/
+ at d z_seen 12 /*we have seen |z_here| but not |y_here|*/
+
+@<Look at the other stack entries until deciding...@>=
+p=link(q);mstate=none_seen;
+while (p!=null)
+  {@+if (width(p)==w) @<Consider a node with matching width; |goto found| if it's
+a hit@>@;
+  else switch (mstate+info(p)) {
+    case none_seen+y_here: mstate=y_seen;@+break;
+    case none_seen+z_here: mstate=z_seen;@+break;
+    case y_seen+z_here: case z_seen+y_here: goto not_found;
+    default:do_nothing;
+    }
+  p=link(p);
+  }
+not_found:
+
+@ We might find a valid hit in a |y| or |z| byte that is already gone
+from the buffer. But we can't change bytes that are gone forever; ``the
+moving finger writes, $\ldots\,\,$.''
+
+@<Consider a node with matching width...@>=
+switch (mstate+info(p)) {
+case none_seen+yz_OK: case none_seen+y_OK: case z_seen+yz_OK: case z_seen+y_OK: @t@>@;@/
+  if (location(p) < dvi_gone) goto not_found;
+  else@<Change buffered instruction to |y| or |w| and |goto found|@>@;@+break;
+case none_seen+z_OK: case y_seen+yz_OK: case y_seen+z_OK: @t@>@;@/
+  if (location(p) < dvi_gone) goto not_found;
+  else@<Change buffered instruction to |z| or |x| and |goto found|@>@;@+break;
+case none_seen+y_here: case none_seen+z_here: case y_seen+z_here: case z_seen+y_here: goto found;
+default:do_nothing;
+}
+
+@ @<Change buffered instruction to |y| or |w| and |goto found|@>=
+{@+k=location(p)-dvi_offset;
+if (k < 0) k=k+dvi_buf_size;
+dvi_buf[k]=dvi_buf[k]+y1-down1;
+info(p)=y_here;goto found;
+}
+
+@ @<Change buffered instruction to |z| or |x| and |goto found|@>=
+{@+k=location(p)-dvi_offset;
+if (k < 0) k=k+dvi_buf_size;
+dvi_buf[k]=dvi_buf[k]+z1-down1;
+info(p)=z_here;goto found;
+}
+
+@ In case you are wondering when all the movement nodes are removed from
+\TeX's memory, the answer is that they are recycled just before
+|hlist_out| and |vlist_out| finish outputting a box. This restores the
+down and right stacks to the state they were in before the box was output,
+except that some |info|'s may have become more restrictive.
+
+ at p static void prune_movements(int @!l)
+   /*delete movement nodes with |location >= l|*/
+{@+
+pointer p; /*node being deleted*/
+while (down_ptr!=null)
+  {@+if (location(down_ptr) < l) goto done;
+  p=down_ptr;down_ptr=link(p);free_node(p, movement_node_size);
+  }
+done: while (right_ptr!=null)
+  {@+if (location(right_ptr) < l) return;
+  p=right_ptr;right_ptr=link(p);free_node(p, movement_node_size);
+  }
+}
+
+@ The actual distances by which we want to move might be computed as the
+sum of several separate movements. For example, there might be several
+glue nodes in succession, or we might want to move right by the width of
+some box plus some amount of glue. More importantly, the baselineskip
+distances are computed in terms of glue together with the depth and
+height of adjacent boxes, and we want the \.{DVI} file to lump these
+three quantities together into a single motion.
+
+Therefore, \TeX\ maintains two pairs of global variables: |dvi_h| and |dvi_v|
+are the |h| and |v| coordinates corresponding to the commands actually
+output to the \.{DVI} file, while |cur_h| and |cur_v| are the coordinates
+corresponding to the current state of the output routines. Coordinate
+changes will accumulate in |cur_h| and |cur_v| without being reflected
+in the output, until such a change becomes necessary or desirable; we
+can call the |movement| procedure whenever we want to make |dvi_h==cur_h|
+or |dvi_v==cur_v|.
+
+The current font reflected in the \.{DVI} output is called |dvi_f|;
+there is no need for a `\\{cur\_f}' variable.
+
+The depth of nesting of |hlist_out| and |vlist_out| is called |cur_s|;
+this is essentially the depth of |push| commands in the \.{DVI} output.
+
+ at d synch_h if (cur_h!=dvi_h)
+    {@+movement(cur_h-dvi_h, right1);dvi_h=cur_h;
+    }
+ at d synch_v if (cur_v!=dvi_v)
+    {@+movement(cur_v-dvi_v, down1);dvi_v=cur_v;
+    }
+
+@<Glob...@>=
+static scaled @!dvi_h, @!dvi_v; /*a \.{DVI} reader program thinks we are here*/
+static scaled @!cur_h, @!cur_v; /*\TeX\ thinks we are here*/
+static internal_font_number @!dvi_f; /*the current font*/
+static int @!cur_s; /*current depth of output box nesting, initially $-1$*/
+
+@ @<Initialize variables as |ship_out| begins@>=
+dvi_h=0;dvi_v=0;cur_h=h_offset;dvi_f=null_font;
+ensure_dvi_open;
+if (total_pages==0)
+  {@+dvi_out(pre);dvi_out(id_byte); /*output the preamble*/
+@^preamble of \.{DVI} file@>
+  dvi_four(25400000);dvi_four(473628672); /*conversion ratio for sp*/
+  prepare_mag();dvi_four(mag); /*magnification factor is frozen*/
+  old_setting=selector;selector=new_string;
+  print(" TeX output ");print_int(year);print_char('.');
+  print_two(month);print_char('.');print_two(day);
+  print_char(':');print_two(time/60);
+  print_two(time%60);
+  selector=old_setting;dvi_out(cur_length);
+  for (s=str_start[str_ptr]; s<=pool_ptr-1; s++) dvi_out(so(str_pool[s]));
+  pool_ptr=str_start[str_ptr]; /*flush the current string*/
+  }
+
+@ When |hlist_out| is called, its duty is to output the box represented
+by the |hlist_node| pointed to by |temp_ptr|. The reference point of that
+box has coordinates |(cur_h, cur_v)|.
+
+Similarly, when |vlist_out| is called, its duty is to output the box represented
+by the |vlist_node| pointed to by |temp_ptr|. The reference point of that
+box has coordinates |(cur_h, cur_v)|.
+@^recursion@>
+
+ at p static void vlist_out(void); /*|hlist_out| and |vlist_out| are mutually
+  recursive*/
+
+@ The recursive procedures |hlist_out| and |vlist_out| each have local variables
+|save_h| and |save_v| to hold the values of |dvi_h| and |dvi_v| just before
+entering a new level of recursion.  In effect, the values of |save_h| and
+|save_v| on \TeX's run-time stack correspond to the values of |h| and |v|
+that a \.{DVI}-reading program will push onto its coordinate stack.
+
+ at p @t\4@>@<Declare procedures needed in |hlist_out|, |vlist_out|@>@t@>@/
+static void hlist_out(void) /*output an |hlist_node| box*/
+{@+
+scaled base_line; /*the baseline coordinate for this box*/
+scaled @!left_edge; /*the left coordinate for this box*/
+scaled @!save_h, @!save_v; /*what |dvi_h| and |dvi_v| should pop to*/
+pointer @!this_box; /*pointer to containing box*/
+glue_ord @!g_order; /*applicable order of infinity for glue*/
+int @!g_sign; /*selects type of glue*/
+pointer @!p; /*current position in the hlist*/
+int @!save_loc; /*\.{DVI} byte location upon entry*/
+pointer @!leader_box; /*the leader box being replicated*/
+scaled @!leader_wd; /*width of leader box being replicated*/
+scaled @!lx; /*extra space between leader boxes*/
+bool @!outer_doing_leaders; /*were we doing leaders?*/
+scaled @!edge; /*left edge of sub-box, or right edge of leader space*/
+double @!glue_temp; /*glue value before rounding*/
+double @!cur_glue; /*glue seen so far*/
+scaled @!cur_g; /*rounded equivalent of |cur_glue| times the glue ratio*/
+cur_g=0;cur_glue=float_constant(0);
+this_box=temp_ptr;g_order=glue_order(this_box);
+g_sign=glue_sign(this_box);p=list_ptr(this_box);
+incr(cur_s);
+if (cur_s > 0) dvi_out(push);
+if (cur_s > max_push) max_push=cur_s;
+save_loc=dvi_offset+dvi_ptr;base_line=cur_v;left_edge=cur_h;
+while (p!=null) @<Output node |p| for |hlist_out| and move to the next node, maintaining
+the condition |cur_v=base_line|@>;
+prune_movements(save_loc);
+if (cur_s > 0) dvi_pop(save_loc);
+decr(cur_s);
+}
+
+@ We ought to give special care to the efficiency of one part of |hlist_out|,
+since it belongs to \TeX's inner loop. When a |char_node| is encountered,
+we save a little time by processing several nodes in succession until
+reaching a non-|char_node|. The program uses the fact that |set_char_0==0|.
+@^inner loop@>
+
+@<Output node |p| for |hlist_out|...@>=
+reswitch: if (is_char_node(p))
+  {@+synch_h;synch_v;
+  @/do at +{f=font(p);c=character(p);
+  if (f!=dvi_f) @<Change font |dvi_f| to |f|@>;
+  if (c >= qi(128)) dvi_out(set1);
+  dvi_out(qo(c));@/
+  cur_h=cur_h+char_width(f, char_info(f, c));
+  p=link(p);
+  }@+ while (!(!is_char_node(p)));
+  dvi_h=cur_h;
+  }
+else@<Output the non-|char_node| |p| for |hlist_out| and move to the next node@>@;
+
+@ @<Change font |dvi_f| to |f|@>=
+{@+if (!font_used[f])
+  {@+dvi_font_def(f);font_used[f]=true;
+  }
+if (f <= 64+font_base) dvi_out(f-font_base-1+fnt_num_0)@;
+else{@+dvi_out(fnt1);dvi_out(f-font_base-1);
+  }
+dvi_f=f;
+}
+
+@ @<Output the non-|char_node| |p| for |hlist_out|...@>=
+{@+switch (type(p)) {
+case hlist_node: case vlist_node: @<Output a box in an hlist@>@;@+break;
+case rule_node: {@+rule_ht=height(p);rule_dp=depth(p);rule_wd=width(p);
+  goto fin_rule;
+  }
+case whatsit_node: @<Output the whatsit node |p| in an hlist@>;@+break;
+case glue_node: @<Move right or output leaders@>@;
+case kern_node: case math_node: cur_h=cur_h+width(p);@+break;
+case ligature_node: @<Make node |p| look like a |char_node| and |goto reswitch|@>@;
+default:do_nothing;
+} @/
+goto next_p;
+fin_rule: @<Output a rule in an hlist@>;
+move_past: cur_h=cur_h+rule_wd;
+next_p: p=link(p);
+}
+
+@ @<Output a box in an hlist@>=
+if (list_ptr(p)==null) cur_h=cur_h+width(p);
+else{@+save_h=dvi_h;save_v=dvi_v;
+  cur_v=base_line+shift_amount(p); /*shift the box down*/
+  temp_ptr=p;edge=cur_h;
+  if (type(p)==vlist_node) vlist_out();@+else hlist_out();
+  dvi_h=save_h;dvi_v=save_v;
+  cur_h=edge+width(p);cur_v=base_line;
+  }
+
+@ @<Output a rule in an hlist@>=
+if (is_running(rule_ht)) rule_ht=height(this_box);
+if (is_running(rule_dp)) rule_dp=depth(this_box);
+rule_ht=rule_ht+rule_dp; /*this is the rule thickness*/
+if ((rule_ht > 0)&&(rule_wd > 0))  /*we don't output empty rules*/
+  {@+synch_h;cur_v=base_line+rule_dp;synch_v;
+  dvi_out(set_rule);dvi_four(rule_ht);dvi_four(rule_wd);
+  cur_v=base_line;dvi_h=dvi_h+rule_wd;
+  }
+
+@ @d billion float_constant(1000000000)
+ at d vet_glue(A) glue_temp=A;
+  if (glue_temp > billion)
+           glue_temp=billion;
+  else if (glue_temp < -billion)
+           glue_temp=-billion
+
+@<Move right or output leaders@>=
+{@+g=glue_ptr(p);rule_wd=width(g)-cur_g;
+if (g_sign!=normal)
+  {@+if (g_sign==stretching)
+    {@+if (stretch_order(g)==g_order)
+      {@+cur_glue=cur_glue+stretch(g);
+      vet_glue(float(glue_set(this_box))*cur_glue);
+@^real multiplication@>
+      cur_g=round(glue_temp);
+      }
+    }
+  else if (shrink_order(g)==g_order)
+      {@+cur_glue=cur_glue-shrink(g);
+      vet_glue(float(glue_set(this_box))*cur_glue);
+      cur_g=round(glue_temp);
+      }
+  }
+rule_wd=rule_wd+cur_g;
+if (subtype(p) >= a_leaders)
+  @<Output leaders in an hlist, |goto fin_rule| if a rule or to |next_p| if done@>;
+goto move_past;
+}
+
+@ @<Output leaders in an hlist...@>=
+{@+leader_box=leader_ptr(p);
+if (type(leader_box)==rule_node)
+  {@+rule_ht=height(leader_box);rule_dp=depth(leader_box);
+  goto fin_rule;
+  }
+leader_wd=width(leader_box);
+if ((leader_wd > 0)&&(rule_wd > 0))
+  {@+rule_wd=rule_wd+10; /*compensate for floating-point rounding*/
+  edge=cur_h+rule_wd;lx=0;
+  @<Let |cur_h| be the position of the first box, and set |leader_wd+lx| to the spacing
+between corresponding parts of boxes@>;
+  while (cur_h+leader_wd <= edge)
+    @<Output a leader box at |cur_h|, then advance |cur_h| by |leader_wd+lx|@>;
+  cur_h=edge-10;goto next_p;
+  }
+}
+
+@ The calculations related to leaders require a bit of care. First, in the
+case of |a_leaders| (aligned leaders), we want to move |cur_h| to
+|left_edge| plus the smallest multiple of |leader_wd| for which the result
+is not less than the current value of |cur_h|; i.e., |cur_h| should become
+$|left_edge|+|leader_wd|\times\lceil
+(|cur_h|-|left_edge|)/|leader_wd|\rceil$.  The program here should work in
+all cases even though some implementations of \PASCAL\ give nonstandard
+results for the |/| operation when |cur_h| is less than |left_edge|.
+
+In the case of |c_leaders| (centered leaders), we want to increase |cur_h|
+by half of the excess space not occupied by the leaders; and in the
+case of |x_leaders| (expanded leaders) we increase |cur_h|
+by $1/(q+1)$ of this excess space, where $q$ is the number of times the
+leader box will be replicated. Slight inaccuracies in the division might
+accumulate; half of this rounding error is placed at each end of the leaders.
+
+@<Let |cur_h| be the position of the first box,...@>=
+if (subtype(p)==a_leaders)
+  {@+save_h=cur_h;
+  cur_h=left_edge+leader_wd*((cur_h-left_edge)/leader_wd);
+  if (cur_h < save_h) cur_h=cur_h+leader_wd;
+  }
+else{@+lq=rule_wd/leader_wd; /*the number of box copies*/
+  lr=rule_wd%leader_wd; /*the remaining space*/
+  if (subtype(p)==c_leaders) cur_h=cur_h+(lr/2);
+  else{@+lx=lr/(lq+1);
+    cur_h=cur_h+((lr-(lq-1)*lx)/2);
+    }
+  }
+
+@ The `\\{synch}' operations here are intended to decrease the number of
+bytes needed to specify horizontal and vertical motion in the \.{DVI} output.
+
+@<Output a leader box at |cur_h|,...@>=
+{@+cur_v=base_line+shift_amount(leader_box);synch_v;save_v=dvi_v;@/
+synch_h;save_h=dvi_h;temp_ptr=leader_box;
+outer_doing_leaders=doing_leaders;doing_leaders=true;
+if (type(leader_box)==vlist_node) vlist_out();@+else hlist_out();
+doing_leaders=outer_doing_leaders;
+dvi_v=save_v;dvi_h=save_h;cur_v=base_line;
+cur_h=save_h+leader_wd+lx;
+}
+
+@ The |vlist_out| routine is similar to |hlist_out|, but a bit simpler.
+
+ at p static void vlist_out(void) /*output a |vlist_node| box*/
+{@+
+scaled left_edge; /*the left coordinate for this box*/
+scaled @!top_edge; /*the top coordinate for this box*/
+scaled @!save_h, @!save_v; /*what |dvi_h| and |dvi_v| should pop to*/
+pointer @!this_box; /*pointer to containing box*/
+glue_ord @!g_order; /*applicable order of infinity for glue*/
+int @!g_sign; /*selects type of glue*/
+pointer @!p; /*current position in the vlist*/
+int @!save_loc; /*\.{DVI} byte location upon entry*/
+pointer @!leader_box; /*the leader box being replicated*/
+scaled @!leader_ht; /*height of leader box being replicated*/
+scaled @!lx; /*extra space between leader boxes*/
+bool @!outer_doing_leaders; /*were we doing leaders?*/
+scaled @!edge; /*bottom boundary of leader space*/
+double @!glue_temp; /*glue value before rounding*/
+double @!cur_glue; /*glue seen so far*/
+scaled @!cur_g; /*rounded equivalent of |cur_glue| times the glue ratio*/
+cur_g=0;cur_glue=float_constant(0);
+this_box=temp_ptr;g_order=glue_order(this_box);
+g_sign=glue_sign(this_box);p=list_ptr(this_box);
+incr(cur_s);
+if (cur_s > 0) dvi_out(push);
+if (cur_s > max_push) max_push=cur_s;
+save_loc=dvi_offset+dvi_ptr;left_edge=cur_h;cur_v=cur_v-height(this_box);
+top_edge=cur_v;
+while (p!=null) @<Output node |p| for |vlist_out| and move to the next node, maintaining
+the condition |cur_h=left_edge|@>;
+prune_movements(save_loc);
+if (cur_s > 0) dvi_pop(save_loc);
+decr(cur_s);
+}
+
+@ @<Output node |p| for |vlist_out|...@>=
+{@+if (is_char_node(p)) confusion("vlistout");
+@:this can't happen vlistout}{\quad vlistout@>
+else@<Output the non-|char_node| |p| for |vlist_out|@>;
+next_p: p=link(p);
+}
+
+@ @<Output the non-|char_node| |p| for |vlist_out|@>=
+{@+switch (type(p)) {
+case hlist_node: case vlist_node: @<Output a box in a vlist@>@;@+break;
+case rule_node: {@+rule_ht=height(p);rule_dp=depth(p);rule_wd=width(p);
+  goto fin_rule;
+  }
+case whatsit_node: @<Output the whatsit node |p| in a vlist@>;@+break;
+case glue_node: @<Move down or output leaders@>@;
+case kern_node: cur_v=cur_v+width(p);@+break;
+default:do_nothing;
+} @/
+goto next_p;
+fin_rule: @<Output a rule in a vlist, |goto next_p|@>;
+move_past: cur_v=cur_v+rule_ht;
+}
+
+@ The |synch_v| here allows the \.{DVI} output to use one-byte commands
+for adjusting |v| in most cases, since the baselineskip distance will
+usually be constant.
+
+@<Output a box in a vlist@>=
+if (list_ptr(p)==null) cur_v=cur_v+height(p)+depth(p);
+else{@+cur_v=cur_v+height(p);synch_v;
+  save_h=dvi_h;save_v=dvi_v;
+  cur_h=left_edge+shift_amount(p); /*shift the box right*/
+  temp_ptr=p;
+  if (type(p)==vlist_node) vlist_out();@+else hlist_out();
+  dvi_h=save_h;dvi_v=save_v;
+  cur_v=save_v+depth(p);cur_h=left_edge;
+  }
+
+@ @<Output a rule in a vlist...@>=
+if (is_running(rule_wd)) rule_wd=width(this_box);
+rule_ht=rule_ht+rule_dp; /*this is the rule thickness*/
+cur_v=cur_v+rule_ht;
+if ((rule_ht > 0)&&(rule_wd > 0))  /*we don't output empty rules*/
+  {@+synch_h;synch_v;
+  dvi_out(put_rule);dvi_four(rule_ht);dvi_four(rule_wd);
+  }
+goto next_p
+
+@ @<Move down or output leaders@>=
+{@+g=glue_ptr(p);rule_ht=width(g)-cur_g;
+if (g_sign!=normal)
+  {@+if (g_sign==stretching)
+    {@+if (stretch_order(g)==g_order)
+      {@+cur_glue=cur_glue+stretch(g);
+      vet_glue(float(glue_set(this_box))*cur_glue);
+@^real multiplication@>
+      cur_g=round(glue_temp);
+      }
+    }
+  else if (shrink_order(g)==g_order)
+      {@+cur_glue=cur_glue-shrink(g);
+      vet_glue(float(glue_set(this_box))*cur_glue);
+      cur_g=round(glue_temp);
+      }
+  }
+rule_ht=rule_ht+cur_g;
+if (subtype(p) >= a_leaders)
+  @<Output leaders in a vlist, |goto fin_rule| if a rule or to |next_p| if done@>;
+goto move_past;
+}
+
+@ @<Output leaders in a vlist...@>=
+{@+leader_box=leader_ptr(p);
+if (type(leader_box)==rule_node)
+  {@+rule_wd=width(leader_box);rule_dp=0;
+  goto fin_rule;
+  }
+leader_ht=height(leader_box)+depth(leader_box);
+if ((leader_ht > 0)&&(rule_ht > 0))
+  {@+rule_ht=rule_ht+10; /*compensate for floating-point rounding*/
+  edge=cur_v+rule_ht;lx=0;
+  @<Let |cur_v| be the position of the first box, and set |leader_ht+lx| to the spacing
+between corresponding parts of boxes@>;
+  while (cur_v+leader_ht <= edge)
+    @<Output a leader box at |cur_v|, then advance |cur_v| by |leader_ht+lx|@>;
+  cur_v=edge-10;goto next_p;
+  }
+}
+
+@ @<Let |cur_v| be the position of the first box,...@>=
+if (subtype(p)==a_leaders)
+  {@+save_v=cur_v;
+  cur_v=top_edge+leader_ht*((cur_v-top_edge)/leader_ht);
+  if (cur_v < save_v) cur_v=cur_v+leader_ht;
+  }
+else{@+lq=rule_ht/leader_ht; /*the number of box copies*/
+  lr=rule_ht%leader_ht; /*the remaining space*/
+  if (subtype(p)==c_leaders) cur_v=cur_v+(lr/2);
+  else{@+lx=lr/(lq+1);
+    cur_v=cur_v+((lr-(lq-1)*lx)/2);
+    }
+  }
+
+@ When we reach this part of the program, |cur_v| indicates the top of a
+leader box, not its baseline.
+
+@<Output a leader box at |cur_v|,...@>=
+{@+cur_h=left_edge+shift_amount(leader_box);synch_h;save_h=dvi_h;@/
+cur_v=cur_v+height(leader_box);synch_v;save_v=dvi_v;
+temp_ptr=leader_box;
+outer_doing_leaders=doing_leaders;doing_leaders=true;
+if (type(leader_box)==vlist_node) vlist_out();@+else hlist_out();
+doing_leaders=outer_doing_leaders;
+dvi_v=save_v;dvi_h=save_h;cur_h=left_edge;
+cur_v=save_v-height(leader_box)+leader_ht+lx;
+}
+
+@ The |hlist_out| and |vlist_out| procedures are now complete, so we are
+ready for the |ship_out| routine that gets them started in the first place.
+
+ at p static void ship_out(pointer @!p) /*output the box |p|*/
+{@+
+execute_output(p);
+flush_node_list(p);
+}
+
+@ @<Flush the box from memory, showing statistics if requested@>=
+#ifdef @!STAT
+if (tracing_stats > 1)
+  {@+print_nl("Memory usage before: ");
+ at .Memory usage...@>
+  print_int(var_used);print_char('&');
+  print_int(dyn_used);print_char(';');
+  }
+#endif
+flush_node_list(p);
+#ifdef @!STAT
+if (tracing_stats > 1)
+  {@+print(" after: ");
+  print_int(var_used);print_char('&');
+  print_int(dyn_used);print("; still untouched: ");
+  print_int(hi_mem_min-lo_mem_max-1);print_ln();
+  }
+#endif
+
+@ @<Ship box |p| out@>=
+@<Update the values of |max_h| and |max_v|; but if the page is too large, |goto done|@>;
+@<Initialize variables as |ship_out| begins@>;
+page_loc=dvi_offset+dvi_ptr;
+dvi_out(bop);
+for (k=0; k<=9; k++) dvi_four(count(k));
+dvi_four(last_bop);last_bop=page_loc;
+cur_v=height(p)+v_offset;temp_ptr=p;
+if (type(p)==vlist_node) vlist_out();@+else hlist_out();
+dvi_out(eop);incr(total_pages);cur_s=-1;
+done:
+
+@ Sometimes the user will generate a huge page because other error messages
+are being ignored. Such pages are not output to the \.{dvi} file, since they
+may confuse the printing software.
+
+@<Update the values of |max_h| and |max_v|; but if the page is too large...@>=
+if ((height(p) > max_dimen)||@|(depth(p) > max_dimen)||@|
+   (height(p)+depth(p)+v_offset > max_dimen)||@|
+   (width(p)+h_offset > max_dimen))
+  {@+print_err("Huge page cannot be shipped out");
+ at .Huge page...@>
+  help2("The page just created is more than 18 feet tall or",@/
+   "more than 18 feet wide, so I suspect something went wrong.");
+  error();
+  if (tracing_output <= 0)
+    {@+begin_diagnostic();
+    print_nl("The following box has been deleted:");
+ at .The following...deleted@>
+    show_box(p);
+    end_diagnostic(true);
+    }
+  goto done;
+  }
+if (height(p)+depth(p)+v_offset > max_v) max_v=height(p)+depth(p)+v_offset;
+if (width(p)+h_offset > max_h) max_h=width(p)+h_offset
+
+@ At the end of the program, we must finish things off by writing the
+post\-amble. If |total_pages==0|, the \.{DVI} file was never opened.
+If |total_pages >= 65536|, the \.{DVI} file will lie. And if
+|max_push >= 65536|, the user deserves whatever chaos might ensue.
+
+An integer variable |k| will be declared for use by this routine.
+
+@<Finish the \.{DVI} file@>=
+while (cur_s > -1)
+  {@+if (cur_s > 0) dvi_out(pop)@;
+  else{@+dvi_out(eop);incr(total_pages);
+    }
+  decr(cur_s);
+  }
+if (total_pages==0) print_nl("No pages of output.");
+ at .No pages of output@>
+else{@+dvi_out(post); /*beginning of the postamble*/
+  dvi_four(last_bop);last_bop=dvi_offset+dvi_ptr-5; /*|post| location*/
+  dvi_four(25400000);dvi_four(473628672); /*conversion ratio for sp*/
+  prepare_mag();dvi_four(mag); /*magnification factor*/
+  dvi_four(max_v);dvi_four(max_h);@/
+  dvi_out(max_push/256);dvi_out(max_push%256);@/
+  dvi_out((total_pages/256)%256);dvi_out(total_pages%256);@/
+  @<Output the font definitions for all fonts that were used@>;
+  dvi_out(post_post);dvi_four(last_bop);dvi_out(id_byte);@/
+  k=4+((dvi_buf_size-dvi_ptr)%4); /*the number of 223's*/
+  while (k > 0)
+    {@+dvi_out(223);decr(k);
+    }
+  @<Empty the last bytes out of |dvi_buf|@>;
+  print_nl("Output written on ");slow_print(output_file_name);
+ at .Output written on x@>
+  print(" (");print_int(total_pages);print(" page");
+  if (total_pages!=1) print_char('s');
+  print(", ");print_int(dvi_offset+dvi_ptr);print(" bytes).");
+  b_close(&dvi_file);
+  }
+
+@ @<Output the font definitions...@>=
+while (font_ptr > font_base)
+  {@+if (font_used[font_ptr]) dvi_font_def(font_ptr);
+  decr(font_ptr);
+  }
+
+@* Packaging.
+We're essentially done with the parts of \TeX\ that are concerned with
+the input (|get_next|) and the output (|ship_out|). So it's time to
+get heavily into the remaining part, which does the real work of typesetting.
+
+After lists are constructed, \TeX\ wraps them up and puts them into boxes.
+Two major subroutines are given the responsibility for this task: |hpack|
+applies to horizontal lists (hlists) and |vpack| applies to vertical lists
+(vlists). The main duty of |hpack| and |vpack| is to compute the dimensions
+of the resulting boxes, and to adjust the glue if one of those dimensions
+is pre-specified. The computed sizes normally enclose all of the material
+inside the new box; but some items may stick out if negative glue is used,
+if the box is overfull, or if a \.{\\vbox} includes other boxes that have
+been shifted left.
+
+The subroutine call |hpack(p, w, m)| returns a pointer to an |hlist_node|
+for a box containing the hlist that starts at |p|. Parameter |w| specifies
+a width; and parameter |m| is either `|exactly|' or `|additional|'.  Thus,
+|hpack(p, w, exactly)| produces a box whose width is exactly |w|, while
+|hpack(p, w, additional)| yields a box whose width is the natural width plus
+|w|.  It is convenient to define a macro called `|natural|' to cover the
+most common case, so that we can say |hpack(p, natural)| to get a box that
+has the natural width of list |p|.
+
+Similarly, |vpack(p, w, m)| returns a pointer to a |vlist_node| for a
+box containing the vlist that starts at |p|. In this case |w| represents
+a height instead of a width; the parameter |m| is interpreted as in |hpack|.
+
+ at d exactly 0 /*a box dimension is pre-specified*/
+ at d additional 1 /*a box dimension is increased from the natural one*/
+ at d natural 0, 0, 0, additional /*shorthand for parameters to |hpack| and |vpack|*/
+
+@ The parameters to |hpack| and |vpack| correspond to \TeX's primitives
+like `\.{\\hbox} \.{to} \.{300pt}', `\.{\\hbox} \.{spread} \.{10pt}'; note
+that `\.{\\hbox}' with no dimension following it is equivalent to
+`\.{\\hbox} \.{spread} \.{0pt}'.  The |scan_spec| subroutine scans such
+constructions in the user's input, including the mandatory left brace that
+follows them, and it puts the specification onto |save_stack| so that the
+desired box can later be obtained by executing the following code:
+$$\vbox{\halign{#\hfil\cr
+|save_ptr=save_ptr-2;|\cr
+|hpack(p, saved(1), saved(0)).|\cr}}$$
+Special care is necessary to ensure that the special |save_stack| codes
+are placed just below the new group code, because scanning can change
+|save_stack| when \.{\\csname} appears.
+
+ at p static void scan_spec(group_code @!c, bool @!three_codes)
+   /*scans a box specification and left brace*/
+{@+
+int @!s; /*temporarily saved value*/
+int @!spec_code;
+if (three_codes) s=saved(0);
+if (scan_keyword("to")) spec_code=exactly;
+ at .to@>
+else if (scan_keyword("spread")) spec_code=additional;
+ at .spread@>
+else{@+spec_code=additional;cur_val=cur_hfactor=cur_vfactor=0;
+  goto found;
+  }
+scan_normal_dimen;
+found: if (three_codes)
+  {@+saved(0)=s;incr(save_ptr);
+  }
+saved(0)=spec_code;saved(1)=cur_val;
+saved_hfactor(1)=cur_hfactor;
+saved_vfactor(1)=cur_vfactor;
+save_ptr=save_ptr+2;
+new_save_level(c);scan_left_brace();
+}
+
+@ To figure out the glue setting, |hpack| and |vpack| determine how much
+stretchability and shrinkability are present, considering all four orders
+of infinity. The highest order of infinity that has a nonzero coefficient
+is then used as if no other orders were present.
+
+For example, suppose that the given list contains six glue nodes with
+the respective stretchabilities 3pt, 8fill, 5fil, 6pt, $-3$fil, $-8$fill.
+Then the total is essentially 2fil; and if a total additional space of 6pt
+is to be achieved by stretching, the actual amounts of stretch will be
+0pt, 0pt, 15pt, 0pt, $-9$pt, and 0pt, since only `fil' glue will be
+considered. (The `fill' glue is therefore not really stretching infinitely
+with respect to `fil'; nobody would actually want that to happen.)
+
+The arrays |total_stretch| and |total_shrink| are used to determine how much
+glue of each kind is present. A global variable |last_badness| is used
+to implement \.{\\badness}.
+
+@<Glob...@>=
+static scaled @!total_stretch0[filll-normal+1], *const @!total_stretch = @!total_stretch0-normal, @!total_shrink0[filll-normal+1], *const @!total_shrink = @!total_shrink0-normal;
+   /*glue found by |hpack| or |vpack|*/
+static int @!last_badness; /*badness of the most recently packaged box*/
+
+@ If the global variable |adjust_tail| is non-null, the |hpack| routine
+also removes all occurrences of |ins_node|, |mark_node|, and |adjust_node|
+items and appends the resulting material onto the list that ends at
+location |adjust_tail|.
+
+@<Glob...@>=
+static pointer @!adjust_tail; /*tail of adjustment list*/
+
+@ @<Set init...@>=adjust_tail=null;last_badness=0;
+
+@ Here now is |hpack|, which contains few if any surprises.
+
+ at p static pointer hpack(pointer p, scaled w, scaled hf, scaled vf, small_number m);
+
+@ @<Clear dimensions to zero@>=
+d=0;x=0;
+total_stretch[normal]=0;total_shrink[normal]=0;
+total_stretch[fil]=0;total_shrink[fil]=0;
+total_stretch[fill]=0;total_shrink[fill]=0;
+total_stretch[filll]=0;total_shrink[filll]=0
+
+@ @<Examine node |p| in the hlist, taking account of its effect...@>=
+@^inner loop@>
+{@+reswitch: while (is_char_node(p))
+  @<Incorporate character dimensions into the dimensions of the hbox that will contain~it,
+then move to the next node@>;
+if (p!=null)
+  {@+switch (type(p)) {
+  case hlist_node: case vlist_node: case rule_node: case unset_node: case unset_set_node: case unset_pack_node:
+    @<Incorporate box dimensions into the dimensions of the hbox that will contain~it@>@;@+break;
+  case ins_node: case mark_node: case adjust_node: if (adjust_tail!=null)
+    @<Transfer node |p| to the adjustment list@>@;@+break;
+  case whatsit_node: @<Incorporate a whatsit node into an hbox@>;@+break;
+  case glue_node: @<Incorporate glue into the horizontal totals@>@;@+break;
+  case kern_node: case math_node: x=x+width(p);@+break;
+  case ligature_node: @<Make node |p| look like a |char_node| and |goto reswitch|@>@;
+  default:do_nothing;
+  } @/
+  p=link(p);
+  }
+}
+
+
+@ @<Make node |p| look like a |char_node| and |goto reswitch|@>=
+{@+mem[lig_trick]=mem[lig_char(p)];link(lig_trick)=link(p);
+p=lig_trick;goto reswitch;
+}
+
+@ The code here implicitly uses the fact that running dimensions are
+indicated by |null_flag|, which will be ignored in the calculations
+because it is a highly negative number.
+
+@<Incorporate box dimensions into the dimensions of the hbox...@>=
+{@+x=x+width(p);
+if (type(p) >= rule_node) s=0;@+else s=shift_amount(p);
+if (height(p)-s > h) h=height(p)-s;
+if (depth(p)+s > d) d=depth(p)+s;
+}
+
+@ The following code is part of \TeX's inner loop; i.e., adding another
+character of text to the user's input will cause each of these instructions
+to be exercised one more time.
+@^inner loop@>
+
+@<Incorporate character dimensions into the dimensions of the hbox...@>=
+{@+f=font(p);i=char_info(f, character(p));hd=height_depth(i);
+x=x+char_width(f, i);@/
+s=char_height(f, hd);@+if (s > h) h=s;
+s=char_depth(f, hd);@+if (s > d) d=s;
+p=link(p);
+}
+
+@ Although node |q| is not necessarily the immediate predecessor of node |p|,
+it always points to some node in the list preceding |p|. Thus, we can delete
+nodes by moving |q| when necessary. The algorithm takes linear time, and the
+extra computation does not intrude on the inner loop unless it is necessary
+to make a deletion.
+@^inner loop@>
+
+@<Transfer node |p| to the adjustment list@>=
+{@+while (link(q)!=p) q=link(q);
+if (type(p)==adjust_node)
+  {@+link(adjust_tail)=adjust_ptr(p);
+  while (link(adjust_tail)!=null) adjust_tail=link(adjust_tail);
+  p=link(p);free_node(link(q), small_node_size);
+  }
+else{@+link(adjust_tail)=p;adjust_tail=p;p=link(p);
+  }
+link(q)=p;p=q;
+}
+
+@ @<Incorporate glue into the horizontal totals@>=
+{@+g=glue_ptr(p);x=x+width(g);@/
+o=stretch_order(g);total_stretch[o]=total_stretch[o]+stretch(g);
+o=shrink_order(g);total_shrink[o]=total_shrink[o]+shrink(g);
+if (subtype(p) >= a_leaders)
+  {@+g=leader_ptr(p);
+  if (height(g) > h) h=height(g);
+  if (depth(g) > d) d=depth(g);
+  }
+}
+
+@ When we get to the present part of the program, |x| is the natural width
+of the box being packaged.
+
+@<Determine the value of |width(r)| and the appropriate glue setting...@>=
+if (m==additional) w=x+w;
+width(r)=w;x=w-x; /*now |x| is the excess to be made up*/
+if (x==0)
+  {@+glue_sign(r)=normal;glue_order(r)=normal;
+  set_glue_ratio_zero(glue_set(r));
+  goto end;
+  }
+else if (x > 0) @<Determine horizontal glue stretch setting, then |return| or \hbox{|goto
+common_ending|}@>@;
+else@<Determine horizontal glue shrink setting, then |return| or \hbox{|goto common_ending|}@>@;
+
+@ @<Determine horizontal glue stretch setting...@>=
+{@+@<Determine the stretch order@>;
+glue_order(r)=o;glue_sign(r)=stretching;
+if (total_stretch[o]!=0) glue_set(r)=unfloat(x/(double)total_stretch[o]);
+@^real division@>
+else{@+glue_sign(r)=normal;
+  set_glue_ratio_zero(glue_set(r)); /*there's nothing to stretch*/
+  }
+if (o==normal) if (list_ptr(r)!=null)
+  @<Report an underfull hbox and |goto common_ending|, if this box is sufficiently
+bad@>;
+goto end;
+}
+
+@ @<Determine the stretch order@>=
+if (total_stretch[filll]!=0) o=filll;
+else if (total_stretch[fill]!=0) o=fill;
+else if (total_stretch[fil]!=0) o=fil;
+else o=normal
+
+@ @<Report an underfull hbox and |goto common_ending|, if...@>=
+{@+last_badness=badness(x, total_stretch[normal]);
+if (last_badness > hbadness)
+  {@+print_ln();
+  if (last_badness > 100) print_nl("Underfull");@+else print_nl("Loose");
+  print(" \\hbox (badness ");print_int(last_badness);
+ at .Underfull \\hbox...@>
+ at .Loose \\hbox...@>
+  goto common_ending;
+  }
+}
+
+@ In order to provide a decent indication of where an overfull or underfull
+box originated, we use a global variable |pack_begin_line| that is
+set nonzero only when |hpack| is being called by the paragraph builder
+or the alignment finishing routine.
+
+@<Glob...@>=
+static int @!pack_begin_line; /*source file line where the current paragraph
+  or alignment began; a negative value denotes alignment*/
+
+@ @<Set init...@>=
+pack_begin_line=0;
+
+@ @<Finish issuing a diagnostic message for an overfull or underfull hbox@>=
+if (output_active) print(") has occurred while \\output is active");
+else{@+if (pack_begin_line!=0)
+    {@+if (pack_begin_line > 0) print(") in paragraph at lines ");
+    else print(") in alignment at lines ");
+    print_int(abs(pack_begin_line));
+    print("--");
+    }
+  else print(") detected at line ");
+  print_int(line);
+  }
+print_ln();@/
+font_in_short_display=null_font;short_display(list_ptr(r));print_ln();@/
+begin_diagnostic();show_box(r);end_diagnostic(true)
+
+@ @<Determine horizontal glue shrink setting...@>=
+{@+@<Determine the shrink order@>;
+glue_order(r)=o;glue_sign(r)=shrinking;
+if (total_shrink[o]!=0) glue_set(r)=unfloat((-x)/(double)total_shrink[o]);
+@^real division@>
+else{@+glue_sign(r)=normal;
+  set_glue_ratio_zero(glue_set(r)); /*there's nothing to shrink*/
+  }
+if ((total_shrink[o] < -x)&&(o==normal)&&(list_ptr(r)!=null))
+  {@+last_badness=1000000;
+  set_glue_ratio_one(glue_set(r)); /*use the maximum shrinkage*/
+  @<Report an overfull hbox and |goto common_ending|, if this box is sufficiently
+bad@>;
+  }
+else if (o==normal) if (list_ptr(r)!=null)
+  @<Report a tight hbox and |goto common_ending|, if this box is sufficiently bad@>;
+goto end;
+}
+
+@ @<Determine the shrink order@>=
+if (total_shrink[filll]!=0) o=filll;
+else if (total_shrink[fill]!=0) o=fill;
+else if (total_shrink[fil]!=0) o=fil;
+else o=normal
+
+@ @<Report an overfull hbox and |goto common_ending|, if...@>=
+if ((-x-total_shrink[normal] > hfuzz)||(hbadness < 100))
+  {@+if ((overfull_rule > 0)&&(-x-total_shrink[normal] > hfuzz))
+    {@+while (link(q)!=null) q=link(q);
+    link(q)=new_rule();
+    width(link(q))=overfull_rule;
+    }
+  print_ln();print_nl("Overfull \\hbox (");
+ at .Overfull \\hbox...@>
+  print_scaled(-x-total_shrink[normal]);print("pt too wide");
+  goto common_ending;
+  }
+
+@ @<Report a tight hbox and |goto common_ending|, if...@>=
+{@+last_badness=badness(-x, total_shrink[normal]);
+if (last_badness > hbadness)
+  {@+print_ln();print_nl("Tight \\hbox (badness ");print_int(last_badness);
+ at .Tight \\hbox...@>
+  goto common_ending;
+  }
+}
+
+@ The |vpack| subroutine is actually a special case of a slightly more
+general routine called |vpackage|, which has four parameters. The fourth
+parameter, which is |max_dimen| in the case of |vpack|, specifies the
+maximum depth of the page box that is constructed. The depth is first
+computed by the normal rules; if it exceeds this limit, the reference
+point is simply moved down until the limiting depth is attained.
+
+
+ at p
+#define vpack(...) @[vpackage(__VA_ARGS__, max_dimen)@] /*special case of unconstrained depth*/
+static pointer vpackage(pointer p, scaled h, scaled hf, scaled vf, small_number m, scaled l);
+
+@ @<Examine node |p| in the vlist, taking account of its effect...@>=
+{@+if (is_char_node(p)) confusion("vpack");
+@:this can't happen vpack}{\quad vpack@>
+else switch (type(p)) {
+  case hlist_node: case vlist_node: case rule_node: case unset_node: case unset_set_node: case unset_pack_node:
+    @<Incorporate box dimensions into the dimensions of the vbox that will contain~it@>@;@+break;
+  case whatsit_node: @<Incorporate a whatsit node into a vbox@>;@+break;
+  case glue_node: @<Incorporate glue into the vertical totals@>@;@+break;
+  case kern_node: {@+x=x+d+width(p);d=0;
+    } @+break;
+  default:do_nothing;
+  }
+p=link(p);
+}
+
+@ @<Incorporate box dimensions into the dimensions of the vbox...@>=
+{@+x=x+d+height(p);d=depth(p);
+if (type(p) >= rule_node) s=0;@+else s=shift_amount(p);
+if (width(p)+s > w) w=width(p)+s;
+}
+
+@ @<Incorporate glue into the vertical totals@>=
+{@+x=x+d;d=0;@/
+g=glue_ptr(p);x=x+width(g);@/
+o=stretch_order(g);total_stretch[o]=total_stretch[o]+stretch(g);
+o=shrink_order(g);total_shrink[o]=total_shrink[o]+shrink(g);
+if (subtype(p) >= a_leaders)
+  {@+g=leader_ptr(p);
+  if (width(g) > w) w=width(g);
+  }
+}
+
+@ When we get to the present part of the program, |x| is the natural height
+of the box being packaged.
+
+@<Determine the value of |height(r)| and the appropriate glue setting...@>=
+if (m==additional) h=x+h;
+height(r)=h;x=h-x; /*now |x| is the excess to be made up*/
+if (x==0)
+  {@+glue_sign(r)=normal;glue_order(r)=normal;
+  set_glue_ratio_zero(glue_set(r));
+  goto end;
+  }
+else if (x > 0) @<Determine vertical glue stretch setting, then |return| or \hbox{|goto
+common_ending|}@>@;
+else@<Determine vertical glue shrink setting, then |return| or \hbox{|goto common_ending|}@>@;
+
+@ @<Determine vertical glue stretch setting...@>=
+{@+@<Determine the stretch order@>;
+glue_order(r)=o;glue_sign(r)=stretching;
+if (total_stretch[o]!=0) glue_set(r)=unfloat(x/(double)total_stretch[o]);
+@^real division@>
+else{@+glue_sign(r)=normal;
+  set_glue_ratio_zero(glue_set(r)); /*there's nothing to stretch*/
+  }
+if (o==normal) if (list_ptr(r)!=null)
+  @<Report an underfull vbox and |goto common_ending|, if this box is sufficiently
+bad@>;
+goto end;
+}
+
+@ @<Report an underfull vbox and |goto common_ending|, if...@>=
+{@+last_badness=badness(x, total_stretch[normal]);
+if (last_badness > vbadness)
+  {@+print_ln();
+  if (last_badness > 100) print_nl("Underfull");@+else print_nl("Loose");
+  print(" \\vbox (badness ");print_int(last_badness);
+ at .Underfull \\vbox...@>
+ at .Loose \\vbox...@>
+  goto common_ending;
+  }
+}
+
+@ @<Finish issuing a diagnostic message for an overfull or underfull vbox@>=
+if (output_active) print(") has occurred while \\output is active");
+else{@+if (pack_begin_line!=0)  /*it's actually negative*/
+    {@+print(") in alignment at lines ");
+    print_int(abs(pack_begin_line));
+    print("--");
+    }
+  else print(") detected at line ");
+  print_int(line);
+  print_ln();@/
+  }
+begin_diagnostic();show_box(r);end_diagnostic(true)
+
+@ @<Determine vertical glue shrink setting...@>=
+{@+@<Determine the shrink order@>;
+glue_order(r)=o;glue_sign(r)=shrinking;
+if (total_shrink[o]!=0) glue_set(r)=unfloat((-x)/(double)total_shrink[o]);
+@^real division@>
+else{@+glue_sign(r)=normal;
+  set_glue_ratio_zero(glue_set(r)); /*there's nothing to shrink*/
+  }
+if ((total_shrink[o] < -x)&&(o==normal)&&(list_ptr(r)!=null))
+  {@+last_badness=1000000;
+  set_glue_ratio_one(glue_set(r)); /*use the maximum shrinkage*/
+  @<Report an overfull vbox and |goto common_ending|, if this box is sufficiently
+bad@>;
+  }
+else if (o==normal) if (list_ptr(r)!=null)
+  @<Report a tight vbox and |goto common_ending|, if this box is sufficiently bad@>;
+goto end;
+}
+
+@ @<Report an overfull vbox and |goto common_ending|, if...@>=
+if ((-x-total_shrink[normal] > vfuzz)||(vbadness < 100))
+  {@+print_ln();print_nl("Overfull \\vbox (");
+ at .Overfull \\vbox...@>
+  print_scaled(-x-total_shrink[normal]);print("pt too high");
+  goto common_ending;
+  }
+
+@ @<Report a tight vbox and |goto common_ending|, if...@>=
+{@+last_badness=badness(-x, total_shrink[normal]);
+if (last_badness > vbadness)
+  {@+print_ln();print_nl("Tight \\vbox (badness ");print_int(last_badness);
+ at .Tight \\vbox...@>
+  goto common_ending;
+  }
+}
+
+@ When a box is being appended to the current vertical list, the
+baselineskip calculation is handled by the |append_to_vlist| routine.
+
+ at p static void append_to_vlist(pointer @!b)@t\2\2@>@/
+{ bool height_known;@t\1@>@/
+  height_known=(type(b)==hlist_node || type(b)==vlist_node ||@|
+	   (type(b)==whatsit_node && subtype(b)==hset_node) ||@|
+	   (type(b)==whatsit_node && subtype(b)==image_node));@/
+  if (prev_depth > ignore_depth && height_known)@/
+  {@+scaled d;@t\1@> /*deficiency of space between baselines*/
+    pointer @!p; /*a new glue node*/
+  {@+d=width(baseline_skip)-prev_depth-height(b);
+  if (d < line_skip_limit) p=new_param_glue(line_skip_code);
+  else{@+p=new_skip_param(baseline_skip_code);
+    width(temp_ptr)=d; /*|temp_ptr==glue_ptr(p)|*/
+    }
+  link(tail)=p;tail=p;
+  }@+
+} @+  else @+if (prev_depth<=unknown_depth || prev_depth>ignore_depth )@t\2@>@/
+  {@+pointer p;
+	p=new_baseline_node(baseline_skip, line_skip, line_skip_limit);
+    link(tail)= p;tail= p;
+  }
+  link(tail)=b;tail=b;
+  if (height_known)
+	prev_depth=depth(b);  /* then also depth is known */
+  else
+	prev_depth=unknown_depth;
+}
+
+@* Data structures for math mode.
+When \TeX\ reads a formula that is enclosed between \.\$'s, it constructs an
+{\sl mlist}, which is essentially a tree structure representing that
+formula.  An mlist is a linear sequence of items, but we can regard it as
+a tree structure because mlists can appear within mlists. For example, many
+of the entries can be subscripted or superscripted, and such ``scripts''
+are mlists in their own right.
+
+An entire formula is parsed into such a tree before any of the actual
+typesetting is done, because the current style of type is usually not
+known until the formula has been fully scanned. For example, when the
+formula `\.{\$a+b \\over c+d\$}' is being read, there is no way to tell
+that `\.{a+b}' will be in script size until `\.{\\over}' has appeared.
+
+During the scanning process, each element of the mlist being built is
+classified as a relation, a binary operator, an open parenthesis, etc.,
+or as a construct like `\.{\\sqrt}' that must be built up. This classification
+appears in the mlist data structure.
+
+After a formula has been fully scanned, the mlist is converted to an hlist
+so that it can be incorporated into the surrounding text. This conversion is
+controlled by a recursive procedure that decides all of the appropriate
+styles by a ``top-down'' process starting at the outermost level and working
+in towards the subformulas. The formula is ultimately pasted together using
+combinations of horizontal and vertical boxes, with glue and penalty nodes
+inserted as necessary.
+
+An mlist is represented internally as a linked list consisting chiefly
+of ``noads'' (pronounced ``no-adds''), to distinguish them from the somewhat
+similar ``nodes'' in hlists and vlists. Certain kinds of ordinary nodes are
+allowed to appear in mlists together with the noads; \TeX\ tells the difference
+by means of the |type| field, since a noad's |type| is always greater than
+that of a node. An mlist does not contain character nodes, hlist nodes, vlist
+nodes, math nodes, ligature nodes,
+or unset nodes; in particular, each mlist item appears in the
+variable-size part of |mem|, so the |type| field is always present.
+
+@ Each noad is four or more words long. The first word contains the |type|
+and |subtype| and |link| fields that are already so familiar to us; the
+second, third, and fourth words are called the noad's |nucleus|, |subscr|,
+and |supscr| fields.
+
+Consider, for example, the simple formula `\.{\$x\^2\$}', which would be
+parsed into an mlist containing a single element called an |ord_noad|.
+The |nucleus| of this noad is a representation of `\.x', the |subscr| is
+empty, and the |supscr| is a representation of `\.2'.
+
+The |nucleus|, |subscr|, and |supscr| fields are further broken into
+subfields. If |p| points to a noad, and if |q| is one of its principal
+fields (e.g., |q==subscr(p)|), there are several possibilities for the
+subfields, depending on the |math_type| of |q|.
+
+\yskip\hang|math_type(q)==math_char| means that |fam(q)| refers to one of
+the sixteen font families, and |character(q)| is the number of a character
+within a font of that family, as in a character node.
+
+\yskip\hang|math_type(q)==math_text_char| is similar, but the character is
+unsubscripted and unsuperscripted and it is followed immediately by another
+character from the same font. (This |math_type| setting appears only
+briefly during the processing; it is used to suppress unwanted italic
+corrections.)
+
+\yskip\hang|math_type(q)==empty| indicates a field with no value (the
+corresponding attribute of noad |p| is not present).
+
+\yskip\hang|math_type(q)==sub_box| means that |info(q)| points to a box
+node (either an |hlist_node| or a |vlist_node|) that should be used as the
+value of the field.  The |shift_amount| in the subsidiary box node is the
+amount by which that box will be shifted downward.
+
+\yskip\hang|math_type(q)==sub_mlist| means that |info(q)| points to
+an mlist; the mlist must be converted to an hlist in order to obtain
+the value of this field.
+
+\yskip\noindent In the latter case, we might have |info(q)==null|. This
+is not the same as |math_type(q)==empty|; for example, `\.{\$P\_\{\}\$}'
+and `\.{\$P\$}' produce different results (the former will not have the
+``italic correction'' added to the width of |P|, but the ``script skip''
+will be added).
+
+The definitions of subfields given here are evidently wasteful of space,
+since a halfword is being used for the |math_type| although only three
+bits would be needed. However, there are hardly ever many noads present at
+once, since they are soon converted to nodes that take up even more space,
+so we can afford to represent them in whatever way simplifies the
+programming.
+
+ at d noad_size 4 /*number of words in a normal noad*/
+ at d nucleus(A) A+1 /*the |nucleus| field of a noad*/
+ at d supscr(A) A+2 /*the |supscr| field of a noad*/
+ at d subscr(A) A+3 /*the |subscr| field of a noad*/
+ at d math_type(A) link(A) /*a |halfword| in |mem|*/
+ at d fam font /*a |quarterword| in |mem|*/
+ at d math_char 1 /*|math_type| when the attribute is simple*/
+ at d sub_box 2 /*|math_type| when the attribute is a box*/
+ at d sub_mlist 3 /*|math_type| when the attribute is a formula*/
+ at d math_text_char 4 /*|math_type| when italic correction is dubious*/
+
+@ Each portion of a formula is classified as Ord, Op, Bin, Rel, Open,
+Close, Punct, or Inner, for purposes of spacing and line breaking. An
+|ord_noad|, |op_noad|, |bin_noad|, |rel_noad|, |open_noad|, |close_noad|,
+|punct_noad|, or |inner_noad| is used to represent portions of the various
+types. For example, an `\.=' sign in a formula leads to the creation of a
+|rel_noad| whose |nucleus| field is a representation of an equals sign
+(usually |fam==0|, |character==075|).  A formula preceded by \.{\\mathrel}
+also results in a |rel_noad|.  When a |rel_noad| is followed by an
+|op_noad|, say, and possibly separated by one or more ordinary nodes (not
+noads), \TeX\ will insert a penalty node (with the current |rel_penalty|)
+just after the formula that corresponds to the |rel_noad|, unless there
+already was a penalty immediately following; and a ``thick space'' will be
+inserted just before the formula that corresponds to the |op_noad|.
+
+A noad of type |ord_noad|, |op_noad|, \dots, |inner_noad| usually
+has a |subtype==normal|. The only exception is that an |op_noad| might
+have |subtype==limits| or |no_limits|, if the normal positioning of
+limits has been overridden for this operator.
+
+ at d ord_noad (unset_node+3) /*|type| of a noad classified Ord*/
+ at d op_noad (ord_noad+1) /*|type| of a noad classified Op*/
+ at d bin_noad (ord_noad+2) /*|type| of a noad classified Bin*/
+ at d rel_noad (ord_noad+3) /*|type| of a noad classified Rel*/
+ at d open_noad (ord_noad+4) /*|type| of a noad classified Open*/
+ at d close_noad (ord_noad+5) /*|type| of a noad classified Close*/
+ at d punct_noad (ord_noad+6) /*|type| of a noad classified Punct*/
+ at d inner_noad (ord_noad+7) /*|type| of a noad classified Inner*/
+ at d limits 1 /*|subtype| of |op_noad| whose scripts are to be above, below*/
+ at d no_limits 2 /*|subtype| of |op_noad| whose scripts are to be normal*/
+
+@ A |radical_noad| is five words long; the fifth word is the |left_delimiter|
+field, which usually represents a square root sign.
+
+A |fraction_noad| is six words long; it has a |right_delimiter| field
+as well as a |left_delimiter|.
+
+Delimiter fields are of type |four_quarters|, and they have four subfields
+called |small_fam|, |small_char|, |large_fam|, |large_char|. These subfields
+represent variable-size delimiters by giving the ``small'' and ``large''
+starting characters, as explained in Chapter~17 of {\sl The \TeX book}.
+@:TeXbook}{\sl The \TeX book@>
+
+A |fraction_noad| is actually quite different from all other noads. Not
+only does it have six words, it has |thickness|, |denominator|, and
+|numerator| fields instead of |nucleus|, |subscr|, and |supscr|. The
+|thickness| is a scaled value that tells how thick to make a fraction
+rule; however, the special value |default_code| is used to stand for the
+|default_rule_thickness| of the current size. The |numerator| and
+|denominator| point to mlists that define a fraction; we always have
+$$\hbox{|math_type(numerator)==math_type(denominator)==sub_mlist|}.$$ The
+|left_delimiter| and |right_delimiter| fields specify delimiters that will
+be placed at the left and right of the fraction. In this way, a
+|fraction_noad| is able to represent all of \TeX's operators \.{\\over},
+\.{\\atop}, \.{\\above}, \.{\\overwithdelims}, \.{\\atopwithdelims}, and
+ \.{\\abovewithdelims}.
+
+ at d left_delimiter(A) A+4 /*first delimiter field of a noad*/
+ at d right_delimiter(A) A+5 /*second delimiter field of a fraction noad*/
+ at d radical_noad (inner_noad+1) /*|type| of a noad for square roots*/
+ at d radical_noad_size 5 /*number of |mem| words in a radical noad*/
+ at d fraction_noad (radical_noad+1) /*|type| of a noad for generalized fractions*/
+ at d fraction_noad_size 6 /*number of |mem| words in a fraction noad*/
+ at d small_fam(A) mem[A].qqqq.b0 /*|fam| for ``small'' delimiter*/
+ at d small_char(A) mem[A].qqqq.b1 /*|character| for ``small'' delimiter*/
+ at d large_fam(A) mem[A].qqqq.b2 /*|fam| for ``large'' delimiter*/
+ at d large_char(A) mem[A].qqqq.b3 /*|character| for ``large'' delimiter*/
+ at d thickness(A) width(A) /*|thickness| field in a fraction noad*/
+ at d default_code 010000000000 /*denotes |default_rule_thickness|*/
+ at d numerator(A) supscr(A) /*|numerator| field in a fraction noad*/
+ at d denominator(A) subscr(A) /*|denominator| field in a fraction noad*/
+
+@ The global variable |empty_field| is set up for initialization of empty
+fields in new noads. Similarly, |null_delimiter| is for the initialization
+of delimiter fields.
+
+@<Glob...@>=
+static two_halves @!empty_field;
+static four_quarters @!null_delimiter;
+
+@ @<Set init...@>=
+empty_field.rh=empty;empty_field.lh=null;@/
+null_delimiter.b0=0;null_delimiter.b1=min_quarterword;@/
+null_delimiter.b2=0;null_delimiter.b3=min_quarterword;
+
+@ The |new_noad| function creates an |ord_noad| that is completely null.
+
+ at p static pointer new_noad(void)
+{@+pointer p;
+p=get_node(noad_size);
+type(p)=ord_noad;subtype(p)=normal;
+mem[nucleus(p)].hh=empty_field;
+mem[subscr(p)].hh=empty_field;
+mem[supscr(p)].hh=empty_field;
+return p;
+}
+
+@ A few more kinds of noads will complete the set: An |under_noad| has its
+nucleus underlined; an |over_noad| has it overlined. An |accent_noad| places
+an accent over its nucleus; the accent character appears as
+|fam(accent_chr(p))| and |character(accent_chr(p))|. A |vcenter_noad|
+centers its nucleus vertically with respect to the axis of the formula;
+in such noads we always have |math_type(nucleus(p))==sub_box|.
+
+And finally, we have |left_noad| and |right_noad| types, to implement
+\TeX's \.{\\left} and \.{\\right} as well as \eTeX's \.{\\middle}.
+The |nucleus| of such noads is
+replaced by a |delimiter| field; thus, for example, `\.{\\left(}' produces
+a |left_noad| such that |delimiter(p)| holds the family and character
+codes for all left parentheses. A |left_noad| never appears in an mlist
+except as the first element, and a |right_noad| never appears in an mlist
+except as the last element; furthermore, we either have both a |left_noad|
+and a |right_noad|, or neither one is present. The |subscr| and |supscr|
+fields are always |empty| in a |left_noad| and a |right_noad|.
+
+ at d under_noad (fraction_noad+1) /*|type| of a noad for underlining*/
+ at d over_noad (under_noad+1) /*|type| of a noad for overlining*/
+ at d accent_noad (over_noad+1) /*|type| of a noad for accented subformulas*/
+ at d accent_noad_size 5 /*number of |mem| words in an accent noad*/
+ at d accent_chr(A) A+4 /*the |accent_chr| field of an accent noad*/
+ at d vcenter_noad (accent_noad+1) /*|type| of a noad for \.{\\vcenter}*/
+ at d left_noad (vcenter_noad+1) /*|type| of a noad for \.{\\left}*/
+ at d right_noad (left_noad+1) /*|type| of a noad for \.{\\right}*/
+ at d delimiter(A) nucleus(A) /*|delimiter| field in left and right noads*/
+ at d middle_noad 1 /*|subtype| of right noad representing \.{\\middle}*/
+ at d scripts_allowed(A) (type(A) >= ord_noad)&&(type(A) < left_noad)
+
+@ Math formulas can also contain instructions like \.{\\textstyle} that
+override \TeX's normal style rules. A |style_node| is inserted into the
+data structure to record such instructions; it is three words long, so it
+is considered a node instead of a noad. The |subtype| is either |display_style|
+or |text_style| or |script_style| or |script_script_style|. The
+second and third words of a |style_node| are not used, but they are
+present because a |choice_node| is converted to a |style_node|.
+
+\TeX\ uses even numbers 0, 2, 4, 6 to encode the basic styles
+|display_style|, \dots, |script_script_style|, and adds~1 to get the
+``cramped'' versions of these styles. This gives a numerical order that
+is backwards from the convention of Appendix~G in {\sl The \TeX book\/};
+i.e., a smaller style has a larger numerical value.
+@:TeXbook}{\sl The \TeX book@>
+
+ at d style_node (unset_node+1) /*|type| of a style node*/
+ at d style_node_size 3 /*number of words in a style node*/
+ at d display_style 0 /*|subtype| for \.{\\displaystyle}*/
+ at d text_style 2 /*|subtype| for \.{\\textstyle}*/
+ at d script_style 4 /*|subtype| for \.{\\scriptstyle}*/
+ at d script_script_style 6 /*|subtype| for \.{\\scriptscriptstyle}*/
+ at d cramped 1 /*add this to an uncramped style if you want to cramp it*/
+
+ at p static pointer new_style(small_number @!s) /*create a style node*/
+{@+pointer p; /*the new node*/
+p=get_node(style_node_size);type(p)=style_node;
+subtype(p)=s;width(p)=0;depth(p)=0; /*the |width| and |depth| are not used*/
+return p;
+}
+
+@ Finally, the \.{\\mathchoice} primitive creates a |choice_node|, which
+has special subfields |display_mlist|, |text_mlist|, |script_mlist|,
+and |script_script_mlist| pointing to the mlists for each style.
+
+ at d choice_node (unset_node+2) /*|type| of a choice node*/
+ at d display_mlist(A) info(A+1) /*mlist to be used in display style*/
+ at d text_mlist(A) link(A+1) /*mlist to be used in text style*/
+ at d script_mlist(A) info(A+2) /*mlist to be used in script style*/
+ at d script_script_mlist(A) link(A+2) /*mlist to be used in scriptscript style*/
+
+ at p static pointer new_choice(void) /*create a choice node*/
+{@+pointer p; /*the new node*/
+p=get_node(style_node_size);type(p)=choice_node;
+subtype(p)=0; /*the |subtype| is not used*/
+display_mlist(p)=null;text_mlist(p)=null;script_mlist(p)=null;
+script_script_mlist(p)=null;
+return p;
+}
+
+@ Let's consider now the previously unwritten part of |show_node_list|
+that displays the things that can only be present in mlists; this
+program illustrates how to access the data structures just defined.
+
+In the context of the following program, |p| points to a node or noad that
+should be displayed, and the current string contains the ``recursion history''
+that leads to this point. The recursion history consists of a dot for each
+outer level in which |p| is subsidiary to some node, or in which |p| is
+subsidiary to the |nucleus| field of some noad; the dot is replaced by
+`\.\_' or `\.\^' or `\./' or `\.\\' if |p| is descended from the |subscr|
+or |supscr| or |denominator| or |numerator| fields of noads. For example,
+the current string would be `\.{.\^.\_/}' if |p| points to the |ord_noad| for
+|x| in the (ridiculous) formula
+`\.{\$\\sqrt\{a\^\{\\mathinner\{b\_\{c\\over x+y\}\}\}\}\$}'.
+
+@<Cases of |show_node_list| that arise...@>=
+case style_node: print_style(subtype(p));@+break;
+case choice_node: @<Display choice node |p|@>@;@+break;
+case ord_noad: case op_noad: case bin_noad: case rel_noad: case open_noad: case close_noad: case punct_noad: case inner_noad:
+  case radical_noad: case over_noad: case under_noad: case vcenter_noad: case accent_noad:
+  case left_noad: case right_noad: @<Display normal noad |p|@>@;@+break;
+case fraction_noad: @<Display fraction noad |p|@>@;@+break;
+
+@ Here are some simple routines used in the display of noads.
+
+@<Declare procedures needed for displaying the elements of mlists@>=
+static void print_fam_and_char(pointer @!p) /*prints family and character*/
+{@+print_esc("fam");print_int(fam(p));print_char(' ');
+print_ASCII(qo(character(p)));
+}
+@#
+static void print_delimiter(pointer @!p) /*prints a delimiter as 24-bit hex value*/
+{@+int a; /*accumulator*/
+a=small_fam(p)*256+qo(small_char(p));
+a=a*0x1000+large_fam(p)*256+qo(large_char(p));
+if (a < 0) print_int(a); /*this should never happen*/
+else print_hex(a);
+}
+
+@ The next subroutine will descend to another level of recursion when a
+subsidiary mlist needs to be displayed. The parameter |c| indicates what
+character is to become part of the recursion history. An empty mlist is
+distinguished from a field with |math_type(p)==empty|, because these are
+not equivalent (as explained above).
+@^recursion@>
+
+@<Declare procedures needed for displaying...@>=
+static void show_info(void); /*|show_node_list(info(temp_ptr))|*/
+static void print_subsidiary_data(pointer @!p, ASCII_code @!c)
+   /*display a noad field*/
+{@+if (cur_length >= depth_threshold)
+  {@+if (math_type(p)!=empty) print(" []");
+  }
+else{@+append_char(c); /*include |c| in the recursion history*/
+  temp_ptr=p; /*prepare for |show_info| if recursion is needed*/
+  switch (math_type(p)) {
+  case math_char: {@+print_ln();print_current_string();print_fam_and_char(p);
+    } @+break;
+  case sub_box: show_info();@+break; /*recursive call*/
+  case sub_mlist: if (info(p)==null)
+      {@+print_ln();print_current_string();print("{}");
+      }
+    else show_info();@+break; /*recursive call*/
+  default:do_nothing; /*|empty|*/
+  } @/
+  flush_char; /*remove |c| from the recursion history*/
+  }
+}
+
+@ The inelegant introduction of |show_info| in the code above seems better
+than the alternative of using \PASCAL's strange |forward| declaration for a
+procedure with parameters. The \PASCAL\ convention about dropping parameters
+from a post-|forward| procedure is, frankly, so intolerable to the author
+of \TeX\ that he would rather stoop to communication via a global temporary
+variable. (A similar stoopidity occurred with respect to |hlist_out| and
+|vlist_out| above, and it will occur with respect to |mlist_to_hlist| below.)
+@^Knuth, Donald Ervin@>
+@:PASCAL}{\PASCAL@>
+
+ at p static void show_info(void) /*the reader will kindly forgive this*/
+{@+show_node_list(info(temp_ptr));
+}
+
+@ @<Declare procedures needed for displaying...@>=
+static void print_style(int @!c)
+{@+switch (c/2) {
+case 0: print_esc("displaystyle");@+break; /*|display_style==0|*/
+case 1: print_esc("textstyle");@+break; /*|text_style==2|*/
+case 2: print_esc("scriptstyle");@+break; /*|script_style==4|*/
+case 3: print_esc("scriptscriptstyle");@+break; /*|script_script_style==6|*/
+default:print("Unknown style!");
+}
+}
+
+@ @<Display choice node |p|@>=
+{@+print_esc("mathchoice");
+append_char('D');show_node_list(display_mlist(p));flush_char;
+append_char('T');show_node_list(text_mlist(p));flush_char;
+append_char('S');show_node_list(script_mlist(p));flush_char;
+append_char('s');show_node_list(script_script_mlist(p));flush_char;
+}
+
+@ @<Display normal noad |p|@>=
+{@+switch (type(p)) {
+case ord_noad: print_esc("mathord");@+break;
+case op_noad: print_esc("mathop");@+break;
+case bin_noad: print_esc("mathbin");@+break;
+case rel_noad: print_esc("mathrel");@+break;
+case open_noad: print_esc("mathopen");@+break;
+case close_noad: print_esc("mathclose");@+break;
+case punct_noad: print_esc("mathpunct");@+break;
+case inner_noad: print_esc("mathinner");@+break;
+case over_noad: print_esc("overline");@+break;
+case under_noad: print_esc("underline");@+break;
+case vcenter_noad: print_esc("vcenter");@+break;
+case radical_noad: {@+print_esc("radical");print_delimiter(left_delimiter(p));
+  } @+break;
+case accent_noad: {@+print_esc("accent");print_fam_and_char(accent_chr(p));
+  } @+break;
+case left_noad: {@+print_esc("left");print_delimiter(delimiter(p));
+  } @+break;
+case right_noad: {@+if (subtype(p)==normal) print_esc("right");
+  else print_esc("middle");
+  print_delimiter(delimiter(p));
+  }
+}
+if (type(p) < left_noad)
+  {@+if (subtype(p)!=normal)
+    if (subtype(p)==limits) print_esc("limits");
+    else print_esc("nolimits");
+  print_subsidiary_data(nucleus(p),'.');
+  }
+print_subsidiary_data(supscr(p),'^');
+print_subsidiary_data(subscr(p),'_');
+}
+
+@ @<Display fraction noad |p|@>=
+{@+print_esc("fraction, thickness ");
+if (thickness(p)==default_code) print("= default");
+else print_scaled(thickness(p));
+if ((small_fam(left_delimiter(p))!=0)||@+
+  (small_char(left_delimiter(p))!=min_quarterword)||@|
+  (large_fam(left_delimiter(p))!=0)||@|
+  (large_char(left_delimiter(p))!=min_quarterword))
+  {@+print(", left-delimiter ");print_delimiter(left_delimiter(p));
+  }
+if ((small_fam(right_delimiter(p))!=0)||@|
+  (small_char(right_delimiter(p))!=min_quarterword)||@|
+  (large_fam(right_delimiter(p))!=0)||@|
+  (large_char(right_delimiter(p))!=min_quarterword))
+  {@+print(", right-delimiter ");print_delimiter(right_delimiter(p));
+  }
+print_subsidiary_data(numerator(p),'\\');
+print_subsidiary_data(denominator(p),'/');
+}
+
+@ That which can be displayed can also be destroyed.
+
+@<Cases of |flush_node_list| that arise...@>=
+case style_node: {@+free_node(p, style_node_size);goto done;
+  }
+case choice_node: {@+flush_node_list(display_mlist(p));
+  flush_node_list(text_mlist(p));
+  flush_node_list(script_mlist(p));
+  flush_node_list(script_script_mlist(p));
+  free_node(p, style_node_size);goto done;
+  }
+case ord_noad: case op_noad: case bin_noad: case rel_noad: case open_noad: case close_noad: case punct_noad: case inner_noad:
+  case radical_noad: case over_noad: case under_noad: case vcenter_noad: case accent_noad: @t@>@;@/
+  {@+if (math_type(nucleus(p)) >= sub_box)
+    flush_node_list(info(nucleus(p)));
+  if (math_type(supscr(p)) >= sub_box)
+    flush_node_list(info(supscr(p)));
+  if (math_type(subscr(p)) >= sub_box)
+    flush_node_list(info(subscr(p)));
+  if (type(p)==radical_noad) free_node(p, radical_noad_size);
+  else if (type(p)==accent_noad) free_node(p, accent_noad_size);
+  else free_node(p, noad_size);
+  goto done;
+  }
+case left_noad: case right_noad: {@+free_node(p, noad_size);goto done;
+  }
+case fraction_noad: {@+flush_node_list(info(numerator(p)));
+  flush_node_list(info(denominator(p)));
+  free_node(p, fraction_noad_size);goto done;
+  }
+
+@* Subroutines for math mode.
+In order to convert mlists to hlists, i.e., noads to nodes, we need several
+subroutines that are conveniently dealt with now.
+
+Let us first introduce the macros that make it easy to get at the parameters and
+other font information. A size code, which is a multiple of 16, is added to a
+family number to get an index into the table of internal font numbers
+for each combination of family and size.  (Be alert: Size codes get
+larger as the type gets smaller.)
+
+ at d text_size 0 /*size code for the largest size in a family*/
+ at d script_size 16 /*size code for the medium size in a family*/
+ at d script_script_size 32 /*size code for the smallest size in a family*/
+
+@<Basic printing procedures@>=
+static void print_size(int @!s)
+{@+if (s==text_size) print_esc("textfont");
+else if (s==script_size) print_esc("scriptfont");
+else print_esc("scriptscriptfont");
+}
+
+@ Before an mlist is converted to an hlist, \TeX\ makes sure that
+the fonts in family~2 have enough parameters to be math-symbol
+fonts, and that the fonts in family~3 have enough parameters to be
+math-extension fonts. The math-symbol parameters are referred to by using the
+following macros, which take a size code as their parameter; for example,
+|num1(cur_size)| gives the value of the |num1| parameter for the current size.
+@^parameters for symbols@>
+@^font parameters@>
+
+ at d mathsy_end(A) fam_fnt(2+A)]].sc
+ at d mathsy(A) font_info[A+param_base[mathsy_end
+ at d math_x_height mathsy(5) /*height of `\.x'*/
+ at d math_quad mathsy(6) /*\.{18mu}*/
+ at d num1 mathsy(8) /*numerator shift-up in display styles*/
+ at d num2 mathsy(9) /*numerator shift-up in non-display, non-\.{\\atop}*/
+ at d num3 mathsy(10) /*numerator shift-up in non-display \.{\\atop}*/
+ at d denom1 mathsy(11) /*denominator shift-down in display styles*/
+ at d denom2 mathsy(12) /*denominator shift-down in non-display styles*/
+ at d sup1 mathsy(13) /*superscript shift-up in uncramped display style*/
+ at d sup2 mathsy(14) /*superscript shift-up in uncramped non-display*/
+ at d sup3 mathsy(15) /*superscript shift-up in cramped styles*/
+ at d sub1 mathsy(16) /*subscript shift-down if superscript is absent*/
+ at d sub2 mathsy(17) /*subscript shift-down if superscript is present*/
+ at d sup_drop mathsy(18) /*superscript baseline below top of large box*/
+ at d sub_drop mathsy(19) /*subscript baseline below bottom of large box*/
+ at d delim1 mathsy(20) /*size of \.{\\atopwithdelims} delimiters
+  in display styles*/
+ at d delim2 mathsy(21) /*size of \.{\\atopwithdelims} delimiters in non-displays*/
+ at d axis_height mathsy(22) /*height of fraction lines above the baseline*/
+ at d total_mathsy_params 22
+
+@ The math-extension parameters have similar macros, but the size code is
+omitted (since it is always |cur_size| when we refer to such parameters).
+@^parameters for symbols@>
+@^font parameters@>
+
+ at d mathex(A) font_info[A+param_base[fam_fnt(3+cur_size)]].sc
+ at d default_rule_thickness mathex(8) /*thickness of \.{\\over} bars*/
+ at d big_op_spacing1 mathex(9) /*minimum clearance above a displayed op*/
+ at d big_op_spacing2 mathex(10) /*minimum clearance below a displayed op*/
+ at d big_op_spacing3 mathex(11) /*minimum baselineskip above displayed op*/
+ at d big_op_spacing4 mathex(12) /*minimum baselineskip below displayed op*/
+ at d big_op_spacing5 mathex(13) /*padding above and below displayed limits*/
+ at d total_mathex_params 13
+
+@ We also need to compute the change in style between mlists and their
+subsidiaries. The following macros define the subsidiary style for
+an overlined nucleus (|cramped_style|), for a subscript or a superscript
+(|sub_style| or |sup_style|), or for a numerator or denominator (|num_style|
+or |denom_style|).
+
+ at d cramped_style(A) 2*(A/2)+cramped /*cramp the style*/
+ at d sub_style(A) 2*(A/4)+script_style+cramped /*smaller and cramped*/
+ at d sup_style(A) 2*(A/4)+script_style+(A%2) /*smaller*/
+ at d num_style(A) A+2-2*(A/6) /*smaller unless already script-script*/
+ at d denom_style(A) 2*(A/2)+cramped+2-2*(A/6) /*smaller, cramped*/
+
+@ When the style changes, the following piece of program computes associated
+information:
+
+@<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>=
+{@+if (cur_style < script_style) cur_size=text_size;
+else cur_size=16*((cur_style-text_style)/2);
+cur_mu=x_over_n(math_quad(cur_size), 18);
+}
+
+@ Here is a function that returns a pointer to a rule node having a given
+thickness |t|. The rule will extend horizontally to the boundary of the vlist
+that eventually contains it.
+
+ at p static pointer fraction_rule(scaled @!t)
+   /*construct the bar for a fraction*/
+{@+pointer p; /*the new node*/
+p=new_rule();height(p)=t;depth(p)=0;return p;
+}
+
+@ The |overbar| function returns a pointer to a vlist box that consists of
+a given box |b|, above which has been placed a kern of height |k| under a
+fraction rule of thickness |t| under additional space of height |t|.
+
+ at p static pointer overbar(pointer @!b, scaled @!k, scaled @!t)
+{@+pointer p, @!q; /*nodes being constructed*/
+p=new_kern(k);link(p)=b;q=fraction_rule(t);link(q)=p;
+p=new_kern(t);link(p)=q;return vpack(p, natural);
+}
+
+@ The |var_delimiter| function, which finds or constructs a sufficiently
+large delimiter, is the most interesting of the auxiliary functions that
+currently concern us. Given a pointer |d| to a delimiter field in some noad,
+together with a size code |s| and a vertical distance |v|, this function
+returns a pointer to a box that contains the smallest variant of |d| whose
+height plus depth is |v| or more. (And if no variant is large enough, it
+returns the largest available variant.) In particular, this routine will
+construct arbitrarily large delimiters from extensible components, if
+|d| leads to such characters.
+
+The value returned is a box whose |shift_amount| has been set so that
+the box is vertically centered with respect to the axis in the given size.
+If a built-up symbol is returned, the height of the box before shifting
+will be the height of its topmost component.
+
+ at p @t\4@>@<Declare subprocedures for |var_delimiter|@>@;
+static pointer var_delimiter(pointer @!d, small_number @!s, scaled @!v)
+{@+
+pointer b; /*the box that will be constructed*/
+internal_font_number @!f, @!g; /*best-so-far and tentative font codes*/
+quarterword @!c, @!x, @!y; /*best-so-far and tentative character codes*/
+int @!m, @!n; /*the number of extensible pieces*/
+scaled @!u; /*height-plus-depth of a tentative character*/
+scaled @!w; /*largest height-plus-depth so far*/
+four_quarters @!q; /*character info*/
+eight_bits @!hd; /*height-depth byte*/
+four_quarters @!r; /*extensible pieces*/
+small_number @!z; /*runs through font family members*/
+bool @!large_attempt; /*are we trying the ``large'' variant?*/
+f=null_font;w=0;large_attempt=false;
+z=small_fam(d);x=small_char(d);
+loop at +{@+@<Look at the variants of |(z,x)|; set |f| and |c| whenever a better character
+is found; |goto found| as soon as a large enough variant is encountered@>;
+  if (large_attempt) goto found; /*there were none large enough*/
+  large_attempt=true;z=large_fam(d);x=large_char(d);
+  }
+found: if (f!=null_font)
+  @<Make variable |b| point to a box for |(f,c)|@>;
+else{@+b=new_null_box();
+  width(b)=null_delimiter_space; /*use this width if no delimiter was found*/
+  }
+shift_amount(b)=half(height(b)-depth(b))-axis_height(s);
+return b;
+}
+
+@ The search process is complicated slightly by the facts that some of the
+characters might not be present in some of the fonts, and they might not
+be probed in increasing order of height.
+
+@<Look at the variants of |(z,x)|; set |f| and |c|...@>=
+if ((z!=0)||(x!=min_quarterword))
+  {@+z=z+s+16;
+  @/do at +{z=z-16;g=fam_fnt(z);
+  if (g!=null_font)
+    @<Look at the list of characters starting with |x| in font |g|; set |f| and |c|
+whenever a better character is found; |goto found| as soon as a large enough variant
+is encountered@>;
+  }@+ while (!(z < 16));
+  }
+
+@ @<Look at the list of characters starting with |x|...@>=
+{@+y=x;
+if ((qo(y) >= font_bc[g])&&(qo(y) <= font_ec[g]))
+  {@+resume: q=char_info(g, y);
+  if (char_exists(q))
+    {@+if (char_tag(q)==ext_tag)
+      {@+f=g;c=y;goto found;
+      }
+    hd=height_depth(q);
+    u=char_height(g, hd)+char_depth(g, hd);
+    if (u > w)
+      {@+f=g;c=y;w=u;
+      if (u >= v) goto found;
+      }
+    if (char_tag(q)==list_tag)
+      {@+y=rem_byte(q);goto resume;
+      }
+    }
+  }
+}
+
+@ Here is a subroutine that creates a new box, whose list contains a
+single character, and whose width includes the italic correction for
+that character. The height or depth of the box will be negative, if
+the height or depth of the character is negative; thus, this routine
+may deliver a slightly different result than |hpack| would produce.
+
+@<Declare subprocedures for |var_delimiter|@>=
+static pointer char_box(internal_font_number @!f, quarterword @!c)
+{@+four_quarters q;
+eight_bits @!hd; /*|height_depth| byte*/
+pointer @!b, @!p; /*the new box and its character node*/
+q=char_info(f, c);hd=height_depth(q);
+b=new_null_box();width(b)=char_width(f, q)+char_italic(f, q);
+height(b)=char_height(f, hd);depth(b)=char_depth(f, hd);
+p=get_avail();character(p)=c;font(p)=f;list_ptr(b)=p;return b;
+}
+
+@ When the following code is executed, |char_tag(q)| will be equal to
+|ext_tag| if and only if a built-up symbol is supposed to be returned.
+
+@<Make variable |b| point to a box for |(f,c)|@>=
+if (char_tag(q)==ext_tag)
+  @<Construct an extensible character in a new box |b|, using recipe |rem_byte(q)|
+and font |f|@>@;
+else b=char_box(f, c)
+
+@ When we build an extensible character, it's handy to have the
+following subroutine, which puts a given character on top
+of the characters already in box |b|:
+
+@<Declare subprocedures for |var_delimiter|@>=
+static void stack_into_box(pointer @!b, internal_font_number @!f,
+  quarterword @!c)
+{@+pointer p; /*new node placed into |b|*/
+p=char_box(f, c);link(p)=list_ptr(b);list_ptr(b)=p;
+height(b)=height(p);
+}
+
+@ Another handy subroutine computes the height plus depth of
+a given character:
+
+@<Declare subprocedures for |var_delimiter|@>=
+static scaled height_plus_depth(internal_font_number @!f, quarterword @!c)
+{@+four_quarters q;
+eight_bits @!hd; /*|height_depth| byte*/
+q=char_info(f, c);hd=height_depth(q);
+return char_height(f, hd)+char_depth(f, hd);
+}
+
+@ @<Construct an extensible...@>=
+{@+b=new_null_box();
+type(b)=vlist_node;
+r=font_info[exten_base[f]+rem_byte(q)].qqqq;@/
+@<Compute the minimum suitable height, |w|, and the corresponding number of extension
+steps, |n|; also set |width(b)|@>;
+c=ext_bot(r);
+if (c!=min_quarterword) stack_into_box(b, f, c);
+c=ext_rep(r);
+for (m=1; m<=n; m++) stack_into_box(b, f, c);
+c=ext_mid(r);
+if (c!=min_quarterword)
+  {@+stack_into_box(b, f, c);c=ext_rep(r);
+  for (m=1; m<=n; m++) stack_into_box(b, f, c);
+  }
+c=ext_top(r);
+if (c!=min_quarterword) stack_into_box(b, f, c);
+depth(b)=w-height(b);
+}
+
+@ The width of an extensible character is the width of the repeatable
+module. If this module does not have positive height plus depth,
+we don't use any copies of it, otherwise we use as few as possible
+(in groups of two if there is a middle part).
+
+@<Compute the minimum suitable height, |w|, and...@>=
+c=ext_rep(r);u=height_plus_depth(f, c);
+w=0;q=char_info(f, c);width(b)=char_width(f, q)+char_italic(f, q);@/
+c=ext_bot(r);@+if (c!=min_quarterword) w=w+height_plus_depth(f, c);
+c=ext_mid(r);@+if (c!=min_quarterword) w=w+height_plus_depth(f, c);
+c=ext_top(r);@+if (c!=min_quarterword) w=w+height_plus_depth(f, c);
+n=0;
+if (u > 0) while (w < v)
+  {@+w=w+u;incr(n);
+  if (ext_mid(r)!=min_quarterword) w=w+u;
+  }
+
+@ The next subroutine is much simpler; it is used for numerators and
+denominators of fractions as well as for displayed operators and
+their limits above and below. It takes a given box~|b| and
+changes it so that the new box is centered in a box of width~|w|.
+The centering is done by putting \.{\\hss} glue at the left and right
+of the list inside |b|, then packaging the new box; thus, the
+actual box might not really be centered, if it already contains
+infinite glue.
+
+The given box might contain a single character whose italic correction
+has been added to the width of the box; in this case a compensating
+kern is inserted.
+
+ at p static pointer rebox(pointer @!b, scaled @!w)
+{@+pointer p; /*temporary register for list manipulation*/
+internal_font_number @!f; /*font in a one-character box*/
+scaled @!v; /*width of a character without italic correction*/
+if ((width(b)!=w)&&(list_ptr(b)!=null))
+  {@+if (type(b)==vlist_node) b=hpack(b, natural);
+  p=list_ptr(b);
+  if ((is_char_node(p))&&(link(p)==null))
+    {@+f=font(p);v=char_width(f, char_info(f, character(p)));
+    if (v!=width(b)) link(p)=new_kern(width(b)-v);
+    }
+  list_ptr(b)=null; flush_node_list(b);
+  b=new_glue(ss_glue);link(b)=p;
+  while (link(p)!=null) p=link(p);
+  link(p)=new_glue(ss_glue);
+  return hpack(b, w, 0, 0, exactly);
+  }
+else{@+width(b)=w;return b;
+  }
+}
+
+@ Here is a subroutine that creates a new glue specification from another
+one that is expressed in `\.{mu}', given the value of the math unit.
+
+ at d mu_mult(A) nx_plus_y(n, A, xn_over_d(A, f, 0200000))
+
+ at p static pointer math_glue(pointer @!g, scaled @!m)
+{@+pointer p; /*the new glue specification*/
+int @!n; /*integer part of |m|*/
+scaled @!f; /*fraction part of |m|*/
+n=x_over_n(m, 0200000);f=rem;@/
+if (f < 0)
+  {@+decr(n);f=f+0200000;
+  }
+p=get_node(glue_spec_size);
+width(p)=mu_mult(width(g)); /*convert \.{mu} to \.{pt}*/
+stretch_order(p)=stretch_order(g);
+if (stretch_order(p)==normal) stretch(p)=mu_mult(stretch(g));
+else stretch(p)=stretch(g);
+shrink_order(p)=shrink_order(g);
+if (shrink_order(p)==normal) shrink(p)=mu_mult(shrink(g));
+else shrink(p)=shrink(g);
+return p;
+}
+
+@ The |math_kern| subroutine removes |mu_glue| from a kern node, given
+the value of the math unit.
+
+ at p static void math_kern(pointer @!p, scaled @!m)
+{@+int @!n; /*integer part of |m|*/
+scaled @!f; /*fraction part of |m|*/
+if (subtype(p)==mu_glue)
+  {@+n=x_over_n(m, 0200000);f=rem;@/
+  if (f < 0)
+    {@+decr(n);f=f+0200000;
+    }
+  width(p)=mu_mult(width(p));subtype(p)=explicit;
+  }
+}
+
+@ Sometimes it is necessary to destroy an mlist. The following
+subroutine empties the current list, assuming that |abs(mode)==mmode|.
+
+ at p static void flush_math(void)
+{@+flush_node_list(link(head));flush_node_list(incompleat_noad);
+link(head)=null;tail=head;incompleat_noad=null;
+}
+
+@* Typesetting math formulas.
+\TeX's most important routine for dealing with formulas is called
+|mlist_to_hlist|.  After a formula has been scanned and represented as an
+mlist, this routine converts it to an hlist that can be placed into a box
+or incorporated into the text of a paragraph. There are three implicit
+parameters, passed in global variables: |cur_mlist| points to the first
+node or noad in the given mlist (and it might be |null|); |cur_style| is a
+style code; and |mlist_penalties| is |true| if penalty nodes for potential
+line breaks are to be inserted into the resulting hlist. After
+|mlist_to_hlist| has acted, |link(temp_head)| points to the translated hlist.
+
+Since mlists can be inside mlists, the procedure is recursive. And since this
+is not part of \TeX's inner loop, the program has been written in a manner
+that stresses compactness over efficiency.
+@^recursion@>
+
+@<Glob...@>=
+static pointer @!cur_mlist; /*beginning of mlist to be translated*/
+static small_number @!cur_style; /*style code at current place in the list*/
+static small_number @!cur_size; /*size code corresponding to |cur_style|*/
+static scaled @!cur_mu; /*the math unit width corresponding to |cur_size|*/
+static bool @!mlist_penalties; /*should |mlist_to_hlist| insert penalties?*/
+
+@ The recursion in |mlist_to_hlist| is due primarily to a subroutine
+called |clean_box| that puts a given noad field into a box using a given
+math style; |mlist_to_hlist| can call |clean_box|, which can call
+|mlist_to_hlist|.
+@^recursion@>
+
+The box returned by |clean_box| is ``clean'' in the
+sense that its |shift_amount| is zero.
+
+ at p static void mlist_to_hlist(void);@/
+static pointer clean_box(pointer @!p, small_number @!s)
+{@+
+pointer q; /*beginning of a list to be boxed*/
+small_number @!save_style; /*|cur_style| to be restored*/
+pointer @!x; /*box to be returned*/
+pointer @!r; /*temporary pointer*/
+switch (math_type(p)) {
+case math_char: {@+cur_mlist=new_noad();mem[nucleus(cur_mlist)]=mem[p];
+  } @+break;
+case sub_box: {@+q=info(p);goto found;
+  }
+case sub_mlist: cur_mlist=info(p);@+break;
+default:{@+q=new_null_box();goto found;
+  }
+} @/
+save_style=cur_style;cur_style=s;mlist_penalties=false;@/
+mlist_to_hlist();q=link(temp_head); /*recursive call*/
+cur_style=save_style; /*restore the style*/
+@<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>;
+found: if (is_char_node(q)||(q==null)) x=hpack(q, natural);
+  else if ((link(q)==null)&&(type(q) <= vlist_node)&&(shift_amount(q)==0))
+    x=q; /*it's already clean*/
+  else x=hpack(q, natural);
+@<Simplify a trivial box@>;
+return x;
+}
+
+@ Here we save memory space in a common case.
+
+@<Simplify a trivial box@>=
+q=list_ptr(x);
+if (is_char_node(q))
+  {@+r=link(q);
+  if (r!=null) if (link(r)==null) if (!is_char_node(r))
+   if (type(r)==kern_node)  /*unneeded italic correction*/
+    {@+free_node(r, small_node_size);link(q)=null;
+    }
+  }
+
+@ It is convenient to have a procedure that converts a |math_char|
+field to an ``unpacked'' form. The |fetch| routine sets |cur_f|, |cur_c|,
+and |cur_i| to the font code, character code, and character information bytes of
+a given noad field. It also takes care of issuing error messages for
+nonexistent characters; in such cases, |char_exists(cur_i)| will be |false|
+after |fetch| has acted, and the field will also have been reset to |empty|.
+
+ at p static void fetch(pointer @!a) /*unpack the |math_char| field |a|*/
+{@+cur_c=character(a);cur_f=fam_fnt(fam(a)+cur_size);
+if (cur_f==null_font)
+  @<Complain about an undefined family and set |cur_i| null@>@;
+else{@+if ((qo(cur_c) >= font_bc[cur_f])&&(qo(cur_c) <= font_ec[cur_f]))
+    cur_i=char_info(cur_f, cur_c);
+  else cur_i=null_character;
+  if (!(char_exists(cur_i)))
+    {@+char_warning(cur_f, qo(cur_c));
+    math_type(a)=empty;cur_i=null_character;
+    }
+  }
+}
+
+@ @<Complain about an undefined family...@>=
+{@+print_err("");print_size(cur_size);print_char(' ');
+print_int(fam(a));print(" is undefined (character ");
+print_ASCII(qo(cur_c));print_char(')');
+help4("Somewhere in the math formula just ended, you used the",@/
+"stated character from an undefined font family. For example,",@/
+"plain TeX doesn't allow \\it or \\sl in subscripts. Proceed,",@/
+"and I'll try to forget that I needed that character.");
+error();cur_i=null_character;math_type(a)=empty;
+}
+
+@ The outputs of |fetch| are placed in global variables.
+
+@<Glob...@>=
+static internal_font_number @!cur_f; /*the |font| field of a |math_char|*/
+static quarterword @!cur_c; /*the |character| field of a |math_char|*/
+static four_quarters @!cur_i; /*the |char_info| of a |math_char|,
+  or a lig/kern instruction*/
+
+@ We need to do a lot of different things, so |mlist_to_hlist| makes two
+passes over the given mlist.
+
+The first pass does most of the processing: It removes ``mu'' spacing from
+glue, it recursively evaluates all subsidiary mlists so that only the
+top-level mlist remains to be handled, it puts fractions and square roots
+and such things into boxes, it attaches subscripts and superscripts, and
+it computes the overall height and depth of the top-level mlist so that
+the size of delimiters for a |left_noad| and a |right_noad| will be known.
+The hlist resulting from each noad is recorded in that noad's |new_hlist|
+field, an integer field that replaces the |nucleus| or |thickness|.
+@^recursion@>
+
+The second pass eliminates all noads and inserts the correct glue and
+penalties between nodes.
+
+ at d new_hlist(A) mem[nucleus(A)].i /*the translation of an mlist*/
+
+@ Here is the overall plan of |mlist_to_hlist|, and the list of its
+local variables.
+
+ at p @t\4@>@<Declare math construction procedures@>@;
+static void mlist_to_hlist(void)
+{@+
+
+pointer mlist; /*beginning of the given list*/
+bool @!penalties; /*should penalty nodes be inserted?*/
+small_number @!style; /*the given style*/
+small_number @!save_style; /*holds |cur_style| during recursion*/
+pointer @!q; /*runs through the mlist*/
+pointer @!r; /*the most recent noad preceding |q|*/
+small_number @!r_type; /*the |type| of noad |r|, or |op_noad| if |r==null|*/
+small_number @!t; /*the effective |type| of noad |q| during the second pass*/
+pointer @!p, @!x, @!y, @!z; /*temporary registers for list construction*/
+int @!pen; /*a penalty to be inserted*/
+small_number @!s; /*the size of a noad to be deleted*/
+scaled @!max_h, @!max_d; /*maximum height and depth of the list translated so far*/
+scaled @!delta; /*offset between subscript and superscript*/
+mlist=cur_mlist;penalties=mlist_penalties;
+style=cur_style; /*tuck global parameters away as local variables*/
+q=mlist;r=null;r_type=op_noad;max_h=0;max_d=0;
+@<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>;
+while (q!=null) @<Process node-or-noad |q| as much as possible in preparation for
+the second pass of |mlist_to_hlist|, then move to the next item in the mlist@>;
+@<Convert \(a)a final |bin_noad| to an |ord_noad|@>;
+@<Make a second pass over the mlist, removing all noads and inserting the proper spacing
+and penalties@>;
+}
+
+@ We use the fact that no character nodes appear in an mlist, hence
+the field |type(q)| is always present.
+
+@<Process node-or-noad...@>=
+{@+@<Do first-pass processing based on |type(q)|; |goto done_with_noad| if a noad
+has been fully processed, |goto check_dimensions| if it has been translated into |new_hlist(q)|,
+or |goto done_with_node| if a node has been fully processed@>;
+check_dimensions: z=hpack(new_hlist(q), natural);
+if (height(z) > max_h) max_h=height(z);
+if (depth(z) > max_d) max_d=depth(z);
+list_ptr(z)=null; flush_node_list(z);
+done_with_noad: r=q;r_type=type(r);
+if (r_type==right_noad)
+  {@+r_type=left_noad;cur_style=style;@<Set up the values...@>;
+  }
+done_with_node: q=link(q);
+}
+
+@ One of the things we must do on the first pass is change a |bin_noad| to
+an |ord_noad| if the |bin_noad| is not in the context of a binary operator.
+The values of |r| and |r_type| make this fairly easy.
+
+@<Do first-pass processing...@>=
+reswitch: delta=0;
+switch (type(q)) {
+case bin_noad: switch (r_type) {
+  case bin_noad: case op_noad: case rel_noad: case open_noad: case punct_noad: case left_noad:
+    {@+type(q)=ord_noad;goto reswitch;
+    }
+  default:do_nothing;
+  } @+break;
+case rel_noad: case close_noad: case punct_noad: case right_noad: {@+ at t@>@;@/
+  @<Convert \(a)a final |bin_noad| to an |ord_noad|@>;
+  if (type(q)==right_noad) goto done_with_noad;
+  } @+break;
+ at t\4@>@<Cases for noads that can follow a |bin_noad|@>@;
+ at t\4@>@<Cases for nodes that can appear in an mlist, after which we |goto done_with_node|@>@;
+default:confusion("mlist1");
+@:this can't happen mlist1}{\quad mlist1@>
+} @/
+@<Convert \(n)|nucleus(q)| to an hlist and attach the sub/superscripts@>@;
+
+@ @<Convert \(a)a final |bin_noad| to an |ord_noad|@>=
+if (r_type==bin_noad) type(r)=ord_noad
+
+@ @<Cases for nodes that can appear in an mlist...@>=
+case style_node: {@+cur_style=subtype(q);
+  @<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>;
+  goto done_with_node;
+  }
+case choice_node: @<Change this node to a style node followed by the correct choice,
+then |goto done_with_node|@>@;
+case ins_node: case mark_node: case adjust_node:
+  case whatsit_node: case penalty_node: case disc_node: goto done_with_node;
+case rule_node: {@+if (height(q) > max_h) max_h=height(q);
+  if (depth(q) > max_d) max_d=depth(q);goto done_with_node;
+  }
+case glue_node: {@+@<Convert \(m)math glue to ordinary glue@>;
+  goto done_with_node;
+  }
+case kern_node: {@+math_kern(q, cur_mu);goto done_with_node;
+  }
+
+@ @d choose_mlist(A) {@+p=A(q);A(q)=null;@+}
+
+@<Change this node to a style node...@>=
+{@+switch (cur_style/2) {
+case 0: choose_mlist(display_mlist)@;@+break; /*|display_style==0|*/
+case 1: choose_mlist(text_mlist)@;@+break; /*|text_style==2|*/
+case 2: choose_mlist(script_mlist)@;@+break; /*|script_style==4|*/
+case 3: choose_mlist(script_script_mlist); /*|script_script_style==6|*/
+}  /*there are no other cases*/
+flush_node_list(display_mlist(q));
+flush_node_list(text_mlist(q));
+flush_node_list(script_mlist(q));
+flush_node_list(script_script_mlist(q));@/
+type(q)=style_node;subtype(q)=cur_style;width(q)=0;depth(q)=0;
+if (p!=null)
+  {@+z=link(q);link(q)=p;
+  while (link(p)!=null) p=link(p);
+  link(p)=z;
+  }
+goto done_with_node;
+}
+
+@ Conditional math glue (`\.{\\nonscript}') results in a |glue_node|
+pointing to |zero_glue|, with |subtype(q)==cond_math_glue|; in such a case
+the node following will be eliminated if it is a glue or kern node and if the
+current size is different from |text_size|. Unconditional math glue
+(`\.{\\muskip}') is converted to normal glue by multiplying the dimensions
+by |cur_mu|.
+@!@:non\_script\_}{\.{\\nonscript} primitive@>
+
+@<Convert \(m)math glue to ordinary glue@>=
+if (subtype(q)==mu_glue)
+  {@+x=glue_ptr(q);
+  y=math_glue(x, cur_mu);delete_glue_ref(x);glue_ptr(q)=y;
+  subtype(q)=normal;
+  }
+else if ((cur_size!=text_size)&&(subtype(q)==cond_math_glue))
+  {@+p=link(q);
+  if (p!=null) if ((type(p)==glue_node)||(type(p)==kern_node))
+    {@+link(q)=link(p);link(p)=null;flush_node_list(p);
+    }
+  }
+
+@ @<Cases for noads that can follow a |bin_noad|@>=
+case left_noad: goto done_with_noad;
+case fraction_noad: {@+make_fraction(q);goto check_dimensions;
+  }
+case op_noad: {@+delta=make_op(q);
+  if (subtype(q)==limits) goto check_dimensions;
+  } @+break;
+case ord_noad: make_ord(q);@+break;
+case open_noad: case inner_noad: do_nothing;@+break;
+case radical_noad: make_radical(q);@+break;
+case over_noad: make_over(q);@+break;
+case under_noad: make_under(q);@+break;
+case accent_noad: make_math_accent(q);@+break;
+case vcenter_noad: make_vcenter(q);@+break;
+
+@ Most of the actual construction work of |mlist_to_hlist| is done
+by procedures with names
+like |make_fraction|, |make_radical|, etc. To illustrate
+the general setup of such procedures, let's begin with a couple of
+simple ones.
+
+@<Declare math...@>=
+static void make_over(pointer @!q)
+{@+info(nucleus(q))=@|
+  overbar(clean_box(nucleus(q), cramped_style(cur_style)),@|
+  3*default_rule_thickness, default_rule_thickness);
+math_type(nucleus(q))=sub_box;
+}
+
+@ @<Declare math...@>=
+static void make_under(pointer @!q)
+{@+pointer p, @!x, @!y; /*temporary registers for box construction*/
+scaled @!delta; /*overall height plus depth*/
+x=clean_box(nucleus(q), cur_style);
+p=new_kern(3*default_rule_thickness);link(x)=p;
+link(p)=fraction_rule(default_rule_thickness);
+y=vpack(x, natural);
+delta=height(y)+depth(y)+default_rule_thickness;
+height(y)=height(x);depth(y)=delta-height(y);
+info(nucleus(q))=y;math_type(nucleus(q))=sub_box;
+}
+
+@ @<Declare math...@>=
+static void make_vcenter(pointer @!q)
+{@+pointer v; /*the box that should be centered vertically*/
+scaled @!delta; /*its height plus depth*/
+v=info(nucleus(q));
+if (type(v)!=vlist_node) confusion("vcenter");
+@:this can't happen vcenter}{\quad vcenter@>
+delta=height(v)+depth(v);
+height(v)=axis_height(cur_size)+half(delta);
+depth(v)=delta-height(v);
+}
+
+@ According to the rules in the \.{DVI} file specifications, we ensure alignment
+@^square roots@>
+between a square root sign and the rule above its nucleus by assuming that the
+baseline of the square-root symbol is the same as the bottom of the rule. The
+height of the square-root symbol will be the thickness of the rule, and the
+depth of the square-root symbol should exceed or equal the height-plus-depth
+of the nucleus plus a certain minimum clearance~|clr|. The symbol will be
+placed so that the actual clearance is |clr| plus half the excess.
+
+@<Declare math...@>=
+static void make_radical(pointer @!q)
+{@+pointer x, @!y; /*temporary registers for box construction*/
+scaled @!delta, @!clr; /*dimensions involved in the calculation*/
+x=clean_box(nucleus(q), cramped_style(cur_style));
+if (cur_style < text_style)  /*display style*/
+  clr=default_rule_thickness+(abs(math_x_height(cur_size))/4);
+else{@+clr=default_rule_thickness;clr=clr+(abs(clr)/4);
+  }
+y=var_delimiter(left_delimiter(q), cur_size, height(x)+depth(x)+clr+
+  default_rule_thickness);
+delta=depth(y)-(height(x)+depth(x)+clr);
+if (delta > 0) clr=clr+half(delta); /*increase the actual clearance*/
+shift_amount(y)=-(height(x)+clr);
+link(y)=overbar(x, clr, height(y));
+info(nucleus(q))=hpack(y, natural);math_type(nucleus(q))=sub_box;
+}
+
+@ Slants are not considered when placing accents in math mode. The accenter is
+centered over the accentee, and the accent width is treated as zero with
+respect to the size of the final box.
+
+@<Declare math...@>=
+static void make_math_accent(pointer @!q)
+{@+
+pointer p, @!x, @!y; /*temporary registers for box construction*/
+int @!a; /*address of lig/kern instruction*/
+quarterword @!c; /*accent character*/
+internal_font_number @!f; /*its font*/
+four_quarters @!i; /*its |char_info|*/
+scaled @!s; /*amount to skew the accent to the right*/
+scaled @!h; /*height of character being accented*/
+scaled @!delta; /*space to remove between accent and accentee*/
+scaled @!w; /*width of the accentee, not including sub/superscripts*/
+fetch(accent_chr(q));
+if (char_exists(cur_i))
+  {@+i=cur_i;c=cur_c;f=cur_f;@/
+  @<Compute the amount of skew@>;
+  x=clean_box(nucleus(q), cramped_style(cur_style));w=width(x);h=height(x);
+  @<Switch to a larger accent if available and appropriate@>;
+  if (h < x_height(f)) delta=h;@+else delta=x_height(f);
+  if ((math_type(supscr(q))!=empty)||(math_type(subscr(q))!=empty))
+    if (math_type(nucleus(q))==math_char)
+      @<Swap the subscript and superscript into box |x|@>;
+  y=char_box(f, c);
+  shift_amount(y)=s+half(w-width(y));
+  width(y)=0;p=new_kern(-delta);link(p)=x;link(y)=p;
+  y=vpack(y, natural);width(y)=width(x);
+  if (height(y) < h) @<Make the height of box |y| equal to |h|@>;
+  info(nucleus(q))=y;
+  math_type(nucleus(q))=sub_box;
+  }
+}
+
+@ @<Make the height of box |y|...@>=
+{@+p=new_kern(h-height(y));link(p)=list_ptr(y);list_ptr(y)=p;
+height(y)=h;
+}
+
+@ @<Switch to a larger accent if available and appropriate@>=
+loop at +{@+if (char_tag(i)!=list_tag) goto done;
+  y=rem_byte(i);
+  i=char_info(f, y);
+  if (!char_exists(i)) goto done;
+  if (char_width(f, i) > w) goto done;
+  c=y;
+  }
+done:
+
+@ @<Compute the amount of skew@>=
+s=0;
+if (math_type(nucleus(q))==math_char)
+  {@+fetch(nucleus(q));
+  if (char_tag(cur_i)==lig_tag)
+    {@+a=lig_kern_start(cur_f, cur_i);
+    cur_i=font_info[a].qqqq;
+    if (skip_byte(cur_i) > stop_flag)
+      {@+a=lig_kern_restart(cur_f, cur_i);
+      cur_i=font_info[a].qqqq;
+      }
+    loop at +{@+if (qo(next_char(cur_i))==skew_char[cur_f])
+        {@+if (op_byte(cur_i) >= kern_flag)
+          if (skip_byte(cur_i) <= stop_flag) s=char_kern(cur_f, cur_i);
+        goto done1;
+        }
+      if (skip_byte(cur_i) >= stop_flag) goto done1;
+      a=a+qo(skip_byte(cur_i))+1;
+      cur_i=font_info[a].qqqq;
+      }
+    }
+  }
+done1:
+
+@ @<Swap the subscript and superscript into box |x|@>=
+{@+flush_node_list(x);x=new_noad();
+mem[nucleus(x)]=mem[nucleus(q)];
+mem[supscr(x)]=mem[supscr(q)];
+mem[subscr(x)]=mem[subscr(q)];@/
+mem[supscr(q)].hh=empty_field;
+mem[subscr(q)].hh=empty_field;@/
+math_type(nucleus(q))=sub_mlist;info(nucleus(q))=x;
+x=clean_box(nucleus(q), cur_style);delta=delta+height(x)-h;h=height(x);
+}
+
+@ The |make_fraction| procedure is a bit different because it sets
+|new_hlist(q)| directly rather than making a sub-box.
+
+@<Declare math...@>=
+static void make_fraction(pointer @!q)
+{@+pointer p, @!v, @!x, @!y, @!z; /*temporary registers for box construction*/
+scaled @!delta, @!delta1, @!delta2, @!shift_up, @!shift_down, @!clr;
+   /*dimensions for box calculations*/
+if (thickness(q)==default_code) thickness(q)=default_rule_thickness;
+@<Create equal-width boxes |x| and |z| for the numerator and denominator, and compute
+the default amounts |shift_up| and |shift_down| by which they are displaced from the
+baseline@>;
+if (thickness(q)==0) @<Adjust \(s)|shift_up| and |shift_down| for the case of no fraction
+line@>@;
+else@<Adjust \(s)|shift_up| and |shift_down| for the case of a fraction line@>;
+@<Construct a vlist box for the fraction, according to |shift_up| and |shift_down|@>;
+@<Put the \(f)fraction into a box with its delimiters, and make |new_hlist(q)| point
+to it@>;
+}
+
+@ @<Create equal-width boxes |x| and |z| for the numerator and denom...@>=
+x=clean_box(numerator(q), num_style(cur_style));
+z=clean_box(denominator(q), denom_style(cur_style));
+if (width(x) < width(z)) x=rebox(x, width(z));
+else z=rebox(z, width(x));
+if (cur_style < text_style)  /*display style*/
+  {@+shift_up=num1(cur_size);shift_down=denom1(cur_size);
+  }
+else{@+shift_down=denom2(cur_size);
+  if (thickness(q)!=0) shift_up=num2(cur_size);
+  else shift_up=num3(cur_size);
+  }
+
+@ The numerator and denominator must be separated by a certain minimum
+clearance, called |clr| in the following program. The difference between
+|clr| and the actual clearance is twice |delta|.
+
+@<Adjust \(s)|shift_up| and |shift_down| for the case of no fraction line@>=
+{@+if (cur_style < text_style) clr=7*default_rule_thickness;
+else clr=3*default_rule_thickness;
+delta=half(clr-((shift_up-depth(x))-(height(z)-shift_down)));
+if (delta > 0)
+  {@+shift_up=shift_up+delta;
+  shift_down=shift_down+delta;
+  }
+}
+
+@ In the case of a fraction line, the minimum clearance depends on the actual
+thickness of the line.
+
+@<Adjust \(s)|shift_up| and |shift_down| for the case of a fraction line@>=
+{@+if (cur_style < text_style) clr=3*thickness(q);
+else clr=thickness(q);
+delta=half(thickness(q));
+delta1=clr-((shift_up-depth(x))-(axis_height(cur_size)+delta));
+delta2=clr-((axis_height(cur_size)-delta)-(height(z)-shift_down));
+if (delta1 > 0) shift_up=shift_up+delta1;
+if (delta2 > 0) shift_down=shift_down+delta2;
+}
+
+@ @<Construct a vlist box for the fraction...@>=
+v=new_null_box();type(v)=vlist_node;
+height(v)=shift_up+height(x);depth(v)=depth(z)+shift_down;
+width(v)=width(x); /*this also equals |width(z)|*/
+if (thickness(q)==0)
+  {@+p=new_kern((shift_up-depth(x))-(height(z)-shift_down));
+  link(p)=z;
+  }
+else{@+y=fraction_rule(thickness(q));@/
+  p=new_kern((axis_height(cur_size)-delta)-@|(height(z)-shift_down));@/
+  link(y)=p;link(p)=z;@/
+  p=new_kern((shift_up-depth(x))-(axis_height(cur_size)+delta));
+  link(p)=y;
+  }
+link(x)=p;list_ptr(v)=x
+
+@ @<Put the \(f)fraction into a box with its delimiters...@>=
+if (cur_style < text_style) delta=delim1(cur_size);
+else delta=delim2(cur_size);
+x=var_delimiter(left_delimiter(q), cur_size, delta);link(x)=v;@/
+z=var_delimiter(right_delimiter(q), cur_size, delta);link(v)=z;@/
+new_hlist(q)=hpack(x, natural)
+
+@ If the nucleus of an |op_noad| is a single character, it is to be
+centered vertically with respect to the axis, after first being enlarged
+(via a character list in the font) if we are in display style.  The normal
+convention for placing displayed limits is to put them above and below the
+operator in display style.
+
+The italic correction is removed from the character if there is a subscript
+and the limits are not being displayed. The |make_op|
+routine returns the value that should be used as an offset between
+subscript and superscript.
+
+After |make_op| has acted, |subtype(q)| will be |limits| if and only if
+the limits have been set above and below the operator. In that case,
+|new_hlist(q)| will already contain the desired final box.
+
+@<Declare math...@>=
+static scaled make_op(pointer @!q)
+{@+scaled delta; /*offset between subscript and superscript*/
+pointer @!p, @!v, @!x, @!y, @!z; /*temporary registers for box construction*/
+quarterword @!c;@+four_quarters @!i; /*registers for character examination*/
+scaled @!shift_up, @!shift_down; /*dimensions for box calculation*/
+if ((subtype(q)==normal)&&(cur_style < text_style))
+  subtype(q)=limits;
+if (math_type(nucleus(q))==math_char)
+  {@+fetch(nucleus(q));
+  if ((cur_style < text_style)&&(char_tag(cur_i)==list_tag))  /*make it larger*/
+    {@+c=rem_byte(cur_i);i=char_info(cur_f, c);
+    if (char_exists(i))
+      {@+cur_c=c;cur_i=i;character(nucleus(q))=c;
+      }
+    }
+  delta=char_italic(cur_f, cur_i);x=clean_box(nucleus(q), cur_style);
+  if ((math_type(subscr(q))!=empty)&&(subtype(q)!=limits))
+    width(x)=width(x)-delta; /*remove italic correction*/
+  shift_amount(x)=half(height(x)-depth(x))-axis_height(cur_size);
+     /*center vertically*/
+  math_type(nucleus(q))=sub_box;info(nucleus(q))=x;
+  }
+else delta=0;
+if (subtype(q)==limits)
+  @<Construct a box with limits above and below it, skewed by |delta|@>;
+return delta;
+}
+
+@ The following program builds a vlist box |v| for displayed limits. The
+width of the box is not affected by the fact that the limits may be skewed.
+
+@<Construct a box with limits above and below it...@>=
+{@+x=clean_box(supscr(q), sup_style(cur_style));
+y=clean_box(nucleus(q), cur_style);
+z=clean_box(subscr(q), sub_style(cur_style));
+v=new_null_box();type(v)=vlist_node;width(v)=width(y);
+if (width(x) > width(v)) width(v)=width(x);
+if (width(z) > width(v)) width(v)=width(z);
+x=rebox(x, width(v));y=rebox(y, width(v));z=rebox(z, width(v));@/
+shift_amount(x)=half(delta);shift_amount(z)=-shift_amount(x);
+height(v)=height(y);depth(v)=depth(y);
+@<Attach the limits to |y| and adjust |height(v)|, |depth(v)| to account for their
+presence@>;
+new_hlist(q)=v;
+}
+
+@ We use |shift_up| and |shift_down| in the following program for the
+amount of glue between the displayed operator |y| and its limits |x| and
+|z|. The vlist inside box |v| will consist of |x| followed by |y| followed
+by |z|, with kern nodes for the spaces between and around them.
+
+@<Attach the limits to |y| and adjust |height(v)|, |depth(v)|...@>=
+if (math_type(supscr(q))==empty)
+  {@+list_ptr(x)=null; flush_node_list(x);list_ptr(v)=y;
+  }
+else{@+shift_up=big_op_spacing3-depth(x);
+  if (shift_up < big_op_spacing1) shift_up=big_op_spacing1;
+  p=new_kern(shift_up);link(p)=y;link(x)=p;@/
+  p=new_kern(big_op_spacing5);link(p)=x;list_ptr(v)=p;
+  height(v)=height(v)+big_op_spacing5+height(x)+depth(x)+shift_up;
+  }
+if (math_type(subscr(q))==empty)@/
+  {@+list_ptr(z)=null;@+flush_node_list(z);@+}
+else{@+shift_down=big_op_spacing4-height(z);
+  if (shift_down < big_op_spacing2) shift_down=big_op_spacing2;
+  p=new_kern(shift_down);link(y)=p;link(p)=z;@/
+  p=new_kern(big_op_spacing5);link(z)=p;
+  depth(v)=depth(v)+big_op_spacing5+height(z)+depth(z)+shift_down;
+  }
+
+@ A ligature found in a math formula does not create a |ligature_node|, because
+there is no question of hyphenation afterwards; the ligature will simply be
+stored in an ordinary |char_node|, after residing in an |ord_noad|.
+
+The |math_type| is converted to |math_text_char| here if we would not want to
+apply an italic correction to the current character unless it belongs
+to a math font (i.e., a font with |space==0|).
+
+No boundary characters enter into these ligatures.
+
+@<Declare math...@>=
+static void make_ord(pointer @!q)
+{@+
+int a; /*address of lig/kern instruction*/
+pointer @!p, @!r; /*temporary registers for list manipulation*/
+restart: @t@>@;@/
+if (math_type(subscr(q))==empty) if (math_type(supscr(q))==empty)
+ if (math_type(nucleus(q))==math_char)
+  {@+p=link(q);
+  if (p!=null) if ((type(p) >= ord_noad)&&(type(p) <= punct_noad))
+    if (math_type(nucleus(p))==math_char)
+    if (fam(nucleus(p))==fam(nucleus(q)))
+      {@+math_type(nucleus(q))=math_text_char;
+      fetch(nucleus(q));
+      if (char_tag(cur_i)==lig_tag)
+        {@+a=lig_kern_start(cur_f, cur_i);
+        cur_c=character(nucleus(p));
+        cur_i=font_info[a].qqqq;
+        if (skip_byte(cur_i) > stop_flag)
+          {@+a=lig_kern_restart(cur_f, cur_i);
+          cur_i=font_info[a].qqqq;
+          }
+        loop at +{@+@<If instruction |cur_i| is a kern with |cur_c|, attach the kern
+after~|q|; or if it is a ligature with |cur_c|, combine noads |q| and~|p| appropriately;
+then |return| if the cursor has moved past a noad, or |goto restart|@>;
+          if (skip_byte(cur_i) >= stop_flag) return;
+          a=a+qo(skip_byte(cur_i))+1;
+          cur_i=font_info[a].qqqq;
+          }
+        }
+      }
+  }
+}
+
+@ Note that a ligature between an |ord_noad| and another kind of noad
+is replaced by an |ord_noad|, when the two noads collapse into one.
+But we could make a parenthesis (say) change shape when it follows
+certain letters. Presumably a font designer will define such
+ligatures only when this convention makes sense.
+
+\chardef\@@='174 % vertical line to indicate character retention
+
+@<If instruction |cur_i| is a kern with |cur_c|,...@>=
+if (next_char(cur_i)==cur_c) if (skip_byte(cur_i) <= stop_flag)
+  if (op_byte(cur_i) >= kern_flag)
+    {@+p=new_kern(char_kern(cur_f, cur_i));
+    link(p)=link(q);link(q)=p;return;
+    }
+  else{@+check_interrupt; /*allow a way out of infinite ligature loop*/
+    switch (op_byte(cur_i)) {
+  case qi(1): case qi(5): character(nucleus(q))=rem_byte(cur_i);@+break; /*\.{=:\@@}, \.{=:\@@>}*/
+  case qi(2): case qi(6): character(nucleus(p))=rem_byte(cur_i);@+break; /*\.{\@@=:}, \.{\@@=:>}*/
+  case qi(3): case qi(7): case qi(11): {@+r=new_noad(); /*\.{\@@=:\@@}, \.{\@@=:\@@>}, \.{\@@=:\@@>>}*/
+      character(nucleus(r))=rem_byte(cur_i);
+      fam(nucleus(r))=fam(nucleus(q));@/
+      link(q)=r;link(r)=p;
+      if (op_byte(cur_i) < qi(11)) math_type(nucleus(r))=math_char;
+      else math_type(nucleus(r))=math_text_char; /*prevent combination*/
+      } @+break;
+    default:{@+link(q)=link(p);
+      character(nucleus(q))=rem_byte(cur_i); /*\.{=:}*/
+      mem[subscr(q)]=mem[subscr(p)];mem[supscr(q)]=mem[supscr(p)];@/
+      free_node(p, noad_size);
+      }
+    }
+    if (op_byte(cur_i) > qi(3)) return;
+    math_type(nucleus(q))=math_char;goto restart;
+    }
+
+@ When we get to the following part of the program, we have ``fallen through''
+from cases that did not lead to |check_dimensions| or |done_with_noad| or
+|done_with_node|. Thus, |q|~points to a noad whose nucleus may need to be
+converted to an hlist, and whose subscripts and superscripts need to be
+appended if they are present.
+
+If |nucleus(q)| is not a |math_char|, the variable |delta| is the amount
+by which a superscript should be moved right with respect to a subscript
+when both are present.
+@^subscripts@>
+@^superscripts@>
+
+@<Convert \(n)|nucleus(q)| to an hlist and attach the sub/superscripts@>=
+switch (math_type(nucleus(q))) {
+case math_char: case math_text_char:
+  @<Create a character node |p| for |nucleus(q)|, possibly followed by a kern node
+for the italic correction, and set |delta| to the italic correction if a subscript
+is present@>@;@+break;
+case empty: p=null;@+break;
+case sub_box: p=info(nucleus(q));@+break;
+case sub_mlist: {@+cur_mlist=info(nucleus(q));save_style=cur_style;
+  mlist_penalties=false;mlist_to_hlist(); /*recursive call*/
+@^recursion@>
+  cur_style=save_style;@<Set up the values...@>;
+  p=hpack(link(temp_head), natural);
+  } @+break;
+default:confusion("mlist2");
+@:this can't happen mlist2}{\quad mlist2@>
+} @/
+new_hlist(q)=p;
+if ((math_type(subscr(q))==empty)&&(math_type(supscr(q))==empty))
+  goto check_dimensions;
+make_scripts(q, delta)
+
+@ @<Create a character node |p| for |nucleus(q)|...@>=
+{@+fetch(nucleus(q));
+if (char_exists(cur_i))
+  {@+delta=char_italic(cur_f, cur_i);p=new_character(cur_f, qo(cur_c));
+  if ((math_type(nucleus(q))==math_text_char)&&(space(cur_f)!=0))
+    delta=0; /*no italic correction in mid-word of text font*/
+  if ((math_type(subscr(q))==empty)&&(delta!=0))
+    {@+link(p)=new_kern(delta);delta=0;
+    }
+  }
+else p=null;
+}
+
+@ The purpose of |make_scripts(q, delta)| is to attach the subscript and/or
+superscript of noad |q| to the list that starts at |new_hlist(q)|,
+given that the subscript and superscript aren't both empty. The superscript
+will appear to the right of the subscript by a given distance |delta|.
+
+We set |shift_down| and |shift_up| to the minimum amounts to shift the
+baseline of subscripts and superscripts based on the given nucleus.
+
+@<Declare math...@>=
+static void make_scripts(pointer @!q, scaled @!delta)
+{@+pointer p, @!x, @!y, @!z; /*temporary registers for box construction*/
+scaled @!shift_up, @!shift_down, @!clr; /*dimensions in the calculation*/
+small_number @!t; /*subsidiary size code*/
+p=new_hlist(q);
+if (is_char_node(p))
+  {@+shift_up=0;shift_down=0;
+  }
+else{@+z=hpack(p, natural);
+  if (cur_style < script_style) t=script_size;@+else t=script_script_size;
+  shift_up=height(z)-sup_drop(t);
+  shift_down=depth(z)+sub_drop(t);
+  list_ptr(z)=null;flush_node_list(z);
+  }
+if (math_type(supscr(q))==empty)
+  @<Construct a subscript box |x| when there is no superscript@>@;
+else{@+@<Construct a superscript box |x|@>;
+  if (math_type(subscr(q))==empty) shift_amount(x)=-shift_up;
+  else@<Construct a sub/superscript combination box |x|, with the superscript offset
+by |delta|@>;
+  }
+if (new_hlist(q)==null) new_hlist(q)=x;
+else{@+p=new_hlist(q);
+  while (link(p)!=null) p=link(p);
+  link(p)=x;
+  }
+}
+
+@ When there is a subscript without a superscript, the top of the subscript
+should not exceed the baseline plus four-fifths of the x-height.
+
+@<Construct a subscript box |x| when there is no superscript@>=
+{@+x=clean_box(subscr(q), sub_style(cur_style));
+width(x)=width(x)+script_space;
+if (shift_down < sub1(cur_size)) shift_down=sub1(cur_size);
+clr=height(x)-(abs(math_x_height(cur_size)*4)/5);
+if (shift_down < clr) shift_down=clr;
+shift_amount(x)=shift_down;
+}
+
+@ The bottom of a superscript should never descend below the baseline plus
+one-fourth of the x-height.
+
+@<Construct a superscript box |x|@>=
+{@+x=clean_box(supscr(q), sup_style(cur_style));
+width(x)=width(x)+script_space;
+if (odd(cur_style)) clr=sup3(cur_size);
+else if (cur_style < text_style) clr=sup1(cur_size);
+else clr=sup2(cur_size);
+if (shift_up < clr) shift_up=clr;
+clr=depth(x)+(abs(math_x_height(cur_size))/4);
+if (shift_up < clr) shift_up=clr;
+}
+
+@ When both subscript and superscript are present, the subscript must be
+separated from the superscript by at least four times |default_rule_thickness|.
+If this condition would be violated, the subscript moves down, after which
+both subscript and superscript move up so that the bottom of the superscript
+is at least as high as the baseline plus four-fifths of the x-height.
+
+@<Construct a sub/superscript combination box |x|...@>=
+{@+y=clean_box(subscr(q), sub_style(cur_style));
+width(y)=width(y)+script_space;
+if (shift_down < sub2(cur_size)) shift_down=sub2(cur_size);
+clr=4*default_rule_thickness-
+  ((shift_up-depth(x))-(height(y)-shift_down));
+if (clr > 0)
+  {@+shift_down=shift_down+clr;
+  clr=(abs(math_x_height(cur_size)*4)/5)-(shift_up-depth(x));
+  if (clr > 0)
+    {@+shift_up=shift_up+clr;
+    shift_down=shift_down-clr;
+    }
+  }
+shift_amount(x)=delta; /*superscript is |delta| to the right of the subscript*/
+p=new_kern((shift_up-depth(x))-(height(y)-shift_down));link(x)=p;link(p)=y;
+x=vpack(x, natural);shift_amount(x)=shift_down;
+}
+
+@ We have now tied up all the loose ends of the first pass of |mlist_to_hlist|.
+The second pass simply goes through and hooks everything together with the
+proper glue and penalties. It also handles the |left_noad| and |right_noad| that
+might be present, since |max_h| and |max_d| are now known. Variable |p| points
+to a node at the current end of the final hlist.
+
+@<Make a second pass over the mlist,...@>=
+p=temp_head;link(p)=null;q=mlist;r_type=0;cur_style=style;
+@<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>;
+while (q!=null)
+  {@+@<If node |q| is a style node, change the style and |goto delete_q|; otherwise
+if it is not a noad, put it into the hlist, advance |q|, and |goto done|; otherwise
+set |s| to the size of noad |q|, set |t| to the associated type (|ord_noad.. inner_noad|),
+and set |pen| to the associated penalty@>;
+  @<Append inter-element spacing based on |r_type| and |t|@>;
+  @<Append any |new_hlist| entries for |q|, and any appropriate penalties@>;
+  if (type(q)==right_noad) t=open_noad;
+  r_type=t;
+  delete_q: r=q;q=link(q);free_node(r, s);
+  done: ;}
+
+@ Just before doing the big |case| switch in the second pass, the program
+sets up default values so that most of the branches are short.
+
+@<If node |q| is a style node, change the style...@>=
+t=ord_noad;s=noad_size;pen=inf_penalty;
+switch (type(q)) {
+case op_noad: case open_noad: case close_noad: case punct_noad: case inner_noad: t=type(q);@+break;
+case bin_noad: {@+t=bin_noad;pen=bin_op_penalty;
+  } @+break;
+case rel_noad: {@+t=rel_noad;pen=rel_penalty;
+  } @+break;
+case ord_noad: case vcenter_noad: case over_noad: case under_noad: do_nothing;@+break;
+case radical_noad: s=radical_noad_size;@+break;
+case accent_noad: s=accent_noad_size;@+break;
+case fraction_noad: s=fraction_noad_size;@+break;
+case left_noad: case right_noad: t=make_left_right(q, style, max_d, max_h);@+break;
+case style_node: @<Change the current style and |goto delete_q|@>@;
+case whatsit_node: case penalty_node: case rule_node: case disc_node: case adjust_node: case ins_node: case mark_node:
+ case glue_node: case kern_node: @t@>@;@/
+  {@+link(p)=q;p=q;q=link(q);link(p)=null;goto done;
+  }
+default:confusion("mlist3");
+@:this can't happen mlist3}{\quad mlist3@>
+}
+
+@ The |make_left_right| function constructs a left or right delimiter of
+the required size and returns the value |open_noad| or |close_noad|. The
+|right_noad| and |left_noad| will both be based on the original |style|,
+so they will have consistent sizes.
+
+We use the fact that |right_noad-left_noad==close_noad-open_noad|.
+
+@<Declare math...@>=
+static small_number make_left_right(pointer @!q, small_number @!style,
+  scaled @!max_d, scaled @!max_h)
+{@+scaled delta, @!delta1, @!delta2; /*dimensions used in the calculation*/
+cur_style=style;@<Set up the values...@>;
+delta2=max_d+axis_height(cur_size);
+delta1=max_h+max_d-delta2;
+if (delta2 > delta1) delta1=delta2; /*|delta1| is max distance from axis*/
+delta=(delta1/500)*delimiter_factor;
+delta2=delta1+delta1-delimiter_shortfall;
+if (delta < delta2) delta=delta2;
+new_hlist(q)=var_delimiter(delimiter(q), cur_size, delta);
+return type(q)-(left_noad-open_noad); /*|open_noad| or |close_noad|*/
+}
+
+@ @<Change the current style and |goto delete_q|@>=
+{@+cur_style=subtype(q);s=style_node_size;
+@<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>;
+goto delete_q;
+}
+
+@ The inter-element spacing in math formulas depends on an $8\times8$ table that
+\TeX\ preloads as a 64-digit string. The elements of this string have the
+following significance:
+$$\vbox{\halign{#\hfil\cr
+\.0 means no space;\cr
+\.1 means a conditional thin space (\.{\\nonscript\\mskip\\thinmuskip});\cr
+\.2 means a thin space (\.{\\mskip\\thinmuskip});\cr
+\.3 means a conditional medium space
+  (\.{\\nonscript\\mskip\\medmuskip});\cr
+\.4 means a conditional thick space
+  (\.{\\nonscript\\mskip\\thickmuskip});\cr
+\.* means an impossible case.\cr}}$$
+This is all pretty cryptic, but {\sl The \TeX book\/} explains what is
+supposed to happen, and the string makes it happen.
+@:TeXbook}{\sl The \TeX book@>
+
+A global variable |magic_offset| is computed so that if |a| and |b| are
+in the range |ord_noad dotdot inner_noad|, then |str_pool[a*8+b+magic_offset]|
+is the digit for spacing between noad types |a| and |b|.
+
+If \PASCAL\ had provided a good way to preload constant arrays, this part of
+the program would not have been so strange.
+@:PASCAL}{\PASCAL@>
+
+ at d math_spacing @;@/
+ at t\hskip-35pt@>
+"0234000122*4000133**3**344*0400400*000000234000111*1111112341011"
+ at t$ \hskip-35pt$@>
+
+@ @<Glob...@>=
+static const int @!magic_offset=-9*ord_noad; /*used to find inter-element spacing*/
+
+@ @<Append inter-element spacing based on |r_type| and |t|@>=
+if (r_type > 0)  /*not the first noad*/
+  {@+switch (so(math_spacing[r_type*8+t+magic_offset])) {
+  case '0': x=0;@+break;
+  case '1': if (cur_style < script_style) x=thin_mu_skip_code;@+else x=0;@+break;
+  case '2': x=thin_mu_skip_code;@+break;
+  case '3': if (cur_style < script_style) x=med_mu_skip_code;@+else x=0;@+break;
+  case '4': if (cur_style < script_style) x=thick_mu_skip_code;@+else x=0;@+break;
+  default:confusion("mlist4");
+@:this can't happen mlist4}{\quad mlist4@>
+  }
+  if (x!=0)
+    {@+y=math_glue(glue_par(x), cur_mu);
+    z=new_glue(y);glue_ref_count(y)=null;link(p)=z;p=z;@/
+    subtype(z)=x+1; /*store a symbolic subtype*/
+    }
+  }
+
+@ We insert a penalty node after the hlist entries of noad |q| if |pen|
+is not an ``infinite'' penalty, and if the node immediately following |q|
+is not a penalty node or a |rel_noad| or absent entirely.
+
+@<Append any |new_hlist| entries for |q|, and any appropriate penalties@>=
+if (new_hlist(q)!=null)
+  {@+link(p)=new_hlist(q);
+  @/do at +{p=link(p);
+  }@+ while (!(link(p)==null));
+  }
+if (penalties) if (link(q)!=null) if (pen < inf_penalty)
+  {@+r_type=type(link(q));
+  if (r_type!=penalty_node) if (r_type!=rel_noad)
+    {@+z=new_penalty(pen);link(p)=z;p=z;
+    }
+  }
+
+@* Alignment.
+It's sort of a miracle whenever \.{\\halign} and \.{\\valign} work, because
+they cut across so many of the control structures of \TeX.
+
+Therefore the
+present page is probably not the best place for a beginner to start reading
+this program; it is better to master everything else first.
+
+Let us focus our thoughts on an example of what the input might be, in order
+to get some idea about how the alignment miracle happens. The example doesn't
+do anything useful, but it is sufficiently general to indicate all of the
+special cases that must be dealt with; please do not be disturbed by its
+apparent complexity and meaninglessness.
+$$\vbox{\halign{\.{#}\hfil\cr
+{}\\tabskip 2pt plus 3pt\cr
+{}\\halign to 300pt\{u1\#v1\&\cr
+\hskip 50pt\\tabskip 1pt plus 1fil u2\#v2\&\cr
+\hskip 50pt u3\#v3\\cr\cr
+\hskip 25pt a1\&\\omit a2\&\\vrule\\cr\cr
+\hskip 25pt \\noalign\{\\vskip 3pt\}\cr
+\hskip 25pt b1\\span b2\\cr\cr
+\hskip 25pt \\omit\&c2\\span\\omit\\cr\}\cr}}$$
+Here's what happens:
+
+\yskip
+(0) When `\.{\\halign to 300pt\{}' is scanned, the |scan_spec| routine
+places the 300pt dimension onto the |save_stack|, and an |align_group|
+code is placed above it. This will make it possible to complete the alignment
+when the matching `\.\}' is found.
+
+(1) The preamble is scanned next. Macros in the preamble are not expanded,
+@^preamble@>
+except as part of a tabskip specification. For example, if \.{u2} had been
+a macro in the preamble above, it would have been expanded, since \TeX\
+must look for `\.{minus...}' as part of the tabskip glue. A ``preamble list''
+is constructed based on the user's preamble; in our case it contains the
+following seven items:
+$$\vbox{\halign{\.{#}\hfil\qquad&(#)\hfil\cr
+{}\\glue 2pt plus 3pt&the tabskip preceding column 1\cr
+{}\\alignrecord, width $-\infty$&preamble info for column 1\cr
+{}\\glue 2pt plus 3pt&the tabskip between columns 1 and 2\cr
+{}\\alignrecord, width $-\infty$&preamble info for column 2\cr
+{}\\glue 1pt plus 1fil&the tabskip between columns 2 and 3\cr
+{}\\alignrecord, width $-\infty$&preamble info for column 3\cr
+{}\\glue 1pt plus 1fil&the tabskip following column 3\cr}}$$
+These ``alignrecord'' entries have the same size as an |unset_node|,
+since they will later be converted into such nodes. However, at the
+moment they have no |type| or |subtype| fields; they have |info| fields
+instead, and these |info| fields are initially set to the value |end_span|,
+for reasons explained below. Furthermore, the alignrecord nodes have no
+|height| or |depth| fields; these are renamed |u_part| and |v_part|,
+and they point to token lists for the templates of the alignment.
+For example, the |u_part| field in the first alignrecord points to the
+token list `\.{u1}', i.e., the template preceding the `\.\#' for column~1.
+
+(2) \TeX\ now looks at what follows the \.{\\cr} that ended the preamble.
+It is not `\.{\\noalign}' or `\.{\\omit}', so this input is put back to
+be read again, and the template `\.{u1}' is fed to the scanner. Just
+before reading `\.{u1}', \TeX\ goes into restricted horizontal mode.
+Just after reading `\.{u1}', \TeX\ will see `\.{a1}', and then (when the
+{\.\&} is sensed) \TeX\ will see `\.{v1}'. Then \TeX\ scans an |endv|
+token, indicating the end of a column. At this point an |unset_node| is
+created, containing the contents of the current hlist (i.e., `\.{u1a1v1}').
+The natural width of this unset node replaces the |width| field of the
+alignrecord for column~1; in general, the alignrecords will record the
+maximum natural width that has occurred so far in a given column.
+
+(3) Since `\.{\\omit}' follows the `\.\&', the templates for column~2
+are now bypassed. Again \TeX\ goes into restricted horizontal mode and
+makes an |unset_node| from the resulting hlist; but this time the
+hlist contains simply `\.{a2}'. The natural width of the new unset box
+is remembered in the |width| field of the alignrecord for column~2.
+
+(4) A third |unset_node| is created for column 3, using essentially the
+mechanism that worked for column~1; this unset box contains `\.{u3\\vrule
+v3}'. The vertical rule in this case has running dimensions that will later
+extend to the height and depth of the whole first row, since each |unset_node|
+in a row will eventually inherit the height and depth of its enclosing box.
+
+(5) The first row has now ended; it is made into a single unset box
+comprising the following seven items:
+$$\vbox{\halign{\hbox to 325pt{\qquad\.{#}\hfil}\cr
+{}\\glue 2pt plus 3pt\cr
+{}\\unsetbox for 1 column: u1a1v1\cr
+{}\\glue 2pt plus 3pt\cr
+{}\\unsetbox for 1 column: a2\cr
+{}\\glue 1pt plus 1fil\cr
+{}\\unsetbox for 1 column: u3\\vrule v3\cr
+{}\\glue 1pt plus 1fil\cr}}$$
+The width of this unset row is unimportant, but it has the correct height
+and depth, so the correct baselineskip glue will be computed as the row
+is inserted into a vertical list.
+
+(6) Since `\.{\\noalign}' follows the current \.{\\cr}, \TeX\ appends
+additional material (in this case \.{\\vskip 3pt}) to the vertical list.
+While processing this material, \TeX\ will be in internal vertical
+mode, and |no_align_group| will be on |save_stack|.
+
+(7) The next row produces an unset box that looks like this:
+$$\vbox{\halign{\hbox to 325pt{\qquad\.{#}\hfil}\cr
+{}\\glue 2pt plus 3pt\cr
+{}\\unsetbox for 2 columns: u1b1v1u2b2v2\cr
+{}\\glue 1pt plus 1fil\cr
+{}\\unsetbox for 1 column: {\rm(empty)}\cr
+{}\\glue 1pt plus 1fil\cr}}$$
+The natural width of the unset box that spans columns 1~and~2 is stored
+in a ``span node,'' which we will explain later; the |info| field of the
+alignrecord for column~1 now points to the new span node, and the |info|
+of the span node points to |end_span|.
+
+(8) The final row produces the unset box
+$$\vbox{\halign{\hbox to 325pt{\qquad\.{#}\hfil}\cr
+{}\\glue 2pt plus 3pt\cr
+{}\\unsetbox for 1 column: {\rm(empty)}\cr
+{}\\glue 2pt plus 3pt\cr
+{}\\unsetbox for 2 columns: u2c2v2\cr
+{}\\glue 1pt plus 1fil\cr}}$$
+A new span node is attached to the alignrecord for column 2.
+
+(9) The last step is to compute the true column widths and to change all the
+unset boxes to hboxes, appending the whole works to the vertical list that
+encloses the \.{\\halign}. The rules for deciding on the final widths of
+each unset column box will be explained below.
+
+\yskip\noindent
+Note that as \.{\\halign} is being processed, we fearlessly give up control
+to the rest of \TeX. At critical junctures, an alignment routine is
+called upon to step in and do some little action, but most of the time
+these routines just lurk in the background. It's something like
+post-hypnotic suggestion.
+
+@ We have mentioned that alignrecords contain no |height| or |depth| fields.
+Their |glue_sign| and |glue_order| are pre-empted as well, since it
+is necessary to store information about what to do when a template ends.
+This information is called the |extra_info| field.
+
+ at d u_part(A) mem[A+height_offset].i /*pointer to \<u_j> token list*/
+ at d v_part(A) mem[A+depth_offset].i /*pointer to \<v_j> token list*/
+ at d extra_info(A) info(A+list_offset) /*info to remember during template*/
+
+@ Alignments can occur within alignments, so a small stack is used to access
+the alignrecord information. At each level we have a |preamble| pointer,
+indicating the beginning of the preamble list; a |cur_align| pointer,
+indicating the current position in the preamble list; a |cur_span| pointer,
+indicating the value of |cur_align| at the beginning of a sequence of
+spanned columns; a |cur_loop| pointer, indicating the tabskip glue before
+an alignrecord that should be copied next if the current list is extended;
+and the |align_state| variable, which indicates the nesting of braces so
+that \.{\\cr} and \.{\\span} and tab marks are properly intercepted.
+There also are pointers |cur_head| and |cur_tail| to the head and tail
+of a list of adjustments being moved out from horizontal mode to
+vertical~mode.
+
+The current values of these seven quantities appear in global variables;
+when they have to be pushed down, they are stored in 5-word nodes, and
+|align_ptr| points to the topmost such node.
+
+ at d preamble link(align_head) /*the current preamble list*/
+ at d align_stack_node_size 5 /*number of |mem| words to save alignment states*/
+
+@<Glob...@>=
+static pointer @!cur_align; /*current position in preamble list*/
+static pointer @!cur_span; /*start of currently spanned columns in preamble list*/
+static pointer @!cur_loop; /*place to copy when extending a periodic preamble*/
+static pointer @!align_ptr; /*most recently pushed-down alignment stack node*/
+static pointer @!cur_head, @!cur_tail; /*adjustment list pointers*/
+
+@ The |align_state| and |preamble| variables are initialized elsewhere.
+
+@<Set init...@>=
+align_ptr=null;cur_align=null;cur_span=null;cur_loop=null;
+cur_head=null;cur_tail=null;
+
+@ Alignment stack maintenance is handled by a pair of trivial routines
+called |push_alignment| and |pop_alignment|.
+
+ at p static void push_alignment(void)
+{@+pointer p; /*the new alignment stack node*/
+p=get_node(align_stack_node_size);
+link(p)=align_ptr;info(p)=cur_align;
+llink(p)=preamble;rlink(p)=cur_span;
+mem[p+2].i=cur_loop;mem[p+3].i=align_state;
+info(p+4)=cur_head;link(p+4)=cur_tail;
+align_ptr=p;
+cur_head=get_avail();
+}
+@#
+static void pop_alignment(void)
+{@+pointer p; /*the top alignment stack node*/
+free_avail(cur_head);
+p=align_ptr;
+cur_tail=link(p+4);cur_head=info(p+4);
+align_state=mem[p+3].i;cur_loop=mem[p+2].i;
+cur_span=rlink(p);preamble=llink(p);
+cur_align=info(p);align_ptr=link(p);
+free_node(p, align_stack_node_size);
+}
+
+@ \TeX\ has eight procedures that govern alignments: |init_align| and
+|fin_align| are used at the very beginning and the very end; |init_row| and
+|fin_row| are used at the beginning and end of individual rows; |init_span|
+is used at the beginning of a sequence of spanned columns (possibly involving
+only one column); |init_col| and |fin_col| are used at the beginning and
+end of individual columns; and |align_peek| is used after \.{\\cr} to see
+whether the next item is \.{\\noalign}.
+
+We shall consider these routines in the order they are first used during
+the course of a complete \.{\\halign}, namely |init_align|, |align_peek|,
+|init_row|, |init_span|, |init_col|, |fin_col|, |fin_row|, |fin_align|.
+
+@ When \.{\\halign} or \.{\\valign} has been scanned in an appropriate
+mode, \TeX\ calls |init_align|, whose task is to get everything off to a
+good start. This mostly involves scanning the preamble and putting its
+information into the preamble list.
+@^preamble@>
+
+ at p @t\4@>@<Declare the procedure called |get_preamble_token|@>@t@>@/
+static void align_peek(void);@/
+static void normal_paragraph(void);@/
+static void init_align(void)
+{@+
+pointer save_cs_ptr; /*|warning_index| value for error messages*/
+pointer @!p; /*for short-term temporary use*/
+save_cs_ptr=cur_cs; /*\.{\\halign} or \.{\\valign}, usually*/
+push_alignment();align_state=-1000000; /*enter a new alignment level*/
+@<Check for improper alignment in displayed math@>;
+push_nest(); /*enter a new semantic level*/
+@<Change current mode to |-vmode| for \.{\\halign}, |-hmode| for \.{\\valign}@>;
+scan_spec(align_group, false);@/
+@<Scan the preamble and record it in the |preamble| list@>;
+new_save_level(align_group);
+if (every_cr!=null) begin_token_list(every_cr, every_cr_text);
+align_peek(); /*look for \.{\\noalign} or \.{\\omit}*/
+}
+
+@ In vertical modes, |prev_depth| already has the correct value. But
+if we are in |mmode| (displayed formula mode), we reach out to the
+enclosing vertical mode for the |prev_depth| value that produces the
+correct baseline calculations.
+
+@<Change current mode...@>=
+if (mode==mmode)
+  {@+mode=-vmode;prev_depth=nest[nest_ptr-2].aux_field.sc;
+  }
+else if (mode > 0) negate(mode)
+
+@ When \.{\\halign} is used as a displayed formula, there should be
+no other pieces of mlists present.
+
+@<Check for improper alignment in displayed math@>=
+if ((mode==mmode)&&((tail!=head)||(incompleat_noad!=null)))
+  {@+print_err("Improper ");print_esc("halign");print(" inside $$'s");
+ at .Improper \\halign...@>
+  help3("Displays can use special alignments (like \\eqalignno)",@/
+  "only if nothing but the alignment itself is between $$'s.",@/
+  "So I've deleted the formulas that preceded this alignment.");
+  error();flush_math();
+  }
+
+@ @<Scan the preamble and record it in the |preamble| list@>=
+preamble=null;cur_align=align_head;cur_loop=null;scanner_status=aligning;
+warning_index=save_cs_ptr;align_state=-1000000;
+   /*at this point, |cur_cmd==left_brace|*/
+loop at +{@+@<Append the current tabskip glue to the preamble list@>;
+  if (cur_cmd==car_ret) goto done; /*\.{\\cr} ends the preamble*/
+  @<Scan preamble text until |cur_cmd| is |tab_mark| or |car_ret|, looking for changes
+in the tabskip glue; append an alignrecord to the preamble list@>;
+  }
+done: scanner_status=normal
+
+@ @<Append the current tabskip glue to the preamble list@>=
+link(cur_align)=new_param_glue(tab_skip_code);
+cur_align=link(cur_align)
+
+@ @<Scan preamble text until |cur_cmd| is |tab_mark| or |car_ret|...@>=
+@<Scan the template \<u_j>, putting the resulting token list in |hold_head|@>;
+link(cur_align)=new_null_box();cur_align=link(cur_align); /*a new alignrecord*/
+info(cur_align)=end_span;width(cur_align)=null_flag;
+u_part(cur_align)=link(hold_head);
+@<Scan the template \<v_j>, putting the resulting token list in |hold_head|@>;
+v_part(cur_align)=link(hold_head)
+
+@ We enter `\.{\\span}' into |eqtb| with |tab_mark| as its command code,
+and with |span_code| as the command modifier. This makes \TeX\ interpret it
+essentially the same as an alignment delimiter like `\.\&', yet it is
+recognizably different when we need to distinguish it from a normal delimiter.
+It also turns out to be useful to give a special |cr_code| to `\.{\\cr}',
+and an even larger |cr_cr_code| to `\.{\\crcr}'.
+
+The end of a template is represented by two ``frozen'' control sequences
+called \.{\\endtemplate}. The first has the command code |end_template|, which
+is | > outer_call|, so it will not easily disappear in the presence of errors.
+The |get_x_token| routine converts the first into the second, which has |endv|
+as its command code.
+
+ at d span_code 256 /*distinct from any character*/
+ at d cr_code 257 /*distinct from |span_code| and from any character*/
+ at d cr_cr_code (cr_code+1) /*this distinguishes \.{\\crcr} from \.{\\cr}*/
+ at d end_template_token cs_token_flag+frozen_end_template
+
+@<Put each of \TeX's primitives into the hash table@>=
+primitive("span", tab_mark, span_code);@/
+@!@:span\_}{\.{\\span} primitive@>
+primitive("cr", car_ret, cr_code);
+@!@:cr\_}{\.{\\cr} primitive@>
+text(frozen_cr)=text(cur_val);eqtb[frozen_cr]=eqtb[cur_val];@/
+primitive("crcr", car_ret, cr_cr_code);
+@!@:cr\_cr\_}{\.{\\crcr} primitive@>
+text(frozen_end_template)=text(frozen_endv)=s_no("endtemplate");
+ at .endtemplate@>
+eq_type(frozen_endv)=endv;equiv(frozen_endv)=null_list;
+eq_level(frozen_endv)=level_one;@/
+eqtb[frozen_end_template]=eqtb[frozen_endv];
+eq_type(frozen_end_template)=end_template;
+
+@ @<Cases of |print_cmd_chr|...@>=
+case tab_mark: if (chr_code==span_code) print_esc("span");
+  else chr_cmd("alignment tab character ")@;@+break;
+case car_ret: if (chr_code==cr_code) print_esc("cr");
+  else print_esc("crcr");@+break;
+
+@ The preamble is copied directly, except that \.{\\tabskip} causes a change
+to the tabskip glue, thereby possibly expanding macros that immediately
+follow it. An appearance of \.{\\span} also causes such an expansion.
+
+Note that if the preamble contains `\.{\\global\\tabskip}', the `\.{\\global}'
+token survives in the preamble and the `\.{\\tabskip}' defines new
+tabskip glue (locally).
+
+@<Declare the procedure called |get_preamble_token|@>=
+static void get_preamble_token(void)
+{@+
+restart: get_token();
+while ((cur_chr==span_code)&&(cur_cmd==tab_mark))
+  {@+get_token(); /*this token will be expanded once*/
+  if (cur_cmd > max_command)
+    {@+expand();get_token();
+    }
+  }
+if (cur_cmd==endv)
+  fatal_error("(interwoven alignment preambles are not allowed)");
+ at .interwoven alignment preambles...@>
+if ((cur_cmd==assign_glue)&&(cur_chr==glue_base+tab_skip_code))
+  {@+scan_optional_equals();scan_glue(glue_val);
+  if (global_defs > 0) geq_define(glue_base+tab_skip_code, glue_ref, cur_val);
+  else eq_define(glue_base+tab_skip_code, glue_ref, cur_val);
+  goto restart;
+  }
+}
+
+@ Spaces are eliminated from the beginning of a template.
+
+@<Scan the template \<u_j>...@>=
+p=hold_head;link(p)=null;
+loop at +{@+get_preamble_token();
+  if (cur_cmd==mac_param) goto done1;
+  if ((cur_cmd <= car_ret)&&(cur_cmd >= tab_mark)&&(align_state==-1000000))
+   if ((p==hold_head)&&(cur_loop==null)&&(cur_cmd==tab_mark)
+    ) cur_loop=cur_align;
+   else{@+print_err("Missing # inserted in alignment preamble");
+ at .Missing \# inserted...@>
+    help3("There should be exactly one # between &'s, when an",@/
+    "\\halign or \\valign is being set up. In this case you had",@/
+    "none, so I've put one in; maybe that will work.");
+    back_error();goto done1;
+    }
+  else if ((cur_cmd!=spacer)||(p!=hold_head))
+    {@+link(p)=get_avail();p=link(p);info(p)=cur_tok;
+    }
+  }
+done1:
+
+@ @<Scan the template \<v_j>...@>=
+p=hold_head;link(p)=null;
+loop at +{@+resume: get_preamble_token();
+  if ((cur_cmd <= car_ret)&&(cur_cmd >= tab_mark)&&(align_state==-1000000))
+    goto done2;
+  if (cur_cmd==mac_param)
+    {@+print_err("Only one # is allowed per tab");
+ at .Only one \# is allowed...@>
+    help3("There should be exactly one # between &'s, when an",@/
+    "\\halign or \\valign is being set up. In this case you had",@/
+    "more than one, so I'm ignoring all but the first.");
+    error();goto resume;
+    }
+  link(p)=get_avail();p=link(p);info(p)=cur_tok;
+  }
+done2: link(p)=get_avail();p=link(p);
+info(p)=end_template_token /*put \.{\\endtemplate} at the end*/
+
+@ The tricky part about alignments is getting the templates into the
+scanner at the right time, and recovering control when a row or column
+is finished.
+
+We usually begin a row after each \.{\\cr} has been sensed, unless that
+\.{\\cr} is followed by \.{\\noalign} or by the right brace that terminates
+the alignment. The |align_peek| routine is used to look ahead and do
+the right thing; it either gets a new row started, or gets a \.{\\noalign}
+started, or finishes off the alignment.
+
+@<Declare the procedure called |align_peek|@>=
+static void align_peek(void)
+{@+
+restart: align_state=1000000;
+@/do at +{get_x_or_protected();
+}@+ while (!(cur_cmd!=spacer));
+if (cur_cmd==no_align)
+  {@+scan_left_brace();new_save_level(no_align_group);
+  if (mode==-vmode) normal_paragraph();
+  }
+else if (cur_cmd==right_brace) fin_align();
+else if ((cur_cmd==car_ret)&&(cur_chr==cr_cr_code))
+  goto restart; /*ignore \.{\\crcr}*/
+else{@+init_row(); /*start a new row*/
+  init_col(); /*start a new column and replace what we peeked at*/
+  }
+}
+
+@ To start a row (i.e., a `row' that rhymes with `dough' but not with `bough'),
+we enter a new semantic level, copy the first tabskip glue, and change
+from internal vertical mode to restricted horizontal mode or vice versa.
+The |space_factor| and |prev_depth| are not used on this semantic level,
+but we clear them to zero just to be tidy.
+
+ at p @t\4@>@<Declare the procedure called |init_span|@>@t@>@/
+static void init_row(void)
+{@+push_nest();mode=(-hmode-vmode)-mode;
+if (mode==-hmode) space_factor=0;@+else prev_depth=0;
+tail_append(new_glue(glue_ptr(preamble)));
+subtype(tail)=tab_skip_code+1;@/
+cur_align=link(preamble);cur_tail=cur_head;init_span(cur_align);
+}
+
+@ The parameter to |init_span| is a pointer to the alignrecord where the
+next column or group of columns will begin. A new semantic level is
+entered, so that the columns will generate a list for subsequent packaging.
+
+@<Declare the procedure called |init_span|@>=
+static void init_span(pointer @!p)
+{@+push_nest();
+if (mode==-hmode) space_factor=1000;
+else{@+prev_depth=ignore_depth;normal_paragraph();
+  }
+cur_span=p;
+}
+
+@ When a column begins, we assume that |cur_cmd| is either |omit| or else
+the current token should be put back into the input until the \<u_j>
+template has been scanned.  (Note that |cur_cmd| might be |tab_mark| or
+|car_ret|.)  We also assume that |align_state| is approximately 1000000 at
+this time.  We remain in the same mode, and start the template if it is
+called for.
+
+ at p static void init_col(void)
+{@+extra_info(cur_align)=cur_cmd;
+if (cur_cmd==omit) align_state=0;
+else{@+back_input();begin_token_list(u_part(cur_align), u_template);
+  }  /*now |align_state==1000000|*/
+}
+
+@ The scanner sets |align_state| to zero when the \<u_j> template ends. When
+a subsequent \.{\\cr} or \.{\\span} or tab mark occurs with |align_state==0|,
+the scanner activates the following code, which fires up the \<v_j> template.
+We need to remember the |cur_chr|, which is either |cr_cr_code|, |cr_code|,
+|span_code|, or a character code, depending on how the column text has ended.
+
+This part of the program had better not be activated when the preamble
+to another alignment is being scanned, or when no alignment preamble is active.
+
+@<Insert the \(v)\<v_j>...@>=
+{@+if ((scanner_status==aligning)||(cur_align==null))
+  fatal_error("(interwoven alignment preambles are not allowed)");
+ at .interwoven alignment preambles...@>
+cur_cmd=extra_info(cur_align);extra_info(cur_align)=cur_chr;
+if (cur_cmd==omit) begin_token_list(omit_template, v_template);
+else begin_token_list(v_part(cur_align), v_template);
+align_state=1000000;goto restart;
+}
+
+@ The token list |omit_template| just referred to is a constant token
+list that contains the special control sequence \.{\\endtemplate} only.
+
+@<Initialize the special...@>=
+info(omit_template)=end_template_token; /*|link(omit_template)==null|*/
+
+@ When the |endv| command at the end of a \<v_j> template comes through the
+scanner, things really start to happen; and it is the |fin_col| routine
+that makes them happen. This routine returns |true| if a row as well as a
+column has been finished.
+
+ at p static bool fin_col(void)
+{@+
+pointer p; /*the alignrecord after the current one*/
+pointer @!q, @!r; /*temporary pointers for list manipulation*/
+pointer @!s; /*a new span node*/
+pointer @!u; /*a new unset box*/
+scaled @!w; /*natural width*/
+glue_ord @!o; /*order of infinity*/
+halfword @!n; /*span counter*/
+if (cur_align==null) confusion("endv");
+q=link(cur_align);@+if (q==null) confusion("endv");
+@:this can't happen endv}{\quad endv@>
+if (align_state < 500000)
+  fatal_error("(interwoven alignment preambles are not allowed)");
+ at .interwoven alignment preambles...@>
+p=link(q);
+@<If the preamble list has been traversed, check that the row has ended@>;
+if (extra_info(cur_align)!=span_code)
+  {@+unsave();new_save_level(align_group);@/
+  @<Package an unset box for the current column and record its width@>;
+  @<Copy the tabskip glue between columns@>;
+  if (extra_info(cur_align) >= cr_code)
+    {@+return true;
+    }
+  init_span(p);
+  }
+align_state=1000000;
+@/do at +{get_x_or_protected();
+}@+ while (!(cur_cmd!=spacer));
+cur_align=p;
+init_col();return false;
+}
+
+@ @<If the preamble list has been traversed, check that the row has ended@>=
+if ((p==null)&&(extra_info(cur_align) < cr_code))
+ if (cur_loop!=null) @<Lengthen the preamble periodically@>@;
+ else{@+print_err("Extra alignment tab has been changed to ");
+ at .Extra alignment tab...@>
+  print_esc("cr");
+  help3("You have given more \\span or & marks than there were",@/
+  "in the preamble to the \\halign or \\valign now in progress.",@/
+  "So I'll assume that you meant to type \\cr instead.");
+  extra_info(cur_align)=cr_code;error();
+  }
+
+@ @<Lengthen the preamble...@>=
+{@+link(q)=new_null_box();p=link(q); /*a new alignrecord*/
+info(p)=end_span;width(p)=null_flag;cur_loop=link(cur_loop);
+@<Copy the templates from node |cur_loop| into node |p|@>;
+cur_loop=link(cur_loop);
+link(p)=new_glue(glue_ptr(cur_loop));
+subtype(link(p))=tab_skip_code+1;
+}
+
+@ @<Copy the templates from node |cur_loop| into node |p|@>=
+q=hold_head;r=u_part(cur_loop);
+while (r!=null)
+  {@+link(q)=get_avail();q=link(q);info(q)=info(r);r=link(r);
+  }
+link(q)=null;u_part(p)=link(hold_head);
+q=hold_head;r=v_part(cur_loop);
+while (r!=null)
+  {@+link(q)=get_avail();q=link(q);info(q)=info(r);r=link(r);
+  }
+link(q)=null;v_part(p)=link(hold_head)
+
+@ @<Copy the tabskip glue...@>=
+tail_append(new_glue(glue_ptr(link(cur_align))));
+subtype(tail)=tab_skip_code+1
+
+@ @<Package an unset...@>=
+{@+if (mode==-hmode)
+  {@+adjust_tail=cur_tail;u=hpack(link(head), natural);
+  if (type(u)==hlist_node) w=width(u);
+  else w=max_dimen+1;
+  cur_tail=adjust_tail;adjust_tail=null;
+  }
+else{@+u=vpackage(link(head), natural, 0);
+  if (type(u)==vlist_node) w=height(u);
+  else w=max_dimen+1;
+  }
+n=min_quarterword; /*this represents a span count of 1*/
+if (cur_span!=cur_align) @<Update width entry for spanned columns@>@;
+else if (w > width(cur_align)) width(cur_align)=w;
+if (type(u)==whatsit_node)
+{ if (subtype(u)==hset_node ||subtype(u)==vset_node) type(u)=unset_set_node;
+  else type(u)=unset_pack_node;
+  span_count(u)=n;
+}
+else if (type(u)==hlist_node ||type(u)==vlist_node)
+{ type(u)=unset_node;span_count(u)=n;
+@<Determine the stretch order@>;
+glue_order(u)=o;glue_stretch(u)=total_stretch[o];@/
+@<Determine the shrink order@>;
+glue_sign(u)=o;glue_shrink(u)=total_shrink[o];@/
+}
+pop_nest();link(tail)=u;tail=u;
+}
+
+@ A span node is a 2-word record containing |width|, |info|, and |link|
+fields. The |link| field is not really a link, it indicates the number of
+spanned columns; the |info| field points to a span node for the same
+starting column, having a greater extent of spanning, or to |end_span|,
+which has the largest possible |link| field; the |width| field holds the
+largest natural width corresponding to a particular set of spanned columns.
+
+A list of the maximum widths so far, for spanned columns starting at a
+given column, begins with the |info| field of the alignrecord for that
+column.
+
+ at d span_node_size 2 /*number of |mem| words for a span node*/
+
+@<Initialize the special list heads...@>=
+link(end_span)=max_quarterword+1;info(end_span)=null;
+
+@ @<Update width entry for spanned columns@>=
+{@+q=cur_span;
+@/do at +{incr(n);q=link(link(q));
+}@+ while (!(q==cur_align));
+if (n > max_quarterword) confusion("256 spans"); /*this can happen, but won't*/
+@^system dependencies@>

@@ Diff output truncated at 1234567 characters. @@


More information about the tex-live-commits mailing list.