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.