§1 BibTEX INTRODUCTION 1

1* . Introduction. BibTEX is a preprocessor (with elements of postprocessing as explained below) for the LaTEX document-preparation system. It handles most of the formatting decisions required to produce a reference list, outputting a file that a user can edit to add any finishing touches BibTEX isn’t designed to handle (in practice, such editing almost never is needed); with this file LaTEX actually produces the reference list.

Here’s how BibTEX works. It takes as input (a) an file produced by LaTEX on an earlier run;

(b) a file (the style file), which specifies the general reference-list style and specifies how to format individual entries, and which is written by a style designer (called a wizard throughout this program) in a special-purpose language described in the BibTEX documentation—see the file ; and (c) file(s) constituting a database of all reference-list entries the user might ever hope to use. BibTEX chooses from the file(s) only those entries specified by the file (that is, those given by LaTEX’s or commands), and creates as output a file containing these entries together with the formatting commands specified by the file (BibTEX also creates a log file, which includes any error or warning messages, but this file isn’t used by any program). LaTEX will use the file, perhaps edited by the user, to produce the reference list.

Many modules of BibTEX were taken from Knuth’s TEX and TEXware, with his permission. All known system-dependent modules are marked in the index entry “system dependencies”; Dave Fuchs helped exorcise unwanted ones. In addition, a few modules that can be changed to make BibTEX smaller are marked in the index entry “space savings”.

Megathanks to Howard Trickey, for whose suggestions future users and style writers would be eternally grateful, if only they knew.

The banner string defined here should be changed whenever BibTEX gets modified.

define banner ≡ ´ ␣  ␣       ␣ ␣       ␣  ´  { printed when the program starts }

2* . Terminal output goes to the file term out , while terminal input comes from term in. On our system, these (system-dependent) files are already opened at the beginning of the program, and have the same real name.

define term out ≡ standard output

define term in ≡ standard input

2  INTRODUCTION  BibTEX §3

3. This program uses the term print instead of write when writing on both the log file and (systemdependent) term out file, and it uses trace pr when in trace mode, for which it writes on just the log file. If you want to change where either set of macros writes to, you should also change the other macros in this program for that set; each such macro begins with print or trace pr .

define print (#) ≡ begin write(log file, #); write(term out , #); end

define print ln(#) ≡ begin write ln(log file, #); write ln(term out , #); end

define print newline ≡ print a newline { making this a procedure saves a little space } define trace pr (#) ≡

begin write(log file, #);

end

define trace pr ln(#) ≡ begin write ln(log file, #); end

define trace pr newline ≡ begin write ln(log file); end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ ≡ procedure print a newline;

begin write ln(log file); write ln(term out ); end;

See also sections 18, 45, 46, 47, 48*, 52, 54, 60, 83, 96, 97, 99, 100, 109, 112, 113, 114, 115, 116, 122, 129, 138, 139, 145, 149, 150, 151, 154, 158, 159, 160, 166, 167, 168, 169, 170, 189, 221, 222, 223, 227, 230, 231, 232, 233, 234, 235, 236, 241, 272, 281, 282, 285, 294, 295, 296, 311, 312, 314, 322, 357, 369, 374, and 457.

This code is used in section 12.

4* . Some of the code below is intended to be used only when diagnosing the strange behavior that sometimes occurs when BibTEX is being installed or when system wizards are fooling around with BibTEX without quite knowing what they are doing. Such code will not normally be compiled; it is delimited by the codewords ‘debug … gubed’, with apologies to people who wish to preserve the purity of English. Similarly, there is some conditional code delimited by ‘stat … tats’ that is intended only for use when statistics are to be kept about BibTEX’s memory/cpu usage, and there is conditional code delimited by ‘trace … ecart’ that is intended to be a trace facility for use mainly when debugging files.

define debug ≡ ifdef (´ ´ ) define gubed ≡ endif (´ ´ ) format debug ≡ begin format gubed ≡ end define stat ≡ ifdef (´ ´ ) define tats ≡ endif (´ ´ ) format stat ≡ begin format tats ≡ end define trace ≡ ifdef (´ ´ ) define ecart ≡ endif (´ ´ ) format trace ≡ begin format ecart ≡ end 5. We assume that case statements may include a default case that applies if no matching label is found, since most PASCAL compilers have plugged this hole in the language by incorporating some sort of default mechanism. For example, the PASCAL-H compiler allows ‘others :’ as a default label, and other PASCALs allow syntaxes like ‘else’ or ‘otherwise’ or ‘otherwise:’, etc. The definitions of othercases and endcases should be changed to agree with local conventions. Note that no semicolon appears before endcases in this program, so the definition of endcases should include a semicolon if the compiler wants one. (Of course, if no default mechanism is available, the case statements of BibTEX will have to be laboriously extended by listing all remaining cases. People who are stuck with such PASCALs have in fact done this, successfully but not happily!)

define othercases ≡ others : { default for cases not listed explicitly }

define endcases ≡ end { follows the default case in an extended case statement }

format othercases ≡ else

format endcases ≡ end

6. Labels are given symbolic names by the following definitions, so that occasional goto statements will be meaningful. We insert the label ‘exit :’ just before the ‘end’ of a procedure in which we have used the ‘return’ statement defined below (and this is the only place ‘exit :’ appears). This label is sometimes used for exiting loops that are set up with the loop construction defined below. Another generic label is ‘loop exit :’; it appears immediately after a loop.

Incidentally, this program never declares a label that isn’t actually used, because some fussy PASCAL compilers will complain about redundant labels.

define exit = 10 { go here to leave a procedure }

define loop exit = 15 { go here to leave a loop within a procedure }

define loop1 exit = 16 { the first generic label for a procedure with two }

define loop2 exit = 17 { the second }

7. And while we’re discussing loops: This program makes into while loops many that would otherwise be for loops because of Standard PASCAL limitations (it’s a bit complicated—standard PASCAL doesn’t allow a global variable as the index of a for loop inside a procedure; furthermore, many compilers have fairly severe limitations on the size of a block, including the main block of the program; so most of the code in this program occurs inside procedures, and since for other reasons this program must use primarily global variables, it doesn’t use many for loops).

8. This program uses this convention: If there are several quantities in a boolean expression, they are ordered by expected frequency (except perhaps when an error message results) so that execution will be fastest; this is more an attempt to understand the program than to make it faster.

9. Here are some macros for common programming idioms.

define incr (#) ≡ # ← # + 1 { increase a variable by unity }

define decr (#) ≡ # ← # − 1 { decrease a variable by unity }

define loop ≡ while true do { repeat over and over until a goto happens }

format loop ≡ xclause { ’s xclause acts like ‘while true do’ }

define do nothing ≡ { empty statement }

define return ≡ goto exit { terminate a procedure call }

format return ≡ nil

define empty = 0 { symbolic name for a null constant }

4  THE MAIN PROGRAM  BibTEX §10

define any value = 0 { this appeases PASCAL’s boolean-evaluation scheme } 10. The main program. This program first reads the file that LaTEX produces, (i) determining

which  file(s) and  file to read and (ii) constructing a list of cite keys in order of occurrence. The
file may have other  files nested within. Second, it reads and executes the  file, (i) determining

how and in which order to process the database entries in the file(s) corresponding to those cite keys in the list (or in some cases, to all the entries in the file(s)), (ii) determining what text to be output for each entry and determining any additional text to be output, and (iii) actually outputting this text to the file. In addition, the program sends error messages and other remarks to the log file and terminal.

define close up shop = 9998 { jump here after fatal errors }

define exit program = 9999 { jump here if we couldn’t even get started } ⟨ Compiler directives 11* ⟩ program BibTEX ; { all files are opened dynamically }

label close up shop, exit program ⟨ Labels in the outer block 110 ⟩; const ⟨ Constants in the outer block 14* ⟩ type ⟨ Types in the outer block 22 ⟩ var ⟨ Globals in the outer block 16 ⟩

⟨ Procedures and functions for about everything 12 ⟩ ⟨ The procedure initialize 13* ⟩ begin initialize; print ln(banner ); ⟨ Read the file 111 ⟩; ⟨ Read and execute the file 152* ⟩;

close up shop: ⟨ Clean up and leave 456 ⟩;

exit program: end.

11* . If the first character of a PASCAL comment is a dollar sign, PASCAL-H treats the comment as a list of “compiler directives” that will affect the translation of this program into machine language. The directives shown below specify full checking and inclusion of the PASCAL debugger when BibTEX is being debugged, but they cause range checking and other redundant code to be eliminated when the production system is being generated. Arithmetic overflow will be detected in all cases. ⟨ Compiler directives 11* ⟩ ≡

This code is used in section 10.

12. All procedures in this program (except for initialize) are grouped into one of the seven classes below, and these classes are dispersed throughout the program. However: Much of this program is written top down, yet PASCAL wants its procedures bottom up. Since mooning is neither a technically nor a socially acceptable solution to the bottom-up problem, this section instead performs the topological gymnastics that allows, ordering these classes to satisfy PASCAL compilers. There are a few procedures still out of place after this ordering, though, and the other modules that complete the task have “gymnastics” as an index entry. ⟨ Procedures and functions for about everything 12 ⟩ ≡

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ ⟨ Procedures and functions for file-system interacting 59 ⟩ ⟨ Procedures and functions for handling numbers, characters, and strings 55 ⟩ ⟨ Procedures and functions for input scanning 84 ⟩ ⟨ Procedures and functions for name-string processing 368 ⟩ ⟨ Procedures and functions for style-file function execution 308 ⟩ ⟨ Procedures and functions for the reading and processing of input files 101* ⟩

This code is used in section 10.

§13 BibTEX THE MAIN PROGRAM 5

13* . This procedure gets things started properly. ⟨ The procedure initialize 13* ⟩ ≡ procedure initialize;

var ⟨ Local variables for initialization 23 ⟩ begin ⟨ Check the “constant” values for consistency 17 ⟩; if (bad > 0) then

begin write ln(term out , bad : 0, ´ ␣ ␣ ␣ ␣ ´ ); uexit (1); end;

⟨ Set initial values of key variables 20 ⟩;

pre def certain strings ;

get the top level aux file name;

end;

This code is used in section 10.

14* . These parameters can be changed at compile time to extend or reduce BibTEX’s capacity. They are set to accommodate about 750 cites when used with the standard styles, although pool size is usually the first limitation to be a problem, often when there are 500 cites. ⟨ Constants in the outer block 14* ⟩ ≡

buf size = 3000; { maximum number of characters in an input line (or string) } min print line = 3; { minimum line length: must be ≥ 3 } max print line = 79; { the maximum: must be > min print line and < buf size } aux stack size = 20; { maximum number of simultaneous open files } max bib files = 20; { maximum number of files allowed } pool size = 2560000; { maximum number of characters in strings } max strings = 20000; { maximum number of strings, including pre-defined; must be ≤ hash size } max cites = 3000; { maximum number of distinct cite keys; must be ≤ max strings } min crossrefs = 2; { minimum number of cross-refs required for automatic cite list inclusion } wiz fn space = 3000; { maximum amount of wiz defined -function space } single fn space = 100; { maximum amount for a single wiz defined -function } max ent ints = 25000; { maximum number of int entry var s (entries × int entry var s) } max ent strs = 25000; { maximum number of str entry var s (entries × str entry var s) } ent str size = 100; { maximum size of a str entry var ; must be ≤ buf size } glob str size = 1000; { maximum size of a str global var ; must be ≤ buf size } max fields = 69000; { maximum number of fields (entries × fields, about 23 ∗ max cites for consistency) } lit stk size = 100; { maximum number of literal functions on the stack }

See also section 334. This code is used in section 10.

15* . These parameters can also be changed at compile time, but they’re needed to define some numeric macros so they must be so defined themselves.

define hash size = 21000 { must be ≥ max strings and ≥ hash prime } define hash prime = 16319 { a prime number about 85% of hash size and ≥ 128 and < 2^{14} − 2^{6} } define file name size ≡ FILENAMESIZE { Get value from . } define max glob strs = 10 { maximum number of str global var names } define max glb str minus 1 = max glob strs − 1 { to avoid wasting a str global var } 16. In case somebody has inadvertently made bad settings of the “constants,” BibTEX checks them using a global variable called bad .

This is the first of many sections of BibTEX where global variables are defined. ⟨ Globals in the outer block 16 ⟩ ≡ bad : integer ; { is some “constant” wrong? }

See also sections 19, 24, 30, 34, 37*, 42, 44, 49, 66, 75, 77, 79, 81, 90, 92, 98*, 105, 118, 125, 130, 148, 162, 164, 196, 220, 248,

291, 332, 338, 345, and 366. This code is used in section 10.

17. Each digit-value of bad has a specific meaning. ⟨ Check the “constant” values for consistency 17 ⟩ ≡

bad ← 0; if (min print line < 3) then bad ← 1; if (max print line ≤ min print line) then bad ← 10 ∗ bad + 2; if (max print line ≥ buf size) then bad ← 10 ∗ bad + 3; if (hash prime < 128) then bad ← 10 ∗ bad + 4; if (hash prime > hash size) then bad ← 10 ∗ bad + 5; if (hash prime ≥ (16384 − 64)) then bad ← 10 ∗ bad + 6; if (max strings > hash size) then bad ← 10 ∗ bad + 7; if (max cites > max strings ) then bad ← 10 ∗ bad + 8; if (ent str size > buf size) then bad ← 10 ∗ bad + 9; if (glob str size > buf size) then bad ← 100 ∗ bad + 11; { well, almost each }

See also section 303. This code is used in section 13*.

18. A global variable called history will contain one of four values at the end of every run: spotless means that no unusual messages were printed; warning message means that a message of possible interest was printed but no serious errors were detected; error message means that at least one error was found; fatal message means that the program terminated abnormally. The value of history does not influence the behavior of the program; it is simply computed for the convenience of systems that might want to use such information.

define spotless = 0 { history value for normal jobs }

define warning message = 1 { history value when non-serious info was printed } define error message = 2 { history value when an error was noted } define fatal message = 3 { history value when we had to stop prematurely }

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure mark warning ;

begin if (history = warning message) then incr (err count )

else if (history = spotless ) then begin history ← warning message; err count ← 1; end;

end; procedure mark error ;

begin if (history < error message) then begin history ← error message; err count ← 1; end

else { history = error message }

incr (err count );

end; procedure mark fatal ;

begin history ← fatal message;

end;

19. For the two states warning message and error message we keep track of the number of messages given; but since warning messages aren’t so serious, we ignore them once we’ve seen an error message. Hence we need just the single variable err count to keep track. ⟨ Globals in the outer block 16 ⟩ +≡ history : spotless . . fatal message; { how bad was this run? } err count : integer ;

20. The err count gets set or reset when history first changes to warning message or error message, so we don’t need to initialize it. ⟨ Set initial values of key variables 20 ⟩ ≡

history ← spotless ;

See also sections 25, 27, 28, 32, 33, 35, 68, 73, 120, 126, 132, 163, 165, 197, and 293. This code is used in section 13*.

8  THE CHARACTER SET  BibTEX §21

21. The character set. (The following material is copied (almost) verbatim from TEX. Thus, the same system-dependent changes should be made to both programs.)

In order to make TEX readily portable between a wide variety of computers, all of its input text is converted to an internal seven-bit code that is essentially 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 ‘ ’ has ASCII code 65 = ´ 101 , and when TEX typesets this letter it specifies character number 65 in the current font. If that font actually has ‘ ’ in a different position, TEX doesn’t know what the real position is; the program that does the actual printing from TEX’s deviceindependent files is responsible for converting from ASCII to a particular font encoding.

TEX’s internal code is relevant also with respect to constants that begin with a reverse apostrophe.

22. 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 in the outer block 22 ⟩ ≡

ASCII code = 0 . . 127; { seven-bit numbers }

See also sections 31, 36*, 43, 50, 65, 74, 106, 119, 131, 161, 292, and 333. This code is used in section 10.

23. The original PASCAL compiler was designed in the late 60s, when six-bit character sets were common, so it did not make provision for lower-case 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 ´ 40 through ´ 176 ; 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 PASCALs use the original name char for the characters in text files, even though there now are more than 64 such characters, while other PASCALs consider 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.

define text char ≡ char { the data type of characters in text files }

define first text char = 0 { ordinal number of the smallest element of text char }

define last text char = 127 { ordinal number of the largest element of text char } ⟨ Local variables for initialization 23 ⟩ ≡ i: 0 . . last text char ; { this is the first one declared }

See also section 67. This code is used in section 13*.

§25 BibTEX THE CHARACTER SET 9

24. 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. ⟨ Globals in the outer block 16 ⟩ +≡ xord : array [text char ] of ASCII code; { specifies conversion of input characters } xchr : array [ASCII code] of text char ; { specifies conversion of output characters } 25. 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 most 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. ⟨ Set initial values of key variables 20 ⟩ +≡

xchr [´ 40 ] ← ´ ␣´ ; xchr [´ 41 ] ← ´ ´ ; xchr [´ 42 ] ← ´ ´ ; xchr [´ 43 ] ← ´ #´ ; xchr [´ 44 ] ← ´ $´ ; xchr [´ 45 ] ← ´ %´ ; xchr [´ 46 ] ← ´ ´ ; xchr [´ 47 ] ← ´ ´ ´ ´ ; xchr [´ 50 ] ← ´ ´ ; xchr [´ 51 ] ← ´ ´ ; xchr [´ 52 ] ← ´ ´ ; xchr [´ 53 ] ← ´ ´ ; xchr [´ 54 ] ← ´ ´ ; xchr [´ 55 ] ← ´ ´ ; xchr [´ 56 ] ← ´ ´ ; xchr [´ 57 ] ← ´ ´ ; xchr [´ 60 ] ← ´ ´ ; xchr [´ 61 ] ← ´ ´ ; xchr [´ 62 ] ← ´ ´ ; xchr [´ 63 ] ← ´ ´ ; xchr [´ 64 ] ← ´ ´ ; xchr [´ 65 ] ← ´ ´ ; xchr [´ 66 ] ← ´ ´ ; xchr [´ 67 ] ← ´ ´ ; xchr [´ 70 ] ← ´ ´ ; xchr [´ 71 ] ← ´ ´ ; xchr [´ 72 ] ← ´ ´ ; xchr [´ 73 ] ← ´ ´ ; xchr [´ 74 ] ← ´ ´ ; xchr [´ 75 ] ← ´ ´ ; xchr [´ 76 ] ← ´ ´ ; xchr [´ 77 ] ← ´ ´ ; xchr [´ 100 ] ← ´ ´ ; xchr [´ 101 ] ← ´ ´ ; xchr [´ 102 ] ← ´ ´ ; xchr [´ 103 ] ← ´ ´ ; xchr [´ 104 ] ← ´ ´ ; xchr [´ 105 ] ← ´ ´ ; xchr [´ 106 ] ← ´ ´ ; xchr [´ 107 ] ← ´ ´ ; xchr [´ 110 ] ← ´ ´ ; xchr [´ 111 ] ← ´ ´ ; xchr [´ 112 ] ← ´ ´ ; xchr [´ 113 ] ← ´ ´ ; xchr [´ 114 ] ← ´ ´ ; xchr [´ 115 ] ← ´ ´ ; xchr [´ 116 ] ← ´ ´ ; xchr [´ 117 ] ← ´ ´ ; xchr [´ 120 ] ← ´ ´ ; xchr [´ 121 ] ← ´ ´ ; xchr [´ 122 ] ← ´ ´ ; xchr [´ 123 ] ← ´ ´ ; xchr [´ 124 ] ← ´ ´ ; xchr [´ 125 ] ← ´ ´ ; xchr [´ 126 ] ← ´ ´ ; xchr [´ 127 ] ← ´ ´ ; xchr [´ 130 ] ← ´ ´ ; xchr [´ 131 ] ← ´ ´ ; xchr [´ 132 ] ← ´ ´ ; xchr [´ 133 ] ← ´ ´ ; xchr [´ 134 ] ← ´ ´ ; xchr [´ 135 ] ← ´ ´ ; xchr [´ 136 ] ← ´ ´ ; xchr [´ 137 ] ← ´ ´ ; xchr [´ 140 ] ← ´ ` ´ ; xchr [´ 141 ] ← ´ ´ ; xchr [´ 142 ] ← ´ ´ ; xchr [´ 143 ] ← ´ ´ ; xchr [´ 144 ] ← ´ ´ ; xchr [´ 145 ] ← ´ ´ ; xchr [´ 146 ] ← ´ ´ ; xchr [´ 147 ] ← ´ ´ ; xchr [´ 150 ] ← ´ ´ ; xchr [´ 151 ] ← ´ ´ ; xchr [´ 152 ] ← ´ ´ ; xchr [´ 153 ] ← ´ ´ ; xchr [´ 154 ] ← ´ ´ ; xchr [´ 155 ] ← ´ ´ ; xchr [´ 156 ] ← ´ ´ ; xchr [´ 157 ] ← ´ ´ ; xchr [´ 160 ] ← ´ ´ ; xchr [´ 161 ] ← ´ ´ ; xchr [´ 162 ] ← ´ ´ ; xchr [´ 163 ] ← ´ ´ ; xchr [´ 164 ] ← ´ ´ ; xchr [´ 165 ] ← ´ ´ ; xchr [´ 166 ] ← ´ ´ ; xchr [´ 167 ] ← ´ ´ ; xchr [´ 170 ] ← ´ ´ ; xchr [´ 171 ] ← ´ ´ ; xchr [´ 172 ] ← ´ ´ ; xchr [´ 173 ] ← ´ ´ ; xchr [´ 174 ] ← ´ ´ ; xchr [´ 175 ] ← ´ ´ ; xchr [´ 176 ] ← ´ ´ ; xchr [0] ← ´ ␣´ ; xchr [´ 177 ] ← ´ ␣´ ; { ASCII codes 0 and ´ 177 do not appear in text }

26. Some of the ASCII codes without visible characters have been given symbolic names in this program because they are used with a special meaning. The tab character may be system dependent.

define null code = ´ 0 { ASCII code that might disappear } define tab = ´ 11 { ASCII code treated as white space } define space = ´ 40 { ASCII code treated as white space } define invalid code = ´ 177 { ASCII code that should not appear } 27. 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 The TEXbook gives a complete specification of the intended correspondence between characters and TEX’s internal representation.

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 [1 . . ´ 37 ], 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 ‘ ’ instead of ‘ ’. At MIT, for example, it would be more appropriate to substitute the code

for i ← 1 to ´ 37 do xchr [i] ← chr (i);

TEX’s character set is essentially the same as MIT’s, even with respect to characters less than ´ 40 . 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 ´ 40 . ⟨ Set initial values of key variables 20 ⟩ +≡

for i ← 1 to ´ 37 do xchr [i] ← ´ ␣´ ;

xchr [tab] ← chr (tab);

28. This 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 < ´ 177 , 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 ´ 40 in case there is a coincidence. ⟨ Set initial values of key variables 20 ⟩ +≡

for i ← first text char to last text char do xord [chr (i)] ← invalid code;

for i ← 1 to ´ 176 do xord [xchr [i]] ← i; 29. Also, various characters are given symbolic names; all the ones this program uses are collected here. We use the sharp sign as the concat char , rather than something more natural (like an ampersand), for uniformity of database syntax (ampersand is a valid character in identifiers).

define double quote = { delimits strings } define number sign = # { marks an int literal } define comment = % { ignore the rest of a or TEX line } define single quote = ´ { marks a quoted function } define left paren = { optional database entry left delimiter } define right paren = { corresponding right delimiter } define comma = { separates various things } define minus sign = { for a negative number } define equals sign = { separates a field name from a field value } define at sign = { the beginning of a database entry } define left brace = { left delimiter of many things } define right brace = { corresponding right delimiter } define period = { these are three } define question mark = { string-ending characters }

define exclamation mark =  { of interest in  $ }
define tie =  { the default space char, in  $ }
define hyphen =  { like white space, in  $ }

define star = { for including entire database } define concat char = # { for concatenating field tokens } define colon = { for lower-casing (usually title) strings } define backslash = { used to recognize accented characters }

30. These arrays give a lexical classification for the ASCII codes; lex class is used for general scanning and id class is used for scanning identifiers. ⟨ Globals in the outer block 16 ⟩ +≡ lex class : array [ASCII code] of lex type; id class : array [ASCII code] of id type;

31. Every character has two types of the lexical classifications. The first type is general, and the second type tells whether the character is legal in identifiers.

define illegal = 0 { the unrecognized ASCII codes } define white space = 1 { things like spaces that you can’t see } define alpha = 2 { the upper- and lower-case letters } define numeric = 3 { the ten digits } define sep char = 4 { things sometimes treated like white space } define other lex = 5 { when none of the above applies } define last lex = 5 { the same number as on the line above } define illegal id char = 0 { a few forbidden ones } define legal id char = 1 { most printing characters }

⟨ Types in the outer block 22 ⟩ +≡ lex type = 0 . . last lex ; id type = 0 . . 1; 32. Now we initialize the system-dependent lex class array. The tab character may be system dependent. Note that the order of these assignments is important here. ⟨ Set initial values of key variables 20 ⟩ +≡

for i ← 0 to ´ 177 do lex class [i] ← other lex ; for i ← 0 to ´ 37 do lex class [i] ← illegal ; lex class [invalid code] ← illegal ; lex class [tab] ← white space; lex class [space] ← white space; lex class [tie] ← sep char ; lex class [hyphen] ← sep char ; for i ← ´ 60 to ´ 71 do lex class [i] ← numeric; for i ← ´ 101 to ´ 132 do lex class [i] ← alpha; for i ← ´ 141 to ´ 172 do lex class [i] ← alpha;

33. And now the id class array. ⟨ Set initial values of key variables 20 ⟩ +≡

for i ← 0 to ´ 177 do id class [i] ← legal id char ; for i ← 0 to ´ 37 do id class [i] ← illegal id char ; id class [space] ← illegal id char ; id class [tab] ← illegal id char ; id class [double quote] ← illegal id char ; id class [number sign] ← illegal id char ; id class [comment ] ← illegal id char ; id class [single quote] ← illegal id char ; id class [left paren] ← illegal id char ; id class [right paren] ← illegal id char ; id class [comma] ← illegal id char ; id class [equals sign] ← illegal id char ; id class [left brace] ← illegal id char ; id class [right brace] ← illegal id char ;

34. The array char width gives relative printing widths of each ASCII code, and string width will be used later to sum up char widths in a string. ⟨ Globals in the outer block 16 ⟩ +≡ char width: array [ASCII code] of integer ; string width: integer ; 35. Now we initialize the system-dependent char width array, for which space is the only white space character given a nonzero printing width. The widths here are taken from Stanford’s June ’87 cmr10 font and represent hundredths of a point (rounded), but since they’re used only for relative comparisons, the units have no meaning.

define ss width = 500 { character ´ 31 ’s width in the cmr10 font } define ae width = 722 { character ´ 32 ’s width in the cmr10 font } define oe width = 778 { character ´ 33 ’s width in the cmr10 font } define upper ae width = 903 { character ´ 35 ’s width in the cmr10 font } define upper oe width = 1014 { character ´ 36 ’s width in the cmr10 font }

14  INPUT AND OUTPUT  BibTEX §36

⟨ Set initial values of key variables 20 ⟩ +≡ for i ← 0 to ´ 177 do char width[i] ← 0; char width[´ 40 ] ← 278; char width[´ 41 ] ← 278; char width[´ 42 ] ← 500; char width[´ 43 ] ← 833; char width[´ 44 ] ← 500; char width[´ 45 ] ← 833; char width[´ 46 ] ← 778; char width[´ 47 ] ← 278; char width[´ 50 ] ← 389; char width[´ 51 ] ← 389; char width[´ 52 ] ← 500; char width[´ 53 ] ← 778; char width[´ 54 ] ← 278; char width[´ 55 ] ← 333; char width[´ 56 ] ← 278; char width[´ 57 ] ← 500; char width[´ 60 ] ← 500; char width[´ 61 ] ← 500; char width[´ 62 ] ← 500; char width[´ 63 ] ← 500; char width[´ 64 ] ← 500; char width[´ 65 ] ← 500; char width[´ 66 ] ← 500; char width[´ 67 ] ← 500; char width[´ 70 ] ← 500; char width[´ 71 ] ← 500; char width[´ 72 ] ← 278; char width[´ 73 ] ← 278; char width[´ 74 ] ← 278; char width[´ 75 ] ← 778; char width[´ 76 ] ← 472; char width[´ 77 ] ← 472; char width[´ 100 ] ← 778; char width[´ 101 ] ← 750; char width[´ 102 ] ← 708; char width[´ 103 ] ← 722; char width[´ 104 ] ← 764; char width[´ 105 ] ← 681; char width[´ 106 ] ← 653; char width[´ 107 ] ← 785; char width[´ 110 ] ← 750; char width[´ 111 ] ← 361; char width[´ 112 ] ← 514; char width[´ 113 ] ← 778; char width[´ 114 ] ← 625; char width[´ 115 ] ← 917; char width[´ 116 ] ← 750; char width[´ 117 ] ← 778; char width[´ 120 ] ← 681; char width[´ 121 ] ← 778; char width[´ 122 ] ← 736; char width[´ 123 ] ← 556; char width[´ 124 ] ← 722; char width[´ 125 ] ← 750; char width[´ 126 ] ← 750; char width[´ 127 ] ← 1028; char width[´ 130 ] ← 750; char width[´ 131 ] ← 750; char width[´ 132 ] ← 611; char width[´ 133 ] ← 278; char width[´ 134 ] ← 500; char width[´ 135 ] ← 278; char width[´ 136 ] ← 500; char width[´ 137 ] ← 278; char width[´ 140 ] ← 278; char width[´ 141 ] ← 500; char width[´ 142 ] ← 556; char width[´ 143 ] ← 444; char width[´ 144 ] ← 556; char width[´ 145 ] ← 444; char width[´ 146 ] ← 306; char width[´ 147 ] ← 500; char width[´ 150 ] ← 556; char width[´ 151 ] ← 278; char width[´ 152 ] ← 306; char width[´ 153 ] ← 528; char width[´ 154 ] ← 278; char width[´ 155 ] ← 833; char width[´ 156 ] ← 556; char width[´ 157 ] ← 500; char width[´ 160 ] ← 556; char width[´ 161 ] ← 528; char width[´ 162 ] ← 392; char width[´ 163 ] ← 394; char width[´ 164 ] ← 389; char width[´ 165 ] ← 556; char width[´ 166 ] ← 528; char width[´ 167 ] ← 722; char width[´ 170 ] ← 528; char width[´ 171 ] ← 528; char width[´ 172 ] ← 444; char width[´ 173 ] ← 500; char width[´ 174 ] ← 1000; char width[´ 175 ] ← 500; char width[´ 176 ] ← 500; 36* . Input and output. The basic operations we need to do are (1) inputting and outputting of text characters to or from a file; (2) instructing the operating system to initiate (“open”) or to terminate (“close”) input or output to or from a specified file; and (3) testing whether the end of an input file has been reached. ⟨ Types in the outer block 22 ⟩ +≡

37* . 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 BibTEX; 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 BibTEX can open a file whose external name is specified by name of file. BibTEX does no case conversion for file names. ⟨ Globals in the outer block 16 ⟩ +≡ name of file: packed array [1 . . file name size] of char ; { on some systems this is a record variable } name length: 0 . . file name size; { this many characters are relevant in name of file (the rest are blank) } name ptr : integer ; { index variable into name of file }

38.

39* . File opening will be done in C.

define no file path = −1

40* . Files can be closed with the PASCAL-H routine ‘close(f)’, which 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 close operation makes the corresponding external file appear on the user’s area, ready to be read.

File closing will be done in C, too.

41. Text output is easy to do with the ordinary PASCAL put procedure, so we don’t have to make any other special arrangements. The treatment of text input is more difficult, however, because of the necessary translation to ASCII code values, and because TEX’s conventions should be efficient and they should blend nicely with the user’s operating environment.

42. 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 and last . The buffer array contains ASCII code values, and last is an index into this array marking the end of a line of text. (Occasionally, buffer is used for something else, in which case it is copied to a temporary array.) ⟨ Globals in the outer block 16 ⟩ +≡ buffer : buf type; { usually, lines of characters being read } last : buf pointer ; { end of the line just input to buffer }

43. The type buf type is used for buffer , for saved copies of it, or for scratch work. It’s not packed because otherwise the program would run much slower on some systems (more than 25 percent slower, for example, on a TOPS-20 operating system). But on systems that are byte-addressable and that have a good compiler, packing buf type would save lots of space without much loss of speed. Other modules that have packable arrays are also marked with a “space savings” index entry. ⟨ Types in the outer block 22 ⟩ +≡

buf pointer = 0 . . buf size; { an index into a buf type }

buf type = array [buf pointer ] of ASCII code; { for various buffers }

§44 BibTEX INPUT AND OUTPUT 15

44. And while we’re at it, we declare another buffer for general use. Because buffers are not packed and can get large, we use sv buffer several purposes; this is a bit kludgy, but it helps make the stack space not overflow on some machines. It’s used when reading the entire database file (in the command) and when doing name-handling (through the alias name buf ) in the built in functions $ and

$ .

⟨ Globals in the outer block 16 ⟩ +≡ sv buffer : buf type; sv ptr1 : buf pointer ; sv ptr2 : buf pointer ; tmp ptr , tmp end ptr : integer ; { copy pointers only, usually for buffers }

45. When something in the program wants to be bigger or something out there wants to be smaller, it’s time to call it a run. Here’s the first of several macros that have associated procedures so that they produce less inline code.

define overflow (#) ≡ begin { fatal error—close up shop } print overflow ; print ln(# : 0); goto close up shop; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure print overflow ;

begin print (´ ´ ´ ␣ ␣ ´ ´ ␣´ ); mark fatal ;

end;

46. When something happens that the program thinks is impossible, call the maintainer.

define confusion(#) ≡ begin { fatal error—close up shop } print (#); print confusion; goto close up shop; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure print confusion;

begin print ln(´ ␣ ´ ´ ␣ ´ ); print ln(´ ␣ ␣ ␣ ␣ ´ ); mark fatal ; end;

47. When a buffer overflows, it’s time to complain (and then quit). ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure buffer overflow ;

begin overflow (´ ␣ ␣´ , buf size);

end; 48* . 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 ← 0. In general, the ASCII code numbers that represent the next line of the file are input into buffer [0], buffer [1], …, buffer [last − 1]; and the global variable last is set equal to the length of the line. Trailing white space characters are removed from the line (white space characters are explained in the character-set section—most likely they’re blanks); thus, either last = 0 (in which case the line was entirely blank) or lex class [buffer [last − 1]] ≠ white space. An overflow error is given if the normal actions of input ln would make last > buf size.

Standard PASCAL says that a file should have eoln immediately before eof , but BibTEX 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↑ will be undefined). ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ function input ln(var f : alpha file): boolean; { inputs the next line or returns false }

label loop exit ;

begin last ← 0;

if (eof (f)) then input ln ← false

else begin while (¬eoln(f)) do begin if (last ≥ buf size) then buffer overflow ; buffer [last ] ← xord [getc(f)]; incr (last ); end;

vgetc(f); { skip the eol }

while (last > 0) do { remove trailing white space } if (lex class [buffer [last − 1]] = white space) then decr (last ) else goto loop exit ;

loop exit : input ln ← true;

§49 BibTEX STRING HANDLING 17

end; end; 49. String handling. BibTEX uses variable-length strings of seven-bit characters. Since PASCAL does not have a well-developed string mechanism, BibTEX does all its string processing by home-grown (predominantly TEX’s) methods. Unlike TEX, however, BibTEX does not use a pool file for string storage; it creates its few pre-defined strings at run-time.

The necessary operations are handled with a simple data structure. The array str pool contains all the (seven-bit) ASCII codes in all the strings BibTEX must ever search for (generally identifiers names), and the array str start contains indices of the starting points of each such 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 ; locations str pool [pool ptr ] and str start [str ptr ] are ready for the next string to be allocated. Location str start [0] is unused so that hashing will work correctly.

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. ⟨ Globals in the outer block 16 ⟩ +≡ str pool : packed array [pool pointer ] of ASCII code; { the characters } str start : packed array [str number ] of pool pointer ; { the starting pointers } pool ptr : pool pointer ; { first unused position in str pool } str ptr : str number ; { start of the current string being created } str num: str number ; { general index variable into str start } p ptr1 , p ptr2 : pool pointer ; { several procedures use these locally }

50. Where pool pointer and str number are pointers into str pool and str start . ⟨ Types in the outer block 22 ⟩ +≡

pool pointer = 0 . . pool size; { for variables that point into str pool }

str number = 0 . . max strings ; { for variables that point into str start }

51. These macros send a string in str pool to an output file.

define max pop = 3 { —see the built in functions section }

define print pool str (#) ≡ print a pool str (#) { making this a procedure saves a little space } define trace pr pool str (#) ≡

begin out pool str (log file, #); end

52. And here are the associated procedures. Note: The term out file is system dependent. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure out pool str (var f : alpha file; s : str number );

var i: pool pointer ;

begin { allowing str ptr ≤ s < str ptr + max pop is a -stack kludge }

if ((s < 0) ∨ (s ≥ str ptr + max pop) ∨ (s ≥ max strings )) then

confusion(´ ␣ ␣ ´ , s : 0); for i ← str start [s] to str start [s + 1] − 1 do write(f, xchr [str pool [i]]); end;

procedure print a pool str (s : str number ); begin out pool str (term out , s); out pool str (log file, s); end;

53. Several of the elementary string operations are performed using macros instead of using 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.

18  STRING HANDLING  BibTEX §54

define length(#) ≡ (str start [# + 1] − str start [#]) { the number of characters in string number # } 54. Strings are created by appending character codes to str pool . The macro called append char , 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.

To test if there is room to append l more characters to str pool , we shall write str room(l), which aborts BibTEX and gives an error message if there isn’t enough room.

define append char (#) ≡ { put ASCII code # at the end of str pool } begin str pool [pool ptr ] ← #; incr (pool ptr ); end

define str room(#) ≡ { make sure that the pool hasn’t overflowed } begin if (pool ptr + # > pool size) then pool overflow ; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure pool overflow ;

begin overflow (´ ␣ ␣´ , pool size);

end;

55. Once a sequence of characters has been appended to str pool , it officially becomes a string when the function make string is called. It returns the string number of the string it just made. ⟨ Procedures and functions for handling numbers, characters, and strings 55 ⟩ ≡ function make string : str number ; { current string enters the pool }

begin if (str ptr = max strings ) then overflow (´ ␣ ␣ ␣´ , max strings );

incr (str ptr ); str start [str ptr ] ← pool ptr ; make string ← str ptr − 1;

end;

See also sections 57, 58, 63, 64, 69, 78*, 199*, 266, 279, 301, 302, 304, 336, and 337. This code is used in section 12.

56. These macros destroy and recreate the string at the end of the pool.

define flush string ≡ begin decr (str ptr ); pool ptr ← str start [str ptr ]; end

define unflush string ≡ begin incr (str ptr ); pool ptr ← str start [str ptr ]; end 57. This subroutine compares string s with another string that appears in the buffer buf between positions bf ptr and bf ptr + len − 1; the result is true if and only if the strings are equal. ⟨ Procedures and functions for handling numbers, characters, and strings 55 ⟩ +≡ function str eq buf (s : str number ; var buf : buf type; bf ptr , len : buf pointer ): boolean;

{ test equality of strings } label exit ; var i: buf pointer ; { running }

j: pool pointer ; { indices } begin if (length(s) ≠ len) then { strings of unequal length }

begin str eq buf ← false; return;

end; i ← bf ptr ; j ← str start [s]; while (j < str start [s + 1]) do

begin if (str pool [j] ≠ buf [i]) then begin str eq buf ← false; return; end;

incr (i); incr (j);

end; str eq buf ← true;

exit : end;

58. This subroutine compares two str pool strings and returns true true if and only if the strings are equal. ⟨ Procedures and functions for handling numbers, characters, and strings 55 ⟩ +≡ function str eq str (s1 , s2 : str number ): boolean;

label exit ; begin if (length(s1 ) ≠ length(s2 )) then

begin str eq str ← false; return;

end; p ptr1 ← str start [s1 ]; p ptr2 ← str start [s2 ]; while (p ptr1 < str start [s1 + 1]) do

begin if (str pool [p ptr1 ] ≠ str pool [p ptr2 ]) then begin str eq str ← false; return; end;

incr (p ptr1 ); incr (p ptr2 );

end; str eq str ← true;

exit : end; 59. This procedure copies file name file name into the beginning of name of file, if it will fit. It also sets the global variable name length to the appropriate value. ⟨ Procedures and functions for file-system interacting 59 ⟩ ≡ procedure start name(file name : str number );

var p ptr : pool pointer ; { running index } begin if (length(file name) > file name size) then

begin print (´ ´ ); print pool str (file name); print ln(´ ´ ); file nm size overflow ; end;

name ptr ← 1; p ptr ← str start [file name]; while (p ptr < str start [file name + 1]) do

begin name of file[name ptr ] ← chr (str pool [p ptr ]); incr (name ptr ); incr (p ptr ); end;

name length ← length(file name); end;

See also sections 61 and 62. This code is used in section 12.

60. Yet another complaint-before-quiting. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure file nm size overflow ;

begin overflow (´ ␣ ␣ ␣´ , file name size); end;

61. This procedure copies file extension ext into the array name of file starting at position name length +1. It also sets the global variable name length to the appropriate value. ⟨ Procedures and functions for file-system interacting 59 ⟩ +≡ procedure add extension(ext : str number );

var p ptr : pool pointer ; { running index } begin if (name length + length(ext ) > file name size) then

begin print (´ ´ , name of file, ´ ␣ ´ ); print pool str (ext ); print ln(´ ´ ); file nm size overflow ; end;

name ptr ← name length + 1; p ptr ← str start [ext ]; while (p ptr < str start [ext + 1]) do

begin name of file[name ptr ] ← chr (str pool [p ptr ]); incr (name ptr ); incr (p ptr ); end;

name length ← name length + length(ext ); name ptr ← name length + 1; while (name ptr ≤ file name size) do { pad with blanks }

begin name of file[name ptr ] ← ´ ␣´ ; incr (name ptr );

end; end; 62. This procedure copies the default logical area name area into the array name of file starting at position 1, after shifting up the rest of the filename. It also sets the global variable name length to the appropriate value. ⟨ Procedures and functions for file-system interacting 59 ⟩ +≡ procedure add area(area : str number );

var p ptr : pool pointer ; { running index } begin if (name length + length(area) > file name size) then

begin print (´ ´ ); print pool str (area); print (name of file, ´ ´ ); file nm size overflow ; end;

name ptr ← name length; while (name ptr > 0) do { shift up name }

begin name of file[name ptr + length(area)] ← name of file[name ptr ]; decr (name ptr ); end;

name ptr ← 1; p ptr ← str start [area]; while (p ptr < str start [area + 1]) do

begin name of file[name ptr ] ← chr (str pool [p ptr ]); incr (name ptr ); incr (p ptr ); end;

name length ← name length + length(area); end;

63. This system-independent procedure converts upper-case characters to lower case for the specified part of buf . It is system independent because it uses only the internal representation for characters.

define case difference = − ⟨ Procedures and functions for handling numbers, characters, and strings 55 ⟩ +≡ procedure lower case(var buf : buf type; bf ptr , len : buf pointer );

var i: buf pointer ; begin if (len > 0) then

for i ← bf ptr to bf ptr + len − 1 do

if ((buf [i] ≥ ) ∧ (buf [i] ≤ )) then buf [i] ← buf [i] + case difference; end;

64. This system-independent procedure is the same as the previous except that it converts lower- to uppercase letters. ⟨ Procedures and functions for handling numbers, characters, and strings 55 ⟩ +≡ procedure upper case(var buf : buf type; bf ptr , len : buf pointer );

var i: buf pointer ; begin if (len > 0) then

for i ← bf ptr to bf ptr + len − 1 do

22  THE HASH TABLE  BibTEX §65

if ((buf [i] ≥ ) ∧ (buf [i] ≤ )) then buf [i] ← buf [i] − case difference; end; 65. The hash table. All static strings that BibTEX might have to search for, generally identifiers, are stored and retrieved by means of a fairly standard hash-table algorithm (but slightly altered here) called the method of “coalescing lists” (cf. Algorithm 6.4C in The Art of Computer Programming). Once a string enters the table, it is never removed. The actual sequence of characters forming a string is stored in the str pool array.

The hash table consists of the four arrays hash next , hash text , hash ilk , and ilk info. The first array, hash next [p], points to the next identifier belonging to the same coalesced list as the identifier corresponding to p. The second, hash text [p], points to the str start entry for p’s string. If position p of the hash table is empty, we have hash text [p] = 0; if position p is either empty or the end of a coalesced hash list, we have hash next [p] = empty ; an auxiliary pointer variable called hash used is maintained in such a way that all locations p ≥ hash used are nonempty. The third, hash ilk [p], tells how this string is used (as ordinary text, as a variable name, as an file command, etc). The fourth, ilk info[p], contains information specific to the corresponding hash ilk —for integer ilk s: the integer’s value; for cite ilk s: a pointer into cite list ; for lc cite ilk s: a pointer to a cite ilk string; for command ilk s: a constant to be used in a case statement; for bst fn ilk s: function-specific information; for macro ilk s: a pointer to its definition string; for control seq ilk s: a constant for use in a case statement; for all other ilk s it contains no information. This ilk -specific information is set in other parts of the program rather than here in the hashing routine.

define hash base = empty + 1 { lowest numbered hash-table location }

define hash max = hash base + hash size − 1 { highest numbered hash-table location }

define hash is full ≡ (hash used = hash base) { test if all positions are occupied }

define text ilk = 0 { a string of ordinary text }

define integer ilk = 1 { an integer (possibly with a minus sign) }

define aux command ilk = 2 { an -file command }

define aux file ilk = 3 { an file name }

define bst command ilk = 4 { a -file command }

define bst file ilk = 5 { a file name }

define bib file ilk = 6 { a file name }

define file ext ilk = 7 { one of  ,  ,  ,  , or  }
define file area ilk = 8 { one of  or  }

define cite ilk = 9 { a argument }

define lc cite ilk = 10 { a argument converted to lower case }

define bst fn ilk = 11 { a function name }

define bib command ilk = 12 { a -file command }

define macro ilk = 13 { a macro or a string }

define control seq ilk = 14 { a control sequence specifying a foreign character }

define last ilk = 14 { the same number as on the line above } ⟨ Types in the outer block 22 ⟩ +≡

hash loc = hash base . . hash max ; { a location within the hash table }

hash pointer = empty . . hash max ; { either empty or a hash loc }

str ilk = 0 . . last ilk ; { the legal string types }

§67 BibTEX THE HASH TABLE 23

66. ⟨ Globals in the outer block 16 ⟩ +≡ hash next : packed array [hash loc] of hash pointer ; { coalesced-list link } hash text : packed array [hash loc] of str number ; { pointer to a string } hash ilk : packed array [hash loc] of str ilk ; { the type of string } ilk info: packed array [hash loc] of integer ; { ilk -specific info } hash used : hash base . . hash max + 1; { allocation pointer for hash table } hash found : boolean; { set to true if it’s already in the hash table } dummy loc: hash loc; { receives str lookup value whenever it’s useless } 67. ⟨ Local variables for initialization 23 ⟩ +≡ k: hash loc;

68. Now it’s time to initialize the hash table; note that str start [0] must be unused if hash text [k] ← 0 is to have the desired effect. ⟨ Set initial values of key variables 20 ⟩ +≡

for k ← hash base to hash max do begin hash next [k] ← empty ; hash text [k] ← 0; { thus, no need to initialize hash ilk or ilk info } end;

hash used ← hash max + 1; { nothing in table initially }

69. Here is the subroutine that searches the hash table for a (string, str ilk ) pair, where the string is of length l ≥ 0 and appears in buffer [j . . (j +l −1)]. If it finds the pair, it returns the corresponding hash-table location and sets the global variable hash found to true. Otherwise it sets hash found to false, and if the parameter insert it is true, it inserts the pair into the hash table, inserts the string into str pool if not previously encountered, and returns its location. Note that two different pairs can have the same string but different str ilk s, in which case the second pair encountered, if insert it were true, would be inserted into the hash table though its string wouldn’t be inserted into str pool because it would already be there.

define max hash value = hash prime + hash prime − 2 + 127 { h’s maximum value } define do insert ≡ true { insert string if not found in hash table } define dont insert ≡ false { don’t insert string } define str found = 40 { go here when you’ve found the string } define str not found = 45 { go here when you haven’t }

⟨ Procedures and functions for handling numbers, characters, and strings 55 ⟩ +≡ function str lookup(var buf : buf type; j, l : buf pointer ; ilk : str ilk ; insert it : boolean): hash loc;

{ search the hash table } label str found , str not found ; var h: 0 . . max hash value; { hash code }

p: hash loc; { index into hash arrays } k: buf pointer ; { index into buf array } old string : boolean; { set to true if it’s an already encountered string } str num: str number ; { pointer to an already encountered string }

begin ⟨ Compute the hash code h 70 ⟩;

p ← h + hash base; { start searching here; note that 0 ≤ h < hash prime } hash found ← false; old string ← false; loop

begin ⟨ Process the string if we’ve already encountered it 71 ⟩;

if (hash next [p] = empty ) then { location p may or may not be empty } begin if (¬insert it ) then goto str not found ; ⟨ Insert pair into hash table and make p point to it 72 ⟩; goto str found ; end;

p ← hash next [p]; { old and new locations p are not empty }

end; str not found : do nothing ; { don’t insert pair; function value meaningless } str found : str lookup ← p;

end; 70. The value of hash prime should be roughly 85% of hash size, and it should be a prime number (it should also be less than 2^{14} + 2^{6} = 16320 because of ’s simple-macro bound). The theory of hashing tells us to expect fewer than two table probes, on the average, when the search is successful. ⟨ Compute the hash code h 70 ⟩ ≡

begin h ← 0; { note that this works for zero-length strings } k ← j; while (k < j + l) do { not a for loop in case j = l = 0 }

begin h ← h + h + buf [k]; while (h ≥ hash prime) do h ← h − hash prime; incr (k); end;

end

This code is used in section 69.

71. Here we handle the case in which we’ve already encountered this string; note that even if we have, we’ll still have to insert the pair into the hash table if str ilk doesn’t match. ⟨ Process the string if we’ve already encountered it 71 ⟩ ≡

begin if (hash text [p] > 0) then { there’s something here }

if (str eq buf (hash text [p], buf , j, l)) then { it’s the right string }

if (hash ilk [p] = ilk ) then { it’s the right str ilk } begin hash found ← true; goto str found ; end

else begin { it’s the wrong str ilk } old string ← true; str num ← hash text [p]; end;

end

This code is used in section 69.

72. This code inserts the pair in the appropriate unused location. ⟨ Insert pair into hash table and make p point to it 72 ⟩ ≡

begin if (hash text [p] > 0) then { location p isn’t empty }

begin repeat if (hash is full ) then overflow (´ ␣ ␣´ , hash size);

decr (hash used ); until (hash text [hash used ] = 0); { search for an empty location } hash next [p] ← hash used ; p ← hash used ; end; { now location p is empty }

if (old string ) then { it’s an already encountered string }

hash text [p] ← str num else begin { it’s a new string }

str room(l); { make sure it’ll fit in str pool } k ← j; while (k < j + l) do { not a for loop in case j = l = 0 }

begin append char (buf [k]); incr (k);

end; hash text [p] ← make string ; { and make it official } end;

hash ilk [p] ← ilk ; end

This code is used in section 69.

73. Now that we’ve defined the hash-table workings we can initialize the string pool. Unlike TEX, BibTEX does not use a pool file for string storage; instead it inserts its pre-defined strings into str pool —this makes one file fewer for the BibTEX implementor to deal with. This section initializes str pool ; the pre-defined strings will be inserted into it shortly; and other strings are inserted while processing the input files. ⟨ Set initial values of key variables 20 ⟩ +≡

pool ptr ← 0; str ptr ← 1; { hash table must have str start [0] unused }

str start [str ptr ] ← pool ptr ;

74. The longest pre-defined string determines type definitions used to insert the pre-defined strings into str pool .

define longest pds = 12 { the length of ‘ $ ’ } ⟨ Types in the outer block 22 ⟩ +≡

pds loc = 1 . . longest pds ; pds len = 0 . . longest pds ; pds type = packed array [pds loc] of char ;

75. The variables in this program beginning with s specify the locations in str pool for certain often-used strings. Those here have to do with the file system; the next section will actually insert them into str pool . ⟨ Globals in the outer block 16 ⟩ +≡ s aux extension: str number ; { } s log extension: str number ; { } s bbl extension: str number ; { } s bst extension: str number ; { } s bib extension: str number ; { } s bst area: str number ; { } s bib area: str number ; { }

76. It’s time to insert some of the pre-defined strings into str pool (and thus the hash table). These systemdependent strings should contain no upper-case letters, and they must all be exactly longest pds characters long (even if fewer characters are actually stored). The pre define routine appears shortly.

Important notes: These pre-definitions must not have any glitches or the program may bomb because the log file hasn’t been opened yet, and text ilk s should be pre-defined later, for -function-execution purposes. ⟨ Pre-define certain strings 76 ⟩ ≡

pre define(´ ␣␣␣␣␣␣␣␣´ , 4, file ext ilk ); s aux extension ← hash text [pre def loc];

pre define(´ ␣␣␣␣␣␣␣␣´ , 4, file ext ilk ); s bbl extension ← hash text [pre def loc];

pre define(´ ␣␣␣␣␣␣␣␣´ , 4, file ext ilk ); s log extension ← hash text [pre def loc];

pre define(´ ␣␣␣␣␣␣␣␣´ , 4, file ext ilk ); s bst extension ← hash text [pre def loc];

pre define(´ ␣␣␣␣␣␣␣␣´ , 4, file ext ilk ); s bib extension ← hash text [pre def loc];

pre define(´ ␣␣´ , 10, file area ilk ); s bst area ← hash text [pre def loc];

pre define(´ ␣␣␣␣␣´ , 7, file area ilk ); s bib area ← hash text [pre def loc];

See also sections 80, 335, 340, and 341. This code is used in section 337.

77. This global variable gives the hash-table location of pre-defined strings generated by calls to str lookup. ⟨ Globals in the outer block 16 ⟩ +≡ pre def loc: hash loc; 78* . This procedure initializes a pre-defined string of length at most longest pds . ⟨ Procedures and functions for handling numbers, characters, and strings 55 ⟩ +≡ procedure pre define(pds : pds type; len : pds len; ilk : str ilk );

var i: pds len; begin for i ← 1 to len do buffer [i] ← xord [pds [i − 1]]; pre def loc ← str lookup(buffer , 1, len, ilk , do insert ); end;

79. These constants all begin with n and are used for the case statement that determines which command to execute. The variable command num is set to one of these and is used to do the branching, but it must have the full integer range because at times it can assume an arbitrary ilk info value (though it will be one of the values here when we actually use it).

define n aux bibdata = 0 { } define n aux bibstyle = 1 { } define n aux citation = 2 { } define n aux input = 3 { } define n bst entry = 0 { } define n bst execute = 1 { } define n bst function = 2 { } define n bst integers = 3 { } define n bst iterate = 4 { } define n bst macro = 5 { } define n bst read = 6 { } define n bst reverse = 7 { } define n bst sort = 8 { } define n bst strings = 9 { } define n bib comment = 0 { } define n bib preamble = 1 { } define n bib string = 2 { }

⟨ Globals in the outer block 16 ⟩ +≡ command num: integer ; 80. Now we pre-define the command strings; they must all be exactly longest pds characters long.

Important note: These pre-definitions must not have any glitches or the program may bomb because the log file hasn’t been opened yet. ⟨ Pre-define certain strings 76 ⟩ +≡

28  SCANNING AN INPUT LINE  BibTEX §81

pre define(´ ␣␣␣´ , 9, aux command ilk ); ilk info[pre def loc] ← n aux citation; pre define(´ ␣␣␣␣´ , 8, aux command ilk ); ilk info[pre def loc] ← n aux bibdata; pre define(´ ␣␣␣´ , 9, aux command ilk ); ilk info[pre def loc] ← n aux bibstyle; pre define(´ ␣␣␣␣␣´ , 7, aux command ilk ); ilk info[pre def loc] ← n aux input ; pre define(´ ␣␣␣␣␣␣␣´ , 5, bst command ilk ); ilk info[pre def loc] ← n bst entry ; pre define(´ ␣␣␣␣␣´ , 7, bst command ilk ); ilk info[pre def loc] ← n bst execute; pre define(´ ␣␣␣␣´ , 8, bst command ilk ); ilk info[pre def loc] ← n bst function; pre define(´ ␣␣␣␣´ , 8, bst command ilk ); ilk info[pre def loc] ← n bst integers ; pre define(´ ␣␣␣␣␣´ , 7, bst command ilk ); ilk info[pre def loc] ← n bst iterate; pre define(´ ␣␣␣␣␣␣␣´ , 5, bst command ilk ); ilk info[pre def loc] ← n bst macro; pre define(´ ␣␣␣␣␣␣␣␣´ , 4, bst command ilk ); ilk info[pre def loc] ← n bst read ; pre define(´ ␣␣␣␣␣´ , 7, bst command ilk ); ilk info[pre def loc] ← n bst reverse; pre define(´ ␣␣␣␣␣␣␣␣´ , 4, bst command ilk ); ilk info[pre def loc] ← n bst sort ; pre define(´ ␣␣␣␣␣´ , 7, bst command ilk ); ilk info[pre def loc] ← n bst strings ; pre define(´ ␣␣␣␣␣´ , 7, bib command ilk ); ilk info[pre def loc] ← n bib comment ; pre define(´ ␣␣␣␣´ , 8, bib command ilk ); ilk info[pre def loc] ← n bib preamble; pre define(´ ␣␣␣␣␣␣´ , 6, bib command ilk ); ilk info[pre def loc] ← n bib string ; 81. Scanning an input line. This section describes the various buffer scanning routines. The two global variables buf ptr1 and buf ptr2 are used in scanning an input line. Between scans, buf ptr1 points to the first character of the current token and buf ptr2 points to that of the next. The global variable last , set by the function input ln, marks the end of the current line; it equals 0 at the end of the current file. All the procedures and functions in this section will indicate an end-of-line when it’s the end of the file.

define token len ≡ (buf ptr2 − buf ptr1 ) { of the current token }

define scan char ≡ buffer [buf ptr2 ] { the current character } ⟨ Globals in the outer block 16 ⟩ +≡ buf ptr1 : buf pointer ; { points to the first position of the current token } buf ptr2 : buf pointer ; { used to find the end of the current token }

82. These macros send the current token, in buffer [buf ptr1 ] to buffer [buf ptr2 − 1], to an output file. define print token ≡ print a token { making this a procedure saves a little space } define trace pr token ≡

begin out token(log file); end

83. And here are the associated procedures. Note: The term out file is system dependent. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure out token(var f : alpha file);

var i: buf pointer ;

begin i ← buf ptr1 ;

while (i < buf ptr2 ) do begin write(f, xchr [buffer [i]]); incr (i); end;

end; procedure print a token;

begin out token(term out ); out token(log file);

end;

84. This function scans the buffer for the next token, starting at the global variable buf ptr2 and ending just before either the single specified stop-character or the end of the current line, whichever comes first, respectively returning true or false; afterward, scan char is the first character following this token. ⟨ Procedures and functions for input scanning 84 ⟩ ≡ function scan1 (char1 : ASCII code): boolean;

begin buf ptr1 ← buf ptr2 ; { scan until end-of-line or the specified character } while ((scan char ≠ char1 ) ∧ (buf ptr2 < last )) do incr (buf ptr2 ); if (buf ptr2 < last ) then scan1 ← true else scan1 ← false; end;

See also sections 85, 86, 87, 88, 89, 91, 93, 94, 95, 153, 184, 185, 186, 187, 188, 229, 249, and 250. This code is used in section 12.

§85 BibTEX SCANNING AN INPUT LINE 29

85. This function is the same but stops at white space characters as well. ⟨ Procedures and functions for input scanning 84 ⟩ +≡ function scan1 white(char1 : ASCII code): boolean;

begin buf ptr1 ← buf ptr2 ; { scan until end-of-line, the specified character, or white space } while ((lex class [scan char ] ≠ white space) ∧ (scan char ≠ char1 ) ∧ (buf ptr2 < last )) do

incr (buf ptr2 ); if (buf ptr2 < last ) then scan1 white ← true else scan1 white ← false; end;

86. This function is similar to scan1 , but stops at either of two stop-characters as well as the end of the current line. ⟨ Procedures and functions for input scanning 84 ⟩ +≡ function scan2 (char1 , char2 : ASCII code): boolean;

begin buf ptr1 ← buf ptr2 ; { scan until end-of-line or the specified characters } while ((scan char ≠ char1 ) ∧ (scan char ≠ char2 ) ∧ (buf ptr2 < last )) do incr (buf ptr2 ); if (buf ptr2 < last ) then scan2 ← true else scan2 ← false; end;

87. This function is the same but stops at white space characters as well. ⟨ Procedures and functions for input scanning 84 ⟩ +≡ function scan2 white(char1 , char2 : ASCII code): boolean;

begin buf ptr1 ← buf ptr2 ; { scan until end-of-line, the specified characters, or white space } while ((scan char ≠ char1 )∧(scan char ≠ char2 )∧(lex class [scan char ] ≠ white space)∧(buf ptr2 < last ))

do incr (buf ptr2 ); if (buf ptr2 < last ) then scan2 white ← true else scan2 white ← false; end;

88. This function is similar to scan2 , but stops at either of three stop-characters as well as the end of the current line. ⟨ Procedures and functions for input scanning 84 ⟩ +≡ function scan3 (char1 , char2 , char3 : ASCII code): boolean;

begin buf ptr1 ← buf ptr2 ; { scan until end-of-line or the specified characters } while ((scan char ≠ char1 ) ∧ (scan char ≠ char2 ) ∧ (scan char ≠ char3 ) ∧ (buf ptr2 < last )) do

incr (buf ptr2 ); if (buf ptr2 < last ) then scan3 ← true else scan3 ← false; end;

89. This function scans for letters, stopping at the first nonletter; it returns true if there is at least one letter. ⟨ Procedures and functions for input scanning 84 ⟩ +≡ function scan alpha: boolean;

begin buf ptr1 ← buf ptr2 ; { scan until end-of-line or a nonletter } while ((lex class [scan char ] = alpha) ∧ (buf ptr2 < last )) do incr (buf ptr2 ); if (token len = 0) then scan alpha ← false else scan alpha ← true; end; 90. These are the possible values for scan result ; they’re set by the scan identifier procedure and are described in the next section.

define id null = 0

define specified char adjacent = 1

define other char adjacent = 2

define white adjacent = 3 ⟨ Globals in the outer block 16 ⟩ +≡ scan result : id null . . white adjacent ;

91. This procedure scans for an identifier, stopping at the first illegal id char , or stopping at the first character if it’s numeric. It sets the global variable scan result to id null if the identifier is null, else to white adjacent if it ended at a white space character or an end-of-line, else to specified char adjacent if it ended at one of char1 or char2 or char3 , else to other char adjacent if it ended at a nonspecified, nonwhite space illegal id char . By convention, when some calling code really wants just one or two “specified” characters, it merely repeats one of the characters. ⟨ Procedures and functions for input scanning 84 ⟩ +≡ procedure scan identifier (char1 , char2 , char3 : ASCII code);

begin buf ptr1 ← buf ptr2 ;

if (lex class [scan char ] ≠ numeric) then { scan until end-of-line or an illegal id char }

while ((id class [scan char ] = legal id char ) ∧ (buf ptr2 < last )) do incr (buf ptr2 ); if (token len = 0) then scan result ← id null else if ((lex class [scan char ] = white space) ∨ (buf ptr2 = last )) then scan result ← white adjacent

else if ((scan char = char1 ) ∨ (scan char = char2 ) ∨ (scan char = char3 )) then

scan result ← specified char adjacent else scan result ← other char adjacent ;

end;

92. The next two procedures scan for an integer, setting the global variable token value to the corresponding integer.

define char value ≡ (scan char − ) { the value of the digit being scanned } ⟨ Globals in the outer block 16 ⟩ +≡ token value: integer ; { the numeric value of the current token }

93. This function scans for a nonnegative integer, stopping at the first nondigit; it sets the value of token value accordingly. It returns true if the token was a legal nonnegative integer (i.e., consisted of one or more digits). ⟨ Procedures and functions for input scanning 84 ⟩ +≡ function scan nonneg integer : boolean;

begin buf ptr1 ← buf ptr2 ; token value ← 0; { scan until end-of-line or a nondigit } while ((lex class [scan char ] = numeric) ∧ (buf ptr2 < last )) do

begin token value ← token value ∗ 10 + char value; incr (buf ptr2 );

end; if (token len = 0) then { there were no digits }

scan nonneg integer ← false else scan nonneg integer ← true; end; 94. This procedure scans for an integer, stopping at the first nondigit; it sets the value of token value accordingly. It returns true if the token was a legal integer (i.e., consisted of an optional minus sign followed by one or more digits).

define negative ≡ (sign length = 1) { if this integer is negative } ⟨ Procedures and functions for input scanning 84 ⟩ +≡ function scan integer : boolean;

var sign length: 0 . . 1; { 1 if there’s a minus sign, 0 if not } begin buf ptr1 ← buf ptr2 ; if (scan char = minus sign) then { it’s a negative number }

begin sign length ← 1; incr (buf ptr2 ); { skip over the minus sign } end

else sign length ← 0; token value ← 0; { scan until end-of-line or a nondigit } while ((lex class [scan char ] = numeric) ∧ (buf ptr2 < last )) do

begin token value ← token value ∗ 10 + char value; incr (buf ptr2 ); end;

if (negative) then token value ← −token value; if (token len = sign length) then { there were no digits }

scan integer ← false else scan integer ← true; end;

95. This function scans over white space characters, stopping either at the first nonwhite character or the end of the line, respectively returning true or false. ⟨ Procedures and functions for input scanning 84 ⟩ +≡ function scan white space: boolean;

begin { scan until end-of-line or a nonwhite } while ((lex class [scan char ] = white space) ∧ (buf ptr2 < last )) do incr (buf ptr2 ); if (buf ptr2 < last ) then scan white space ← true else scan white space ← false; end; 96. The print bad input line procedure prints the current input line, splitting it at the character being scanned: It prints buffer [0], buffer [1], …, buffer [buf ptr2 − 1] on one line and buffer [buf ptr2 ], …, buffer [last − 1] on the next (and both lines start with a colon between two spaces). Each white space character is printed as a space. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure print bad input line;

var bf ptr : buf pointer ; begin print (´ ␣ ␣´ ); bf ptr ← 0; while (bf ptr < buf ptr2 ) do

begin if (lex class [buffer [bf ptr ]] = white space) then print (xchr [space])

else print (xchr [buffer [bf ptr ]]);

incr (bf ptr );

end; print newline; print (´ ␣ ␣´ ); bf ptr ← 0; while (bf ptr < buf ptr2 ) do

begin print (xchr [space]); incr (bf ptr );

end; bf ptr ← buf ptr2 ; while (bf ptr < last ) do

begin if (lex class [buffer [bf ptr ]] = white space) then print (xchr [space])

else print (xchr [buffer [bf ptr ]]);

incr (bf ptr );

end; print newline; bf ptr ← 0; while ((bf ptr < buf ptr2 ) ∧ (lex class [buffer [bf ptr ]] = white space)) do incr (bf ptr ); if (bf ptr = buf ptr2 ) then print ln(´ ␣ ␣ ␣ ␣ ␣ ␣ ´ ); mark error ; end;

97. This little procedure exists because it’s used by at least two other procedures and thus saves some space. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure print skipping whatever remains ;

§98 BibTEX GETTING THE TOP-LEVEL AUXILIARY FILE NAME 33

begin print (´ ´ ´ ␣ ␣ ␣ ␣ ␣ ␣´ ); end; 98* . Getting the top-level auxiliary file name. These modules read the name of the top-level file. Some systems will try to find this on the command line; if it’s not there it will come from the user’s terminal. In either case, the name goes into the char array name of file, and the files relevant to this name are opened.

define aux found = 41 { go here when the name is legit }

define aux not found = 46 { go here when it’s not } ⟨ Globals in the outer block 16 ⟩ +≡ aux name length: integer ;

99. I mean, this is truly disgraceful. A user has to type something in to the terminal just once during the entire run. And it’s not some complicated string where you have to get every last punctuation mark just right, and it’s not some fancy list where you get nervous because if you forget one item you have to type the whole thing again; it’s just a simple, ordinary, file name. Now you’d think a five-year-old could do it; you’d think it’s so simple a user should be able to do it in his sleep. But noooooooooo. He had to sit there droning on and on about who knows what until he exceeded the bounds of common sense, and he probably didn’t even realize it. Just pitiful. What’s this world coming to? We should probably just delete all his files and be done with him. Note: The term out file is system dependent.

define sam you made the file name too long ≡ begin sam too long file name print ; goto aux not found ; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure sam too long file name print ;

begin write(term out , ´ ␣ ␣` ´ ); name ptr ← 1;

while (name ptr ≤ aux name length) do begin write(term out , name of file[name ptr ]); incr (name ptr ); end;

write ln(term out , ´ ´ ´ ␣ ␣ ␣ ´ );

end;

100. We’ve abused the user enough for one section; suffice it to say here that most of what we said last module still applies. Note: The term out file is system dependent.

define sam you made the file name wrong ≡ begin sam wrong file name print ; goto aux not found ; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure sam wrong file name print ;

begin write(term out , ´ ␣ ´ ´ ␣ ␣ ␣ ␣` ´ ); name ptr ← 1; while (name ptr ≤ name length) do

begin write(term out , name of file[name ptr ]); incr (name ptr ); end;

write ln(term out , ´ ´ ´ ´ );

34  GETTING THE TOP-LEVEL AUXILIARY FILE NAME  BibTEX §101

end; 101* . ⟨ Procedures and functions for the reading and processing of input files 101* ⟩ ≡ procedure get the top level aux file name;

label aux found , aux not found ;

begin loop

begin { initialize the path variables }

set paths (BIB INPUT PATH BIT + TEX INPUT PATH BIT ); if (argc > 1) then ⟨ Process a possible command line 103* ⟩ else begin write(term out , ´ ␣ ␣ ␣ ␣ ␣ ␣ ´ );

aux name length ← 0; while (¬eoln(term in)) do

begin if (aux name length = file name size) then begin readln(term in); sam you made the file name too long ; end;

name of file[aux name length + 1] ← getc(term in); incr (aux name length); end;

if (eof (term in)) then begin writeln(term out ); writeln(term out , ´ ␣ ␣ ␣ ␣ ␣ ␣ ´ ); uexit (1); end;

readln(term in);

end; ⟨ Handle this name 104 ⟩;

aux not found : argc ← 0;

end; aux found : { now we’re ready to read the file }

end;

See also sections 121, 127, 133, 140, 143, 144, 146, 171, 178, 179, 181, 202, 204, 206, 211, 212, 213, 215, 216, and 218. This code is used in section 12.

102* . The switch check cmnd line tells us whether we’re to check for a possible command-line argument.

103* . Here’s where we do the real command-line work. Those systems needing more than a single module to handle the task should add the extras to the “System-dependent changes” section. ⟨ Process a possible command line 103* ⟩ ≡

begin argv (1, name of file); aux name length ← 1;

while name of file[aux name length] ≠ ´ ␣´ do incr (aux name length); decr (aux name length); end

This code is used in section 101*.

104. Here we orchestrate this name’s handling: we add the various extensions, try to open the files with the resulting name, and store the name strings we’ll need later. ⟨ Handle this name 104 ⟩ ≡

begin if ((aux name length + length(s aux extension) > file name size) ∨ (aux name length + length(s log extension) > file name size) ∨ (aux name length + length(s bbl extension) > file name size)) then

sam you made the file name too long ; ⟨ Add extensions and open files 107* ⟩; ⟨ Put this name into the hash table 108 ⟩; goto aux found ; end

This code is used in section 101*.

105. Here we set up definitions and declarations for files opened in this section. Each element in aux list (except for aux list [aux stack size], which is always unused) is a pointer to the appropriate str pool string representing the file name. The array aux file contains the corresponding PASCAL file variables.

define cur aux str ≡ aux list [aux ptr ] { shorthand for the current file }

define cur aux file ≡ aux file[aux ptr ] { shorthand for the current aux file }

define cur aux line ≡ aux ln stack [aux ptr ] { line number of current file } ⟨ Globals in the outer block 16 ⟩ +≡ aux file: array [aux number ] of alpha file; { open file variables } aux list : array [aux number ] of str number ; { the open file list } aux ptr : aux number ; { points to the currently open file } aux ln stack : array [aux number ] of integer ; { open line numbers } top lev str : str number ; { the top-level file’s name } log file: alpha file; { the file variable for the file } bbl file: alpha file; { the file variable for the file }

106. Where aux number is the obvious. ⟨ Types in the outer block 22 ⟩ +≡

aux number = 0 . . aux stack size; { gives the aux list range }

107* . We must make sure the (top-level)  ,  , and  files can be opened.

⟨ Add extensions and open files 107* ⟩ ≡ begin name length ← aux name length; { set to last used position } add extension(s aux extension); { this also sets name length } aux ptr ← 0; { initialize the file stack } if (¬a open in(cur aux file, no file path)) then sam you made the file name wrong ; name length ← aux name length; add extension(s log extension); { this also sets name length } if (¬a open out (log file)) then sam you made the file name wrong ; name length ← aux name length; add extension(s bbl extension); { this also sets name length } if (¬a open out (bbl file)) then sam you made the file name wrong ; end

This code is used in section 104.

108. This code puts the file name, both with and without the extension, into the hash table, and it initializes aux list . Note that all previous top-level -file stuff must have been successful. ⟨ Put this name into the hash table 108 ⟩ ≡

begin name length ← aux name length; add extension(s aux extension); { this also sets name length } name ptr ← 1; while (name ptr ≤ name length) do

begin buffer [name ptr ] ← xord [name of file[name ptr ]]; incr (name ptr ); end;

top lev str ← hash text [str lookup(buffer , 1, aux name length, text ilk , do insert )]; cur aux str ← hash text [str lookup(buffer , 1, name length, aux file ilk , do insert )];

{ note that this has initialized aux list } if (hash found ) then

begin trace print aux name;

ecart

confusion(´ ␣ ␣ ␣ ´ );

end; cur aux line ← 0; { this finishes initializing the top-level file } end

This code is used in section 104.

109. Print the name of the current file, followed by a newline. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure print aux name;

§110 BibTEX READING THE AUXILIARY FILE(S) 37

begin print pool str (cur aux str ); print newline; end; 110. Reading the auxiliary file(s). Now it’s time to read the file. The only commands we handle are (there can be arbitrarily many, each having arbitrarily many arguments), (there can be just one, but it can have arbitrarily many arguments), (there can be just one, and it can have just one argument), and (there can be arbitrarily many, each with one argument, and they can be nested to a depth of aux stack size). Each of these commands is assumed to be on just a single line. The rest of the file is ignored.

define aux done = 31 { go here when finished with the files } ⟨ Labels in the outer block 110 ⟩ ≡

, aux done

See also section 147. This code is used in section 10.

111. We keep reading and processing input lines until none left. This is part of the main program; hence, because of the aux done label, there’s no conventional begin - end pair surrounding the entire module. ⟨ Read the file 111 ⟩ ≡

print (´ ␣ ␣ ␣ ␣´ ); print aux name; loop

begin { pop the aux stack will exit the loop }

incr (cur aux line);

if (¬input ln(cur aux file)) then { end of current file }

pop the aux stack else get aux command and process ; end;

trace trace pr ln(´ ␣ ␣ ␣ ␣ ´ ); ecart

aux done: last check for aux errors ;

This code is used in section 10.

112. When we find a bug, we print a message and flush the rest of the line. This macro must be called from within a procedure that has an exit label.

define aux err return ≡ begin aux err print ; return; { flush this input line } end

define aux err (#) ≡ begin print (#); aux err return; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure aux err print ;

38  READING THE AUXILIARY FILE(S)  BibTEX §113

begin print (´ ␣´ , cur aux line : 0, ´ ␣ ␣ ␣´ ); print aux name; print bad input line; { this call does the mark error } print skipping whatever remains ; print ln(´ ´ ) end; 113. Here are a bunch of macros whose print statements are used at least twice. Thus we save space by making the statements procedures. This macro complains when there’s a repeated command that’s to be used just once.

define aux err illegal another (#) ≡ begin aux err illegal another print (#); aux err return; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure aux err illegal another print (cmd num : integer );

begin print (´ ␣ ␣ ´ ); case (cmd num) of n aux bibdata: print (´ ´ ); n aux bibstyle: print (´ ´ ); othercases confusion(´ ␣ ␣ ´ ) endcases; print (´ ␣ ´ ); end;

114. This one complains when a command is missing its right brace.

define aux err no right brace ≡ begin aux err no right brace print ; aux err return; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure aux err no right brace print ;

begin print (´ ␣ ´ , xchr [right brace], ´ ´ ); end;

115. This one complains when a command has stuff after its right brace.

define aux err stuff after right brace ≡ begin aux err stuff after right brace print ; aux err return; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure aux err stuff after right brace print ;

begin print (´ ␣ ␣ ´ , xchr [right brace], ´ ´ ); end;

116. And this one complains when a command has white space in its argument.

define aux err white space in argument ≡ begin aux err white space in argument print ; aux err return; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure aux err white space in argument print ;

begin print (´ ␣ ␣ ␣ ´ ); end; 117. We’re not at the end of an file, so we see if the current line might be a command of interest. A command of interest will be a line without blanks, consisting of a command name, a left brace, one or more arguments separated by commas, and a right brace. ⟨ Scan for and process an command 117 ⟩ ≡ procedure get aux command and process ;

label exit ;

begin buf ptr2 ← 0; { mark the beginning of the next token }

if (¬scan1 (left brace)) then { no left brace—flush line }

return; command num ← ilk info[str lookup(buffer , buf ptr1 , token len, aux command ilk , dont insert )]; if (hash found ) then

case (command num) of

n aux bibdata: aux bib data command ; n aux bibstyle: aux bib style command ; n aux citation: aux citation command ; n aux input : aux input command ; othercases confusion(´ ␣ ␣ ´ ) endcases;

exit : end;

This code is used in section 144.

118. Here we introduce some variables for processing a command. Each element in bib list (except for bib list [max bib files ], which is always unused) is a pointer to the appropriate str pool string representing the file name. The array bib file contains the corresponding PASCAL file variables.

define cur bib str ≡ bib list [bib ptr ] { shorthand for current file }

define cur bib file ≡ bib file[bib ptr ] { shorthand for current bib file } ⟨ Globals in the outer block 16 ⟩ +≡ bib list : array [bib number ] of str number ; { the file list } bib ptr : bib number ; { pointer for the current file } num bib files : bib number ; { the total number of files } bib seen: boolean; { true if we’ve already seen a command } bib file: array [bib number ] of alpha file; { corresponding file variables }

119. Where bib number is the obvious. ⟨ Types in the outer block 22 ⟩ +≡

bib number = 0 . . max bib files ; { gives the bib list range }

120. ⟨ Set initial values of key variables 20 ⟩ +≡

bib ptr ← 0; { this makes bib list empty }

bib seen ← false; { we haven’t seen a command yet } 121. A command will have its arguments between braces and separated by commas. There must be exactly one such command in the file(s). All upper-case letters are converted to lower case. ⟨ Procedures and functions for the reading and processing of input files 101* ⟩ +≡ procedure aux bib data command ;

label exit ;

begin if (bib seen) then aux err illegal another (n aux bibdata);

bib seen ← true; { now we’ve seen a command }

while (scan char ≠ right brace) do begin incr (buf ptr2 ); { skip over the previous stop-character } if (¬scan2 white(right brace, comma)) then aux err no right brace; if (lex class [scan char ] = white space) then aux err white space in argument ; if ((last > buf ptr2 + 1) ∧ (scan char = right brace)) then aux err stuff after right brace; ⟨ Open a file 124* ⟩; end;

exit : end;

122. Here’s a procedure we’ll need shortly. It prints the name of the current file, followed by a newline. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure print bib name;

begin print pool str (cur bib str ); print pool str (s bib extension); print newline;

end;

123. This macro is similar to aux err but it complains specifically about opening a file for a command.

define open bibdata aux err (#) ≡ begin print (#); print bib name; aux err return; { this does the mark error } end

124* . Now we add the just-found argument to bib list if it hasn’t already been encountered as a argument and if, after appending the s bib extension string, the resulting file name can be opened. ⟨ Open a file 124* ⟩ ≡

begin if (bib ptr = max bib files ) then overflow (´ ␣ ␣ ␣ ␣´ , max bib files ); cur bib str ← hash text [str lookup(buffer , buf ptr1 , token len, bib file ilk , do insert )]; if (hash found ) then { already encountered this as a argument }

open bibdata aux err (´ ␣ ␣ ␣ ␣ ␣ ␣ ␣´ ); start name(cur bib str ); add extension(s bib extension); if (¬a open in(cur bib file, BIB INPUT PATH )) then

open bibdata aux err (´ ␣ ´ ´ ␣ ␣ ␣ ␣´ ); trace trace pr pool str (cur bib str ); trace pr pool str (s bib extension); trace pr ln(´ ␣ ␣ ␣ ␣ ´ ); ecart incr (bib ptr ); end

This code is used in section 121.

125. Here we introduce some variables for processing a command. ⟨ Globals in the outer block 16 ⟩ +≡ bst seen: boolean; { true if we’ve already seen a command } bst str : str number ; { the string number for the file } bst file: alpha file; { the corresponding file variable } 126. And we initialize. ⟨ Set initial values of key variables 20 ⟩ +≡

bst str ← 0; { mark bst str as unused } bst seen ← false; { we haven’t seen a command yet }

127. A command will have exactly one argument, and it will be between braces. There must be exactly one such command in the file(s). All upper-case letters are converted to lower case. ⟨ Procedures and functions for the reading and processing of input files 101* ⟩ +≡ procedure aux bib style command ;

label exit ; begin if (bst seen) then aux err illegal another (n aux bibstyle); bst seen ← true; { now we’ve seen a command } incr (buf ptr2 ); { skip over the left brace } if (¬scan1 white(right brace)) then aux err no right brace; if (lex class [scan char ] = white space) then aux err white space in argument ; if (last > buf ptr2 + 1) then aux err stuff after right brace; ⟨ Open the file 128* ⟩;

exit : end;

128* . Now we open the file whose name is the just-found argument appended with the s bst extension string, if possible. ⟨ Open the file 128* ⟩ ≡

begin bst str ← hash text [str lookup(buffer , buf ptr1 , token len, bst file ilk , do insert )]; if (hash found ) then

begin trace print bst name;

ecart

confusion(´ ␣ ␣ ␣ ´ );

end; start name(bst str ); add extension(s bst extension); if (¬a open in(bst file, TEX INPUT PATH )) then

begin print (´ ␣ ´ ´ ␣ ␣ ␣ ␣´ ); print bst name; bst str ← 0; { mark as unused again } aux err return; end;

print (´ ␣ ␣ ␣´ ); print bst name; end

This code is used in section 127.

129. Print the name of the file, followed by a newline. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure print bst name;

begin print pool str (bst str ); print pool str (s bst extension); print newline; end; 130. Here we introduce some variables for processing a command. Each element in cite list (except for cite list [max cites ], which is always unused) is a pointer to the appropriate str pool string. The cite-key list is kept in order of occurrence with duplicates removed.

define cur cite str ≡ cite list [cite ptr ] { shorthand for the current cite key } ⟨ Globals in the outer block 16 ⟩ +≡ cite list : packed array [cite number ] of str number ; { the cite-key list } cite ptr : cite number ; { pointer for the current cite key } entry cite ptr : cite number ; { cite pointer for the current entry } num cites : cite number ; { the total number of distinct cite keys } old num cites : cite number ; { set to a previous num cites value } citation seen: boolean; { true if we’ve seen a command } cite loc: hash loc; { the hash-table location of a cite key } lc cite loc: hash loc; { and of its lower-case equivalent } lc xcite loc: hash loc; { a second lc cite loc variable } cite found : boolean; { true if we’ve already seen this cite key } all entries : boolean; { true if we’re to use the entire database } all marker : cite number ; { we put the other entries in cite list here }

131. Where cite number is the obvious. ⟨ Types in the outer block 22 ⟩ +≡

cite number = 0 . . max cites ; { gives the cite list range }

132. ⟨ Set initial values of key variables 20 ⟩ +≡

cite ptr ← 0; { this makes cite list empty }

citation seen ← false; { we haven’t seen a command yet }

all entries ← false; { by default, use just the entries explicitly named }

133. A command will have its arguments between braces and separated by commas. Upper/lower cases are considered to be different for arguments, which is the same as the rest of LaTEX but different from the rest of BibTEX. A cite key needn’t exactly case-match its corresponding database key to work, although two cite keys that are case-mismatched will produce an error message. (A case mismatch is a mismatch, but only because of a case difference.)

A command having as an argument indicates that the entire database will be included (almost as if a command that listed every cite key in the database, in order, had been given at the corresponding spot in the file).

define next cite = 23 { read the next argument } ⟨ Procedures and functions for the reading and processing of input files 101* ⟩ +≡ procedure aux citation command ;

label next cite, exit ;

begin citation seen ← true; { now we’ve seen a command }

while (scan char ≠ right brace) do begin incr (buf ptr2 ); { skip over the previous stop-character } if (¬scan2 white(right brace, comma)) then aux err no right brace; if (lex class [scan char ] = white space) then aux err white space in argument ; if ((last > buf ptr2 + 1) ∧ (scan char = right brace)) then aux err stuff after right brace; ⟨ Check the cite key 134 ⟩;

next cite: end; exit : end; 134. We must check if (the lower-case version of) this cite key has been previously encountered, and proceed accordingly. The alias kludge helps make the stack space not overflow on some machines.

define ex buf1 ≡ ex buf { an alias, used only in this module } ⟨ Check the cite key 134 ⟩ ≡

begin trace trace pr token; trace pr (´ ␣ ␣ ␣ ´ ); ecart ⟨ Check for entire database inclusion (and thus skip this cite key) 135 ⟩; tmp ptr ← buf ptr1 ; while (tmp ptr < buf ptr2 ) do

begin ex buf1 [tmp ptr ] ← buffer [tmp ptr ]; incr (tmp ptr );

end; lower case(ex buf1 , buf ptr1 , token len); { convert to ‘canonical’ form } lc cite loc ← str lookup(ex buf1 , buf ptr1 , token len, lc cite ilk , do insert ); if (hash found ) then { already encountered this as a argument }

⟨ Cite seen, don’t add a cite key 136 ⟩ else ⟨ Cite unseen, add a cite key 137 ⟩; { it’s a new cite key—add it to cite list } end

This code is used in section 133.

135. Here we check for a command having as an argument, indicating that the entire database will be included. ⟨ Check for entire database inclusion (and thus skip this cite key) 135 ⟩ ≡

begin if (token len = 1) then

if (buffer [buf ptr1 ] = star ) then begin trace trace pr ln(´ ␣ ␣ ␣ ␣ ´ ); ecart if (all entries ) then

begin print ln(´ ␣ ␣ ␣ ␣ ´ ); aux err return; end

else begin all entries ← true; all marker ← cite ptr ; goto next cite;

end; end;

end

This code is used in section 134.

136. We’ve previously encountered the lower-case version, so we check that the actual version exactly matches the actual version of the previously-encountered cite key(s). ⟨ Cite seen, don’t add a cite key 136 ⟩ ≡

begin trace trace pr ln(´ ␣ ´ ); ecart dummy loc ← str lookup(buffer , buf ptr1 , token len, cite ilk , dont insert ); if (¬hash found ) then { case mismatch error }

begin print (´ ␣ ␣ ␣ ␣ ␣ ␣´ ); print token; print (´ ␣ ␣´ ); print pool str (cite list [ilk info[ilk info[lc cite loc]]]); print newline; aux err return; end;

end

This code is used in section 134.

137. Now we add the just-found argument to cite list if there isn’t anything funny happening. ⟨ Cite unseen, add a cite key 137 ⟩ ≡

begin trace trace pr newline; ecart cite loc ← str lookup(buffer , buf ptr1 , token len, cite ilk , do insert ); if (hash found ) then hash cite confusion; check cite overflow (cite ptr ); cur cite str ← hash text [cite loc]; ilk info[cite loc] ← cite ptr ; ilk info[lc cite loc] ← cite loc; incr (cite ptr ); end

This code is used in section 134.

138. Here’s a serious complaint (that is, a bug) concerning hash problems. This is the first of several similar bug-procedures that exist only because they save space. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure hash cite confusion;

begin confusion(´ ␣ ␣ ´ ); end;

139. Complain if somebody’s got a cite fetish. This procedure is called when were about to add another cite key to cite list . It assumes that cite loc gives the potential cite key’s hash table location. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure check cite overflow (last cite : cite number );

begin if (last cite = max cites ) then begin print pool str (hash text [cite loc]); print ln(´ ␣ ␣ ␣ ´ ); overflow (´ ␣ ␣ ␣ ␣´ , max cites ); end;

end;

140. An command will have exactly one argument, it will be between braces, and it must have the s aux extension. All upper-case letters are converted to lower case. ⟨ Procedures and functions for the reading and processing of input files 101* ⟩ +≡ procedure aux input command ;

label exit ; var aux extension ok : boolean; { to check for a correct file extension } begin incr (buf ptr2 ); { skip over the left brace } if (¬scan1 white(right brace)) then aux err no right brace; if (lex class [scan char ] = white space) then aux err white space in argument ; if (last > buf ptr2 + 1) then aux err stuff after right brace; ⟨ Push the stack 141 ⟩;

exit : end; 141. We must check that this potential file won’t overflow the stack, that it has the correct extension, that we haven’t encountered it before (to prevent, among other things, an infinite loop). ⟨ Push the stack 141 ⟩ ≡

begin incr (aux ptr ); if (aux ptr = aux stack size) then

begin print token; print (´ ␣´ ); overflow (´ ␣ ␣ ␣´ , aux stack size); end;

aux extension ok ← true; if (token len < length(s aux extension)) then

aux extension ok ← false { else str eq buf might bomb the program } else if (¬str eq buf (s aux extension, buffer , buf ptr2 − length(s aux extension), length(s aux extension)))

then aux extension ok ← false;

if (¬aux extension ok ) then begin print token; print (´ ␣ ␣ ␣ ␣ ´ ); decr (aux ptr ); aux err return; end;

cur aux str ← hash text [str lookup(buffer , buf ptr1 , token len, aux file ilk , do insert )]; if (hash found ) then

begin print (´ ␣ ␣ ␣´ ); print aux name; decr (aux ptr ); aux err return; end;

⟨ Open this file 142* ⟩; end

This code is used in section 140.

142* . We check that this file can actually be opened, and then open it. ⟨ Open this file 142* ⟩ ≡

begin start name(cur aux str ); { extension already there for files } name ptr ← name length + 1; while (name ptr ≤ file name size) do { pad with blanks }

begin name of file[name ptr ] ← ´ ␣´ ; incr (name ptr );

end; if (¬a open in(cur aux file, no file path)) then

begin print (´ ␣ ´ ´ ␣ ␣ ␣ ␣´ ); print aux name; decr (aux ptr ); aux err return; end;

print (´ ␣ ´ , aux ptr : 0, ´ ␣ ␣ ␣´ ); print aux name; cur aux line ← 0; end

This code is used in section 141.

143. Here we close the current-level file and go back up a level, if possible, by decrementing aux ptr . ⟨ Procedures and functions for the reading and processing of input files 101* ⟩ +≡ procedure pop the aux stack ;

begin a close(cur aux file); if (aux ptr = 0) then goto aux done else decr (aux ptr ); end;

144. That’s it for processing commands, except for finishing the procedural gymnastics. ⟨ Procedures and functions for the reading and processing of input files 101* ⟩ +≡

⟨ Scan for and process an command 117 ⟩ 145. We must complain if anything’s amiss.

define aux end err (#) ≡ begin aux end1 err print ; print (#); aux end2 err print ; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure aux end1 err print ;

begin print (´ ␣ ␣ ␣´ ); end;

procedure aux end2 err print ; begin print (´ ␣ ␣ ␣´ ); print aux name; mark error ; end;

146. Before proceeding, we see if we have any complaints. ⟨ Procedures and functions for the reading and processing of input files 101* ⟩ +≡ procedure last check for aux errors ;

§147 BibTEX READING THE STYLE FILE 47

begin num cites ← cite ptr ; { record the number of distinct cite keys } num bib files ← bib ptr ; { and the number of files } if (¬citation seen) then aux end err (´ ␣ ´ ) else if ((num cites = 0) ∧ (¬all entries )) then aux end err (´ ␣ ´ ); if (¬bib seen) then aux end err (´ ␣ ´ ) else if (num bib files = 0) then aux end err (´ ␣ ´ ); if (¬bst seen) then aux end err (´ ␣ ´ ) else if (bst str = 0) then aux end err (´ ␣ ´ ); end; 147. Reading the style file. This part of the program reads the file, which consists of a sequence of commands. Each command consists of a name (for which case differences are ignored) followed by zero or more arguments, each enclosed in braces.

define bst done = 32 { go here when finished with the file }

define no bst file = 9932 { go here when skipping the file } ⟨ Labels in the outer block 110 ⟩ +≡

, bst done, no bst file

148. The bbl line num gets initialized along with the bst line num, so it’s declared here too. ⟨ Globals in the outer block 16 ⟩ +≡ bbl line num: integer ; { line number of the (output) file } bst line num: integer ; { line number of the file }

149. This little procedure exists because it’s used by at least two other procedures and thus saves some space. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure bst ln num print ;

begin print (´ ␣´ , bst line num : 0, ´ ␣ ␣ ␣´ ); print bst name;

end;

150. When there’s a serious error parsing the file, we flush the rest of the current command; a blank line is assumed to mark the end of a command (but for the purposes of error recovery only). Thus, error recovery will be better if style designers leave blank lines between commands. This macro must be called from within a procedure that has an exit label.

define bst err print and look for blank line return ≡ begin bst err print and look for blank line; return; end

define bst err (#) ≡ begin { serious error during parsing } print (#); bst err print and look for blank line return; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure bst err print and look for blank line;

begin print (´ ´ ); bst ln num print ; print bad input line; { this call does the mark error } while (last ≠ 0) do { look for a blank input line }

if (¬input ln(bst file)) then { or the end of the file }

goto bst done

48  READING THE STYLE FILE  BibTEX §151

else incr (bst line num); buf ptr2 ← last ; { to input the next line } end; 151. When there’s a harmless error parsing the file (harmless syntactically, at least) we give just a warning message.

define bst warn(#) ≡ begin { non-serious error during parsing } print (#); bst warn print ; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure bst warn print ;

begin bst ln num print ; mark warning ;

end;

152* . Here’s the outer loop for reading the  file—it keeps reading and processing  commands until

none left. This is part of the main program; hence, because of the bst done label, there’s no conventional begin - end pair surrounding the entire module. ⟨ Read and execute the file 152* ⟩ ≡

if (bst str = 0) then { there’s no file to read }

goto no bst file; { this is a goto so that bst done is not in a block } bst line num ← 0; { initialize things } bbl line num ← 1; { best spot to initialize the output line number } buf ptr2 ← last ; { to get the first input line } hack1 ; begin if (¬eat bst white space) then { the end of the file }

hack2 ; get bst command and process ; end;

bst done: a close(bst file); no bst file: a close(bbl file);

This code is used in section 10.

153. This -specific scanning function skips over white space characters (and comments) until hitting a nonwhite character or the end of the file, respectively returning true or false. It also updates bst line num, the line counter. ⟨ Procedures and functions for input scanning 84 ⟩ +≡ function eat bst white space: boolean;

label exit ;

begin loop

begin if (scan white space) then { hit a nonwhite character on this line } if (scan char ≠ comment ) then { it’s not a comment character; return }

begin eat bst white space ← true; return; end;

if (¬input ln(bst file)) then { end-of-file; return false } begin eat bst white space ← false; return; end;

incr (bst line num); buf ptr2 ← 0;

end; exit : end; 154. It’s often illegal to end a command in certain places, and this is where we come to check.

define eat bst white and eof check (#) ≡

begin if (¬eat bst white space) then begin eat bst print ; bst err (#); end; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure eat bst print ;

begin print (´ ␣ ␣ ␣ ␣ ␣ ␣ ␣´ ); end;

155. We must attend to a few details before getting to work on this command. ⟨ Scan for and process a command 155 ⟩ ≡ procedure get bst command and process ;

label exit ; begin if (¬scan alpha) then bst err (´ ´ , xchr [scan char ], ´ ␣ ´ ´ ␣ ␣ ␣ ␣ ´ ); lower case(buffer , buf ptr1 , token len); { ignore case differences } command num ← ilk info[str lookup(buffer , buf ptr1 , token len, bst command ilk , dont insert )]; if (¬hash found ) then

begin print token; bst err (´ ␣ ␣ ␣ ␣ ␣ ´ ); end;

⟨ Process the appropriate command 156 ⟩; exit : end;

This code is used in section 218.

156. Here we determine which command we’re about to process, and then go to it. ⟨ Process the appropriate command 156 ⟩ ≡

case (command num) of n bst entry : bst entry command ; n bst execute: bst execute command ; n bst function: bst function command ; n bst integers : bst integers command ; n bst iterate: bst iterate command ; n bst macro: bst macro command ; n bst read : bst read command ; n bst reverse: bst reverse command ; n bst sort : bst sort command ; n bst strings : bst strings command ; othercases confusion(´ ␣ ␣ ´ ) endcases

This code is used in section 155.

157. We need data structures for the function definitions, the entry variables, the global variables, and the actual entries corresponding to the cite-key list. First we define the classes of ‘function’s used. Functions in all classes are of bst fn ilk except for int literal s, which are of integer ilk ; and str literal s, which are of text ilk .

define built in = 0 { the ‘primitive’ functions } define wiz defined = 1 { defined in the file } define int literal = 2 { integer ‘constants’ } define str literal = 3 { string ‘constants’ } define field = 4 { things like ‘author’ and ‘title’ } define int entry var = 5 { integer entry variable } define str entry var = 6 { string entry variable } define int global var = 7 { integer global variable } define str global var = 8 { string global variable } define last fn class = 8 { the same number as on the line above }

158. Here’s another bug report. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure unknwn function class confusion;

begin confusion(´ ␣ ␣ ´ ); end;

159. Occasionally we’ll want to print the name of one of these function classes. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure print fn class (fn loc : hash loc);

begin case (fn type[fn loc]) of built in: print (´ ´ ); wiz defined : print (´ ´ ); int literal : print (´ ´ ); str literal : print (´ ´ ); field : print (´ ´ ); int entry var : print (´ ´ ); str entry var : print (´ ´ ); int global var : print (´ ´ ); str global var : print (´ ´ );

othercases unknwn function class confusion

endcases; end; 160. This version is for printing when in trace mode. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡

trace procedure trace pr fn class (fn loc : hash loc); begin case (fn type[fn loc]) of built in: trace pr (´ ´ ); wiz defined : trace pr (´ ´ ); int literal : trace pr (´ ´ ); str literal : trace pr (´ ´ ); field : trace pr (´ ´ ); int entry var : trace pr (´ ´ ); str entry var : trace pr (´ ´ ); int global var : trace pr (´ ´ ); str global var : trace pr (´ ´ );

othercases unknwn function class confusion

endcases; end; ecart

161. Besides the function classes, we have types based on BibTEX’s capacity limitations and one based on what can go into the array wiz functions explained below.

define quote next fn = hash base − 1 { special marker used in defining functions } define end of def = hash max + 1 { another such special marker }

⟨ Types in the outer block 22 ⟩ +≡ fn class = 0 . . last fn class ; { the function classes } wiz fn loc = 0 . . wiz fn space; { wiz defined -function storage locations } int ent loc = 0 . . max ent ints ; { int entry var storage locations } str ent loc = 0 . . max ent strs ; { str entry var storage locations } str glob loc = 0 . . max glb str minus 1 ; { str global var storage locations } field loc = 0 . . max fields ; { individual field storage locations } hash ptr2 = quote next fn . . end of def ; { a special marker or a hash loc } 162. We store information about the functions in arrays the same size as the hash-table arrays and in locations corresponding to their hash-table locations. The two arrays fn info (an alias of ilk info described earlier) and fn type accomplish this: fn type specifies one of the above classes, and fn info gives information dependent on the class.

Six other arrays give the contents of functions: The array wiz functions holds definitions for wiz defined functions—each such function consists of a sequence of pointers to hash-table locations of other functions (with the two special-marker exceptions above); the array entry ints contains the current values of int entry var s; the array entry strs contains the current values of str entry var s; an element of the array global strs contains the current value of a str global var if the corresponding glb str ptr entry is empty, otherwise the nonempty entry is a pointer to the string; and the array field info, for each field of each entry, contains either a pointer to the string or the special value missing .

The array global strs isn’t packed (that is, it isn’t array … of packed array …) to increase speed on some systems; however, on systems that are byte-addressable and that have a good compiler, packing global strs would save lots of space without much loss of speed.

define fn info ≡ ilk info { an alias used with functions }

define missing = empty { a special pointer for missing fields } ⟨ Globals in the outer block 16 ⟩ +≡ fn loc: hash loc; { the hash-table location of a function } wiz loc: hash loc; { the hash-table location of a wizard function } literal loc: hash loc; { the hash-table location of a literal function } macro name loc: hash loc; { the hash-table location of a macro name } macro def loc: hash loc; { the hash-table location of a macro definition } fn type: packed array [hash loc] of fn class ; wiz def ptr : wiz fn loc; { storage location for the next wizard function } wiz fn ptr : wiz fn loc; { general wiz functions location } wiz functions : packed array [wiz fn loc] of hash ptr2 ; int ent ptr : int ent loc; { general int entry var location } entry ints : array [int ent loc] of integer ; num ent ints : int ent loc; { the number of distinct int entry var names } str ent ptr : str ent loc; { general str entry var location } entry strs : array [str ent loc] of packed array [0 . . ent str size] of ASCII code; num ent strs : str ent loc; { the number of distinct str entry var names } str glb ptr : 0 . . max glob strs ; { general str global var location } glb str ptr : array [str glob loc] of str number ; global strs : array [str glob loc] of array [0 . . glob str size] of ASCII code; glb str end : array [str glob loc] of 0 . . glob str size; { end markers } num glb strs : 0 . . max glob strs ; { number of distinct str global var names } field ptr : field loc; { general field info location } field parent ptr , field end ptr : field loc; { two more for doing cross-refs } cite parent ptr , cite xptr : cite number ; { two others for doing cross-refs } field info: packed array [field loc] of str number ; num fields : field loc; { the number of distinct field names } num pre defined fields : field loc; { so far, just one: } crossref num: field loc; { the number given to } no fields : boolean; { used for tr print ing entry information } 163. Now we initialize storage for the wiz defined functions and we initialize variables so that the first str entry var , int entry var , str global var , and field name will be assigned the number 0. Note: The variables num ent strs and num fields will also be set when pre-defining strings. ⟨ Set initial values of key variables 20 ⟩ +≡

wiz def ptr ← 0; num ent ints ← 0; num ent strs ← 0; num fields ← 0; str glb ptr ← 0; while (str glb ptr < max glob strs ) do { make str global var s empty }

begin glb str ptr [str glb ptr ] ← 0; glb str end [str glb ptr ] ← 0; incr (str glb ptr ); end;

num glb strs ← 0;

54  STYLE-FILE COMMANDS  BibTEX §164
164. Style-file commands. There are ten  commands: Five (  ,  ,  ,  ,
and  ) declare and define functions, one (  ) reads in the  -file entries, and four (  ,
,  , and  ) manipulate the entries and produce output.

The boolean variables entry seen and read seen indicate whether we’ve yet encountered an and a command. There must be exactly one of each of these, and the command, as well as any command, must precede the command. Furthermore, the command must precede the four that manipulate the entries and produce output. ⟨ Globals in the outer block 16 ⟩ +≡ entry seen: boolean; { true if we’ve already seen an command } read seen: boolean; { true if we’ve already seen a command } read performed : boolean; { true if we started reading the database file(s) } reading completed : boolean; { true if we made it all the way through } read completed : boolean; { true if the database info didn’t bomb BibTEX }

165. And we initialize them. ⟨ Set initial values of key variables 20 ⟩ +≡

entry seen ← false; read seen ← false; read performed ← false; reading completed ← false; read completed ← false;

166. Here’s another bug. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure id scanning confusion;

begin confusion(´ ␣ ␣ ´ );

end;

167. This macro is used to scan all  identifiers. The argument supplies the  command name.

The associated procedure simply prints an error message.

define bst identifier scan(#) ≡ begin scan identifier (right brace, comment , comment ); if ((scan result = white adjacent ) ∨ (scan result = specified char adjacent )) then do nothing else begin bst id print ; bst err (#);

end; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure bst id print ;

begin if (scan result = id null ) then print (´ ´ , xchr [scan char ], ´ ␣ ␣ ␣ ␣´ ) else if (scan result = other char adjacent ) then

print (´ ´ , xchr [scan char ], ´ ␣ ␣ ␣ ␣ ␣´ ) else id scanning confusion;

§168 BibTEX STYLE-FILE COMMANDS 55

end; 168. This macro just makes sure we’re at a left brace.

define bst get and check left brace(#) ≡

begin if (scan char ≠ left brace) then begin bst left brace print ; bst err (#); end;

incr (buf ptr2 ); { skip over the left brace }

end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure bst left brace print ;

begin print (´ ´ , xchr [left brace], ´ ␣ ␣ ␣ ␣ ␣´ );

end;

169. And this one, a right brace.

define bst get and check right brace(#) ≡

begin if (scan char ≠ right brace) then begin bst right brace print ; bst err (#); end;

incr (buf ptr2 ); { skip over the right brace }

end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure bst right brace print ;

begin print (´ ´ , xchr [right brace], ´ ␣ ␣ ␣ ␣ ␣´ );

end;

170. This macro complains if we’ve already encountered a function to be inserted into the hash table.

define check for already seen function(#) ≡

begin if (hash found ) then { already encountered this as a function } begin already seen function print (#); return; end; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure already seen function print (seen fn loc : hash loc);

label exit ; { so the call to bst err works }

begin print pool str (hash text [seen fn loc]); print (´ ␣ ␣ ␣ ␣ ␣ ´ );

print fn class (seen fn loc); print ln(´ ␣ ␣ ´ ); bst err print and look for blank line return; exit : end; 171. An command has three arguments, each a (possibly empty) list of function names between braces (the names are separated by one or more white space characters). All function names in this and other commands must be legal identifiers. Upper/lower cases are considered to be the same for function names in these lists—all upper-case letters are converted to lower case. These arguments give lists of field s, int entry var s, and str entry var s. ⟨ Procedures and functions for the reading and processing of input files 101* ⟩ +≡ procedure bst entry command ;

label exit ; begin if (entry seen) then bst err (´ ␣ ␣ ␣ ´ ); entry seen ← true; { now we’ve seen an command } eat bst white and eof check (´ ´ ); ⟨ Scan the list of field s 172 ⟩; eat bst white and eof check (´ ´ ); if (num fields = num pre defined fields ) then bst warn(´ ␣ ´ ´ ␣ ␣ ␣ ´ ); ⟨ Scan the list of int entry var s 174 ⟩; eat bst white and eof check (´ ´ ); ⟨ Scan the list of str entry var s 176 ⟩;

exit : end;

172. This module reads a left brace, the list of field s, and a right brace. The field s are those like ‘author’ and ‘title.’ ⟨ Scan the list of field s 172 ⟩ ≡

begin bst get and check left brace(´ ´ ); eat bst white and eof check (´ ´ ); while (scan char ≠ right brace) do

begin bst identifier scan(´ ´ ); ⟨ Insert a field into the hash table 173 ⟩; eat bst white and eof check (´ ´ ); end;

incr (buf ptr2 ); { skip over the right brace } end

This code is used in section 171.

173. Here we insert the just found field name into the hash table, record it as a field , and assign it a number to be used in indexing into the field info array. ⟨ Insert a field into the hash table 173 ⟩ ≡

begin trace trace pr token; trace pr ln(´ ␣ ␣ ␣ ´ ); ecart lower case(buffer , buf ptr1 , token len); { ignore case differences } fn loc ← str lookup(buffer , buf ptr1 , token len, bst fn ilk , do insert ); check for already seen function(fn loc); fn type[fn loc] ← field ; fn info[fn loc] ← num fields ; { give this field a number (take away its name) } incr (num fields ); end

This code is used in section 172.

174. This module reads a left brace, the list of int entry var s, and a right brace. ⟨ Scan the list of int entry var s 174 ⟩ ≡

begin bst get and check left brace(´ ´ ); eat bst white and eof check (´ ´ ); while (scan char ≠ right brace) do

begin bst identifier scan(´ ´ ); ⟨ Insert an int entry var into the hash table 175 ⟩; eat bst white and eof check (´ ´ ); end;

incr (buf ptr2 ); { skip over the right brace } end

This code is used in section 171.

175. Here we insert the just found int entry var name into the hash table and record it as an int entry var . An int entry var is one that the style designer wants a separate copy of for each entry. ⟨ Insert an int entry var into the hash table 175 ⟩ ≡

begin trace trace pr token; trace pr ln(´ ␣ ␣ ␣ ␣ ´ ); ecart lower case(buffer , buf ptr1 , token len); { ignore case differences } fn loc ← str lookup(buffer , buf ptr1 , token len, bst fn ilk , do insert ); check for already seen function(fn loc); fn type[fn loc] ← int entry var ; fn info[fn loc] ← num ent ints ; { give this int entry var a number } incr (num ent ints ); end

This code is used in section 174.

176. This module reads a left brace, the list of str entry var s, and a right brace. A str entry var is one that the style designer wants a separate copy of for each entry. ⟨ Scan the list of str entry var s 176 ⟩ ≡

begin bst get and check left brace(´ ´ ); eat bst white and eof check (´ ´ ); while (scan char ≠ right brace) do

begin bst identifier scan(´ ´ ); ⟨ Insert a str entry var into the hash table 177 ⟩; eat bst white and eof check (´ ´ ); end;

incr (buf ptr2 ); { skip over the right brace } end

This code is used in section 171.

177. Here we insert the just found str entry var name into the hash table, record it as a str entry var , and set its pointer into entry strs . ⟨ Insert a str entry var into the hash table 177 ⟩ ≡

begin trace trace pr token; trace pr ln(´ ␣ ␣ ␣ ␣ ´ ); ecart lower case(buffer , buf ptr1 , token len); { ignore case differences } fn loc ← str lookup(buffer , buf ptr1 , token len, bst fn ilk , do insert ); check for already seen function(fn loc); fn type[fn loc] ← str entry var ; fn info[fn loc] ← num ent strs ; { give this str entry var a number } incr (num ent strs ); end

This code is used in section 176.

178. A legal argument for an  ,  , or  command must exist and be built in or

wiz defined . Here’s where we check, returning true if the argument is illegal. ⟨ Procedures and functions for the reading and processing of input files 101* ⟩ +≡ function bad argument token: boolean;

label exit ; begin bad argument token ← true; { now it’s easy to exit if necessary } lower case(buffer , buf ptr1 , token len); { ignore case differences } fn loc ← str lookup(buffer , buf ptr1 , token len, bst fn ilk , dont insert ); if (¬hash found ) then { unknown function }

begin print token; bst err (´ ␣ ␣ ␣ ␣ ´ ); end

else if ((fn type[fn loc] ≠ built in) ∧ (fn type[fn loc] ≠ wiz defined )) then begin print token; print (´ ␣ ␣ ␣ ␣ ␣´ ); print fn class (fn loc); bst err print and look for blank line return; end;

bad argument token ← false; exit : end;

179. An command has one argument, a single built in or wiz defined function name between braces. Upper/lower cases are considered to be the same—all upper-case letters are converted to lower case. Also, we must make sure we’ve already seen a command.

This module reads a left brace, a single function to be executed, and a right brace. ⟨ Procedures and functions for the reading and processing of input files 101* ⟩ +≡ procedure bst execute command ;

label exit ; begin if (¬read seen) then bst err (´ ␣ ␣ ␣ ␣ ␣ ´ );

eat bst white and eof check (´  ´ ); bst get and check left brace(´  ´ );
eat bst white and eof check (´  ´ ); bst identifier scan(´  ´ );

⟨ Check the -command argument token 180 ⟩; eat bst white and eof check (´ ´ ); bst get and check right brace(´ ´ ); ⟨ Perform an command 297 ⟩;

exit : end;

180. Before executing the function, we must make sure it’s a legal one. It must exist and be built in or wiz defined . ⟨ Check the -command argument token 180 ⟩ ≡

begin trace trace pr token; trace pr ln(´ ␣ ␣ ␣ ␣ ␣ ␣ ´ ); ecart if (bad argument token) then return; end

This code is used in section 179.

181. A command has two arguments; the first is a wiz defined function name between braces. Upper/lower cases are considered to be the same—all upper-case letters are converted to lower case. The second argument defines this function. It consists of a sequence of functions, between braces, separated by white space characters. Upper/lower cases are considered to be the same for function names but not for str literal s. ⟨ Procedures and functions for the reading and processing of input files 101* ⟩ +≡ procedure bst function command ;

label exit ; begin eat bst white and eof check (´ ´ ); ⟨ Scan the wiz defined function name 182 ⟩; eat bst white and eof check (´ ´ ); bst get and check left brace(´ ´ ); scan fn def (wiz loc); { this scans the function definition }

exit : end;

182. This module reads a left brace, a wiz defined function name, and a right brace. ⟨ Scan the wiz defined function name 182 ⟩ ≡

begin bst get and check left brace(´ ´ ); eat bst white and eof check (´ ´ ); bst identifier scan(´ ´ ); ⟨ Check the wiz defined function name 183 ⟩; eat bst white and eof check (´ ´ ); bst get and check right brace(´ ´ ); end

This code is used in section 181.

183. The function name must exist and be a new one; we mark it as wiz defined . Also, see if it’s the default entry-type function. ⟨ Check the wiz defined function name 183 ⟩ ≡

begin trace trace pr token; trace pr ln(´ ␣ ␣ ␣ ␣ ´ ); ecart lower case(buffer , buf ptr1 , token len); { ignore case differences } wiz loc ← str lookup(buffer , buf ptr1 , token len, bst fn ilk , do insert ); check for already seen function(wiz loc); fn type[wiz loc] ← wiz defined ; if (hash text [wiz loc] = s default ) then { we’ve found the default entry-type }

b default ← wiz loc; { see the built in functions for b default } end

This code is used in section 182.

184. We’re about to start scanning tokens in a function definition. When a function token is illegal, we skip until it ends; a white space character, an end-of-line, a right brace, or a comment marks the end of the current token.

define next token = 25 { a bad function token; go read the next one } define skip token(#) ≡

begin { not-so-serious error during parsing }

print (#); skip token print ; { also, skip to the current token’s end } goto next token; end

⟨ Procedures and functions for input scanning 84 ⟩ +≡ procedure skip token print ;

begin print (´ ´ ); bst ln num print ; mark error ; if (scan2 white(right brace, comment )) then { ok if token ends line }

do nothing ; end; 185. This macro is similar to the last one but is specifically for recursion in a wiz defined function, which is illegal; it helps save space.

define skip recursive token ≡ begin print recursion illegal ; goto next token; end

⟨ Procedures and functions for input scanning 84 ⟩ +≡ procedure print recursion illegal ;

begin trace trace pr newline; ecart print ln(´ ␣ ␣ ␣ ␣ ␣ ␣ ´ ); print (´ ␣´ ); print token; print ln(´ ␣ ␣ ␣ ␣ ␣ ␣ ´ ); print recursion illegal ; skip token print ; { also, skip to the current token’s end } end;

186. Here’s another macro for saving some space when there’s a problem with a token.

define skip token unknown function ≡ begin skp token unknown function print ; goto next token; end

⟨ Procedures and functions for input scanning 84 ⟩ +≡ procedure skp token unknown function print ;

begin print token; print (´ ␣ ␣ ␣ ␣ ´ ); skip token print ;

{ also, skip to the current token’s end } end;

187. And another.

define skip token illegal stuff after literal ≡ begin skip illegal stuff after token print ; goto next token; end

⟨ Procedures and functions for input scanning 84 ⟩ +≡ procedure skip illegal stuff after token print ;

begin print (´ ´ , xchr [scan char ], ´ ␣ ´ ´ ␣ ␣ ␣ ´ ); skip token print ;

{ also, skip to the current token’s end } end; 188. This recursive function reads and stores the list of functions (separated by white space characters or ends-of-line) that define this new function, and reads a right brace. ⟨ Procedures and functions for input scanning 84 ⟩ +≡ procedure scan fn def (fn hash loc : hash loc);

label next token, exit ; type fn def loc = 0 . . single fn space; { for a single wiz defined -function } var singl function: packed array [fn def loc] of hash ptr2 ;

single ptr : fn def loc; { next storage location for this definition } copy ptr : fn def loc; { dummy variable } end of num: buf pointer ; { the end of an implicit function’s name } impl fn loc: hash loc; { an implicit function’s hash-table location }

begin eat bst white and eof check (´ ´ ); single ptr ← 0; while (scan char ≠ right brace) do

begin ⟨ Get the next function of the definition 190 ⟩; next token: eat bst white and eof check (´ ´ );

end; ⟨ Complete this function’s definition 201 ⟩; incr (buf ptr2 ); { skip over the right brace }

exit : end;

189. This macro inserts a hash-table location (or one of the two special markers quote next fn and end of def ) into the singl function array, which will later be copied into the wiz functions array.

define insert fn loc(#) ≡ begin singl function[single ptr ] ← #; if (single ptr = single fn space) then singl fn overflow ; incr (single ptr ); end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure singl fn overflow ;

begin overflow (´ ␣ ␣ ␣´ , single fn space); end;

190. There are five possibilities for the first character of the token representing the next function of the definition: If it’s a number sign, the token is an int literal ; if it’s a double quote, the token is a str literal ; if it’s a single quote, the token is a quoted function; if it’s a left brace, the token isn’t really a token, but rather the start of another function definition (which will result in a recursive call to scan fn def ); if it’s anything else, the token is the name of an already-defined function. Note: To prevent the wizard from using recursion, we have to check that neither a quoted function nor an already-defined-function is actually the currently-being-defined function (which is stored at wiz loc). ⟨ Get the next function of the definition 190 ⟩ ≡

case (scan char ) of number sign: ⟨ Scan an int literal 191 ⟩; double quote: ⟨ Scan a str literal 192 ⟩; single quote: ⟨ Scan a quoted function 193 ⟩; left brace: ⟨ Start a new function definition 195 ⟩; othercases ⟨ Scan an already-defined function 200 ⟩ endcases

This code is used in section 188.

191. An int literal is preceded by a number sign, consists of an integer (i.e., an optional minus sign followed by one or more numeric characters), and is followed either by a white space character, an end-of-line, or a right brace. The array fn info contains the value of the integer for int literal s. ⟨ Scan an int literal 191 ⟩ ≡

begin incr (buf ptr2 ); { skip over the number sign } if (¬scan integer ) then skip token(´ ␣ ␣ ␣ ␣ ´ ); trace trace pr (´ #´ ); trace pr token; trace pr ln(´ ␣ ␣ ␣ ␣ ␣ ␣ ␣´ , token value : 0); ecart literal loc ← str lookup(buffer , buf ptr1 , token len, integer ilk , do insert ); if (¬hash found ) then

begin fn type[literal loc] ← int literal ; { set the fn class } fn info[literal loc] ← token value; { the value of this integer } end;

if ((lex class [scan char ] ≠ white space) ∧ (buf ptr2 < last ) ∧ (scan char ≠ right brace) ∧

(scan char ≠ comment )) then skip token illegal stuff after literal ; insert fn loc(literal loc); { add this function to wiz functions } end

This code is used in section 190.

192. A str literal is preceded by a double quote and consists of all characters on this line up to the next double quote. Also, there must be either a white space character, an end-of-line, a right brace, or a comment following (since functions in the definition must be separated by white space). The array fn info contains nothing for str literal s. ⟨ Scan a str literal 192 ⟩ ≡

begin incr (buf ptr2 ); { skip over the double quote } if (¬scan1 (double quote)) then skip token(´ ␣` ´ , xchr [double quote], ´ ´ ´ ␣ ␣ ␣ ␣ ´ ); trace trace pr (´ ´ ); trace pr token; trace pr (´ ´ ); trace pr ln(´ ␣ ␣ ␣ ␣ ´ ); ecart literal loc ← str lookup(buffer , buf ptr1 , token len, text ilk , do insert ); fn type[literal loc] ← str literal ; { set the fn class } incr (buf ptr2 ); { skip over the double quote } if ((lex class [scan char ] ≠ white space) ∧ (buf ptr2 < last ) ∧ (scan char ≠ right brace) ∧

(scan char ≠ comment )) then skip token illegal stuff after literal ; insert fn loc(literal loc); { add this function to wiz functions } end

This code is used in section 190.

193. A quoted function is preceded by a single quote and consists of all characters up to the next white space character, end-of-line, right brace, or comment . ⟨ Scan a quoted function 193 ⟩ ≡

begin incr (buf ptr2 ); { skip over the single quote } if (scan2 white(right brace, comment )) then { ok if token ends line }

do nothing ; trace trace pr (´ ´ ´ ´ ); trace pr token; trace pr (´ ␣ ␣ ␣ ␣ ␣´ ); ecart lower case(buffer , buf ptr1 , token len); { ignore case differences } fn loc ← str lookup(buffer , buf ptr1 , token len, bst fn ilk , dont insert ); if (¬hash found ) then { unknown function }

skip token unknown function else ⟨ Check and insert the quoted function 194 ⟩; end

This code is used in section 190.

194. Here we check that this quoted function is a legal one—the function name must already exist, but it mustn’t be the currently-being-defined function (which is stored at wiz loc). ⟨ Check and insert the quoted function 194 ⟩ ≡

begin if (fn loc = wiz loc) then skip recursive token else begin trace trace pr (´ ␣ ␣´ ); trace pr fn class (fn loc); trace pr newline;

ecart

insert fn loc(quote next fn); { add special marker together with } insert fn loc(fn loc); { this function to wiz functions } end

end

This code is used in section 193.

195. This module marks the implicit function as being quoted, generates a name, and stores it in the hash table. This name is strictly internal to this program, starts with a single quote (since that will make this function name unique), and ends with the variable impl fn num converted to ASCII. The alias kludge helps make the stack space not overflow on some machines.

define ex buf2 ≡ ex buf { an alias, used only in this module } ⟨ Start a new function definition 195 ⟩ ≡

begin ex buf2 [0] ← single quote; int to ASCII (impl fn num, ex buf2 , 1, end of num); impl fn loc ← str lookup(ex buf2 , 0, end of num, bst fn ilk , do insert ); if (hash found ) then confusion(´ ␣ ␣ ␣ ´ ); trace trace pr pool str (hash text [impl fn loc]); trace pr ln(´ ␣ ␣ ␣ ␣ ´ ); ecart incr (impl fn num); fn type[impl fn loc] ← wiz defined ; insert fn loc(quote next fn); { all implicit functions are quoted } insert fn loc(impl fn loc); { add it to wiz functions } incr (buf ptr2 ); { skip over the left brace } scan fn def (impl fn loc); { this is the recursive call } end

This code is used in section 190.

196. The variable impl fn num counts the number of implicit functions seen in the file. ⟨ Globals in the outer block 16 ⟩ +≡ impl fn num: integer ; { the number of implicit functions seen so far } 197. Now we initialize it. ⟨ Set initial values of key variables 20 ⟩ +≡

impl fn num ← 0;

198. This module appends a character to int buf after checking to make sure it will fit; for use in int to ASCII .

define append int char (#) ≡ begin if (int ptr = buf size) then buffer overflow ; int buf [int ptr ] ← #; incr (int ptr ); end

199* . This procedure takes the integer the int , copies the appropriate ASCII code string into int buf starting at int begin, and sets the var parameter int end to the first unused int buf location. The ASCII string will consist of decimal digits, the first of which will be not be a 0 if the integer is nonzero, with a prepended minus sign if the integer is negative. ⟨ Procedures and functions for handling numbers, characters, and strings 55 ⟩ +≡ procedure int to ASCII (the int : integer ; var int buf : buf type; int begin : buf pointer ;

var int end : buf pointer ); var int ptr , int xptr : buf pointer ; { pointers into int buf }

int tmp val : ASCII code; { the temporary element in an exchange } begin int ptr ← int begin; if (the int < 0) then { add the minus sign and use the absolute value }

begin append int char (minus sign); the int ← −the int ;

end; int xptr ← int ptr ; repeat { copy digits into int buf }

append int char ( + (the int mod 10)); the int ← the int div 10; until (the int = 0); int end ← int ptr ; { set the string length } decr (int ptr ); while (int xptr < int ptr ) do { and reorder (flip) the digits }

begin int tmp val ← int buf [int xptr ]; int buf [int xptr ] ← int buf [int ptr ]; int buf [int ptr ] ← int tmp val ; decr (int ptr ); incr (int xptr ); end

end; 200. An already-defined function consists of all characters up to the next white space character, end-of-line, right brace, or comment . This function name must already exist, but it mustn’t be the currently-being-defined function (which is stored at wiz loc). ⟨ Scan an already-defined function 200 ⟩ ≡

begin if (scan2 white(right brace, comment )) then { ok if token ends line }

do nothing ; trace trace pr token; trace pr (´ ␣ ␣ ␣ ␣´ ); ecart lower case(buffer , buf ptr1 , token len); { ignore case differences } fn loc ← str lookup(buffer , buf ptr1 , token len, bst fn ilk , dont insert ); if (¬hash found ) then { unknown function }

skip token unknown function else if (fn loc = wiz loc) then skip recursive token

else begin trace trace pr (´ ␣ ␣´ ); trace pr fn class (fn loc); trace pr newline; ecart insert fn loc(fn loc); { add this function to wiz functions } end;

end

This code is used in section 190.

201. Now we add the end of def special marker, make sure this function will fit into wiz functions , and put it there. ⟨ Complete this function’s definition 201 ⟩ ≡

begin insert fn loc(end of def ); { add special marker ending the definition } if (single ptr + wiz def ptr > wiz fn space) then

begin print (single ptr + wiz def ptr : 0, ´ ␣´ );

overflow (´ ␣ ␣ ␣´ , wiz fn space);

end; fn info[fn hash loc] ← wiz def ptr ; { pointer into wiz functions } copy ptr ← 0; while (copy ptr < single ptr ) do { make this function official }

begin wiz functions [wiz def ptr ] ← singl function[copy ptr ]; incr (copy ptr ); incr (wiz def ptr ); end;

end

This code is used in section 188.

202. An command has one argument, a list of function names between braces (the names are separated by one or more white space characters). Upper/lower cases are considered to be the same for function names in these lists—all upper-case letters are converted to lower case. Each name in this list specifies an int global var . There may be several commands in the file.

This module reads a left brace, a list of int global var s, and a right brace. ⟨ Procedures and functions for the reading and processing of input files 101* ⟩ +≡ procedure bst integers command ;

label exit ; begin eat bst white and eof check (´ ´ ); bst get and check left brace(´ ´ ); eat bst white and eof check (´ ´ ); while (scan char ≠ right brace) do

begin bst identifier scan(´ ´ ); ⟨ Insert an int global var into the hash table 203 ⟩; eat bst white and eof check (´ ´ ); end;

incr (buf ptr2 ); { skip over the right brace } exit : end;

203. Here we insert the just found int global var name into the hash table and record it as an int global var . Also, we initialize it by setting fn info[fn loc] to 0. ⟨ Insert an int global var into the hash table 203 ⟩ ≡

begin trace trace pr token; trace pr ln(´ ␣ ␣ ␣ ␣ ´ ); ecart lower case(buffer , buf ptr1 , token len); { ignore case differences } fn loc ← str lookup(buffer , buf ptr1 , token len, bst fn ilk , do insert ); check for already seen function(fn loc); fn type[fn loc] ← int global var ; fn info[fn loc] ← 0; { initialize } end

This code is used in section 202.

204. An command has one argument, a single built in or wiz defined function name between braces. Upper/lower cases are considered to be the same—all upper-case letters are converted to lower case. Also, we must make sure we’ve already seen a command.

This module reads a left brace, a single function to be iterated, and a right brace. ⟨ Procedures and functions for the reading and processing of input files 101* ⟩ +≡ procedure bst iterate command ;

label exit ; begin if (¬read seen) then bst err (´ ␣ ␣ ␣ ␣ ␣ ´ );

eat bst white and eof check (´  ´ ); bst get and check left brace(´  ´ );
eat bst white and eof check (´  ´ ); bst identifier scan(´  ´ );

⟨ Check the -command argument token 205 ⟩; eat bst white and eof check (´ ´ ); bst get and check right brace(´ ´ ); ⟨ Perform an command 298 ⟩;

exit : end; 205. Before iterating the function, we must make sure it’s a legal one. It must exist and be built in or wiz defined . ⟨ Check the -command argument token 205 ⟩ ≡

begin trace trace pr token; trace pr ln(´ ␣ ␣ ␣ ␣ ␣ ␣ ´ ); ecart if (bad argument token) then return; end

This code is used in section 204.

206. A  command, like a  command, has two arguments; the first is a macro name between

braces. The name must be a legal identifier. Upper/lower cases are considered to be the same—all upper-case letters are converted to lower case. The second argument defines this macro. It consists of a double quote-delimited string (which must be on a single line) between braces, with optional white space characters between the braces and the double quotes. This double quote-delimited string is parsed exactly as a str literal is for the command. ⟨ Procedures and functions for the reading and processing of input files 101* ⟩ +≡ procedure bst macro command ;

label exit ; begin if (read seen) then bst err (´ ␣ ␣ ␣ ␣ ␣ ´ ); eat bst white and eof check (´ ´ ); ⟨ Scan the macro name 207 ⟩; eat bst white and eof check (´ ´ ); ⟨ Scan the macro’s definition 209 ⟩;

exit : end;

207. This module reads a left brace, a macro name, and a right brace. ⟨ Scan the macro name 207 ⟩ ≡

begin bst get and check left brace(´ ´ ); eat bst white and eof check (´ ´ ); bst identifier scan(´ ´ ); ⟨ Check the macro name 208 ⟩; eat bst white and eof check (´ ´ ); bst get and check right brace(´ ´ ); end

This code is used in section 206.

208. The macro name must be a new one; we mark it as macro ilk . ⟨ Check the macro name 208 ⟩ ≡

begin trace trace pr token; trace pr ln(´ ␣ ␣ ␣ ´ ); ecart lower case(buffer , buf ptr1 , token len); { ignore case differences } macro name loc ← str lookup(buffer , buf ptr1 , token len, macro ilk , do insert ); if (hash found ) then

begin print token; bst err (´ ␣ ␣ ␣ ␣ ␣ ␣ ´ ); end;

ilk info[macro name loc] ← hash text [macro name loc]; { default in case of error } end

This code is used in section 207.

209. This module reads a left brace, the double quote-delimited string that defines this macro, and a right brace. ⟨ Scan the macro’s definition 209 ⟩ ≡

begin bst get and check left brace(´ ´ ); eat bst white and eof check (´ ´ ); if (scan char ≠ double quote) then

bst err (´ ␣ ␣ ␣ ␣ ␣´ , xchr [double quote], ´ ´ ); ⟨ Scan the macro definition-string 210 ⟩; eat bst white and eof check (´ ´ ); bst get and check right brace(´ ´ ); end

This code is used in section 206.

210. A macro definition-string is preceded by a double quote and consists of all characters on this line up to the next double quote. The array ilk info contains a pointer to this string for the macro name. ⟨ Scan the macro definition-string 210 ⟩ ≡

begin incr (buf ptr2 ); { skip over the double quote } if (¬scan1 (double quote)) then

bst err (´ ´ ´ ␣ ␣` ´ , xchr [double quote], ´ ´ ´ ␣ ␣ ␣ ␣ ´ ); trace trace pr (´ ´ ); trace pr token; trace pr (´ ´ ); trace pr ln(´ ␣ ␣ ␣ ␣ ´ ); ecart macro def loc ← str lookup(buffer , buf ptr1 , token len, text ilk , do insert ); fn type[macro def loc] ← str literal ; { set the fn class } ilk info[macro name loc] ← hash text [macro def loc]; incr (buf ptr2 ); { skip over the double quote } end

This code is used in section 209.

211. We need to include stuff for  reading here because that’s done by the  command.

⟨ Procedures and functions for the reading and processing of input files 101* ⟩ +≡ ⟨ Scan for and process a command or database entry 237 ⟩

212. The command has no arguments so there’s no more parsing to do. We must make sure we haven’t seen a command before and we’ve already seen an command. ⟨ Procedures and functions for the reading and processing of input files 101* ⟩ +≡ procedure bst read command ;

label exit ; begin if (read seen) then bst err (´ ␣ ␣ ␣ ´ ); read seen ← true; { now we’ve seen a command } if (¬entry seen) then bst err (´ ␣ ␣ ␣ ␣ ␣ ´ ); sv ptr1 ← buf ptr2 ; { save the contents of the input line } sv ptr2 ← last ; tmp ptr ← sv ptr1 ; while (tmp ptr < sv ptr2 ) do

begin sv buffer [tmp ptr ] ← buffer [tmp ptr ]; incr (tmp ptr );

end; ⟨ Read the file(s) 224 ⟩; buf ptr2 ← sv ptr1 ; { and restore } last ← sv ptr2 ; tmp ptr ← buf ptr2 ; while (tmp ptr < last ) do

begin buffer [tmp ptr ] ← sv buffer [tmp ptr ]; incr (tmp ptr );

end; exit : end; 213. A command has one argument, a single built in or wiz defined function name between braces. Upper/lower cases are considered to be the same—all upper-case letters are converted to lower case. Also, we must make sure we’ve already seen a command.

This module reads a left brace, a single function to be iterated in reverse, and a right brace. ⟨ Procedures and functions for the reading and processing of input files 101* ⟩ +≡ procedure bst reverse command ;

label exit ;

begin if (¬read seen) then bst err (´ ␣ ␣ ␣ ␣ ␣ ´ );

eat bst white and eof check (´  ´ ); bst get and check left brace(´  ´ );
eat bst white and eof check (´  ´ ); bst identifier scan(´  ´ );

⟨ Check the -command argument token 214 ⟩;

eat bst white and eof check (´ ´ ); bst get and check right brace(´ ´ ); ⟨ Perform a command 299 ⟩;

exit : end;

214. Before iterating the function in reverse, we must make sure it’s a legal one. It must exist and be built in or wiz defined . ⟨ Check the -command argument token 214 ⟩ ≡

begin trace trace pr token; trace pr ln(´ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ´ ); ecart if (bad argument token) then return; end

This code is used in section 213.

215. The command has no arguments so there’s no more parsing to do, but we must make sure we’ve already seen a command. ⟨ Procedures and functions for the reading and processing of input files 101* ⟩ +≡ procedure bst sort command ;

label exit ;

begin if (¬read seen) then bst err (´ ␣ ␣ ␣ ␣ ␣ ´ ); ⟨ Perform a command 300 ⟩;

exit : end;

216. A command has one argument, a list of function names between braces (the names are separated by one or more white space characters). Upper/lower cases are considered to be the same for function names in these lists—all upper-case letters are converted to lower case. Each name in this list specifies a str global var . There may be several commands in the file.

This module reads a left brace, a list of str global var s, and a right brace. ⟨ Procedures and functions for the reading and processing of input files 101* ⟩ +≡ procedure bst strings command ;

label exit ;

begin eat bst white and eof check (´ ´ ); bst get and check left brace(´ ´ ); eat bst white and eof check (´ ´ ); while (scan char ≠ right brace) do

begin bst identifier scan(´ ´ ); ⟨ Insert a str global var into the hash table 217 ⟩; eat bst white and eof check (´ ´ ); end;

incr (buf ptr2 ); { skip over the right brace } exit : end; 217. Here we insert the just found str global var name into the hash table, record it as a str global var , set its pointer into global strs , and initialize its value there to the null string.

define end of string = invalid code { this illegal ASCII code ends a string } ⟨ Insert a str global var into the hash table 217 ⟩ ≡

begin trace trace pr token; trace pr ln(´ ␣ ␣ ␣ ␣ ´ ); ecart lower case(buffer , buf ptr1 , token len); { ignore case differences } fn loc ← str lookup(buffer , buf ptr1 , token len, bst fn ilk , do insert ); check for already seen function(fn loc); fn type[fn loc] ← str global var ; fn info[fn loc] ← num glb strs ; { pointer into global strs } if (num glb strs = max glob strs ) then

overflow (´ ␣ ␣ ␣ ␣´ , max glob strs ); incr (num glb strs ); end

This code is used in section 216.

218. That’s it for processing commands, except for finishing the procedural gymnastics. Note that this must topologically follow the stuff for reading, because that’s done by the ’s command. ⟨ Procedures and functions for the reading and processing of input files 101* ⟩ +≡

§219 BibTEX READING THE DATABASE FILE(S) 71

⟨ Scan for and process a command 155 ⟩ 219. Reading the database file(s). This section reads the file(s), each of which consists of a sequence of entries (perhaps with a few commands thrown in, as explained later). Each entry consists of an at sign, an entry type, and, between braces or parentheses and separated by commas, a database key and a list of fields. Each field consists of a field name, an equals sign, and nonempty list of field tokens separated by concat char s. Each field token is either a nonnegative number, a macro name (like ‘jan’), or a brace-balanced string delimited by either double quotes or braces. Finally, case differences are ignored for all but delimited strings and database keys, and white space characters and ends-of-line may appear in all reasonable places (i.e., anywhere except within entry types, database keys, field names, and macro names); furthermore, comments may appear anywhere between entries (or before the first or after the last) as long as they contain no at signs.

220. These global variables are used while reading the file(s). The elements of type list , which indicate an entry’s type (book, article, etc.), point either to a hash loc or are one of two special markers: empty , from which hash base = empty + 1 was defined, means we haven’t yet encountered the entry corresponding to this cite key; and undefined means we’ve encountered it but it had an unknown entry type. Thus the array type list is of type hash ptr2 , also defined earlier. An element of the boolean array entry exists whose corresponding entry in cite list gets overwritten (which happens only when all entries is true) indicates whether we’ve encountered that entry of cite list while reading the file(s); this information is unused for entries that aren’t (or more precisely, that have no chance of being) overwritten. When we’re reading the database file, the array cite info contains auxiliary information for cite list . Later, cite info will become sorted cites , and this dual role imposes the (not-very-imposing) restriction max strings ≥ max cites .

define undefined = hash max + 1 { a special marker used for type list } ⟨ Globals in the outer block 16 ⟩ +≡ bib line num: integer ; { line number of the file } entry type loc: hash loc; { the hash-table location of an entry type } type list : packed array [cite number ] of hash ptr2 ; type exists : boolean; { true if this entry type is -defined } entry exists : packed array [cite number ] of boolean; store entry : boolean; { true if we’re to store info for this entry } field name loc: hash loc; { the hash-table location of a field name } field val loc: hash loc; { the hash-table location of a field value } store field : boolean; { true if we’re to store info for this field } store token: boolean; { true if we’re to store this macro token } right outer delim: ASCII code; { either a right brace or a right paren } right str delim: ASCII code; { either a right brace or a double quote } at bib command : boolean; { true for a command, false for an entry } cur macro loc: hash loc; { macro loc for a being defined } cite info: packed array [cite number ] of str number ; { extra cite list info } cite hash found : boolean; { set to a previous hash found value } preamble ptr : bib number ; { pointer into the s preamble array } num preamble strings : bib number ; { counts the s preamble strings }

221. This little procedure exists because it’s used by at least two other procedures and thus saves some space. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure bib ln num print ;

72  READING THE DATABASE FILE(S)  BibTEX §222

begin print (´ ␣´ , bib line num : 0, ´ ␣ ␣ ␣´ ); print bib name; end; 222. When there’s a serious error parsing a file, we flush everything up to the beginning of the next entry.

define bib err (#) ≡ begin { serious error during parsing } print (#); bib err print ; return; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure bib err print ;

begin print (´ ´ ); bib ln num print ; print bad input line; { this call does the mark error } print skipping whatever remains ; if (at bib command ) then print ln(´ ´ ) else print ln(´ ´ ); end;

223. When there’s a harmless error parsing a file, we just give a warning message. This is always called after other stuff has been printed out.

define bib warn(#) ≡ begin { non-serious error during parsing } print (#); bib warn print ; end

define bib warn newline(#) ≡ begin { same as above but with a newline } print ln(#); bib warn print ; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure bib warn print ;

begin bib ln num print ; mark warning ; end;

224. For all num bib files database files, we keep reading and processing entries until none left. ⟨ Read the file(s) 224 ⟩ ≡

begin ⟨ Final initialization for processing 225 ⟩; read performed ← true; bib ptr ← 0; while (bib ptr < num bib files ) do

begin print (´ ␣ ␣#´ , bib ptr + 1 : 0, ´ ␣´ ); print bib name; bib line num ← 0; { initialize to get the first input line } buf ptr2 ← last ; while (¬eof (cur bib file)) do get bib command or entry and process ; a close(cur bib file); incr (bib ptr ); end;

reading completed ← true; trace trace pr ln(´ ␣ ␣ ␣ ␣ ´ ); ecart ⟨ Final initialization for processing the entries 277 ⟩; read completed ← true; end

This code is used in section 212.

225. We need to initialize the field info array, and also various things associated with the cite list array (but not cite list itself). ⟨ Final initialization for processing 225 ⟩ ≡

begin ⟨ Initialize the field info 226 ⟩;

⟨ Initialize things for the cite list 228 ⟩;

end

This code is used in section 224.

226. This module initializes all fields of all entries to missing , the value to which all fields are initialized. ⟨ Initialize the field info 226 ⟩ ≡

begin check field overflow (num fields ∗ num cites ); field ptr ← 0; while (field ptr < max fields ) do

begin field info[field ptr ] ← missing ; incr (field ptr );

end; end

This code is used in section 225.

227. Complain if somebody’s got a field fetish. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure check field overflow (total fields : integer );

begin if (total fields > max fields ) then begin print ln(total fields : 0, ´ ␣ ´ ); overflow (´ ␣ ␣ ␣ ␣´ , max fields ); end;

end; 228. We must initialize the type list array so that we can detect duplicate (or missing) entries for cite keys on cite list . Also, when we’re to include the entire database, we use the array entry exists to detect those missing entries whose cite list info will (or to be more precise, might) be overwritten; and we use the array cite info to save the part of cite list that will (might) be overwritten. We also use cite info for counting cross references when it’s appropriate—when an entry isn’t otherwise to be included on cite list (that is, the entry isn’t d or d). Such an entry is included on the final cite list if it’s cross referenced at least min crossrefs times. ⟨ Initialize things for the cite list 228 ⟩ ≡

begin cite ptr ← 0;

while (cite ptr < max cites ) do begin type list [cite ptr ] ← empty ; cite info[cite ptr ] ← any value; { to appeas PASCAL’s boolean evaluation } incr (cite ptr ); end;

old num cites ← num cites ;

if (all entries ) then begin cite ptr ← all marker ; while (cite ptr < old num cites ) do

begin cite info[cite ptr ] ← cite list [cite ptr ]; entry exists [cite ptr ] ← false; incr (cite ptr ); end;

cite ptr ← all marker ; { we insert the “other” entries here }

end else begin cite ptr ← num cites ; { we insert the cross-referenced entries here }

all marker ← any value; { to appease PASCAL’s boolean evaluation } end;

end

This code is used in section 225.

229. Before we actually start the code for reading a database file, we must define this -specific scanning function. It skips over white space characters until hitting a nonwhite character or the end of the file, respectively returning true or false. It also updates bib line num, the line counter. ⟨ Procedures and functions for input scanning 84 ⟩ +≡ function eat bib white space: boolean;

label exit ;

begin while (¬scan white space) do { no characters left; read another line }

begin if (¬input ln(cur bib file)) then { end-of-file; return false } begin eat bib white space ← false; return; end;

incr (bib line num); buf ptr2 ← 0;

end; eat bib white space ← true;

exit : end; 230. It’s often illegal to end a command in certain places, and this is where we come to check.

define eat bib white and eof check ≡

begin if (¬eat bib white space) then begin eat bib print ; return; end; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure eat bib print ;

label exit ; { so the call to bib err works }

begin bib err (´ ␣ ␣ ␣ ␣ ´ ); exit : end;

231. And here are a bunch of error-message macros, each called more than once, that thus save space as implemented. This one is for when one of two possible characters is expected while scanning.

define bib one of two expected err (#) ≡ begin bib one of two print (#); return; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure bib one of two print (char1 , char2 : ASCII code);

label exit ; { so the call to bib err works }

begin bib err (´ ␣ ␣ ␣ ␣` ´ , xchr [char1 ], ´ ´ ´ ␣ ␣ ␣` ´ , xchr [char2 ], ´ ´ ´ ´ ); exit : end;

232. This one’s for an expected equals sign.

define bib equals sign expected err ≡ begin bib equals sign print ; return; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure bib equals sign print ;

label exit ; { so the call to bib err works }

begin bib err (´ ␣ ␣ ␣ ␣ ´ , xchr [equals sign], ´ ´ ); exit : end;

233. This complains about unbalanced braces.

define bib unbalanced braces err ≡ begin bib unbalanced braces print ; return; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure bib unbalanced braces print ;

label exit ; { so the call to bib err works }

begin bib err (´ ␣ ´ ); exit : end; 234. And this one about an overly exuberant field.

define bib field too long err ≡ begin bib field too long print ; return; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure bib field too long print ;

label exit ; { so the call to bib err works }

begin bib err (´ ␣ ␣ ␣ ␣ ␣´ , buf size : 0, ´ ␣ ´ ); exit : end;

235. This one is just a warning, not an error. It’s for when something isn’t (or might not be) quite right with a macro name.

define macro name warning (#) ≡ begin macro warn print ; bib warn newline(#); end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure macro warn print ;

begin print (´ ␣ ␣ ´ ); print token; print (´ ␣ ␣´ ); end;

236. This macro is used to scan all identifiers. The argument tells what was happening at the time. The associated procedure simply prints an error message.

define bib identifier scan check (#) ≡

begin if ((scan result = white adjacent ) ∨ (scan result = specified char adjacent )) then

do nothing else begin bib id print ; bib err (#);

end; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure bib id print ;

begin if (scan result = id null ) then print (´ ´ ´ ␣ ␣´ )

else if (scan result = other char adjacent ) then

print (´ ´ , xchr [scan char ], ´ ␣ ␣ ␣´ ) else id scanning confusion;

end; 237. This module either reads a database entry, whose three main components are an entry type, a database key, and a list of fields, or it reads a command, whose structure is command dependent and explained later.

define cite already set = 22 { this gets around PASCAL limitations } define first time entry = 26 { for checking for repeated database entries }

⟨ Scan for and process a command or database entry 237 ⟩ ≡ procedure get bib command or entry and process ;

label cite already set , first time entry , loop exit , exit ; begin at bib command ← false; ⟨ Skip to the next database entry or command 238 ⟩; ⟨ Scan the entry type or scan and process the command 239 ⟩; eat bib white and eof check ; ⟨ Scan the entry’s database key 267 ⟩; eat bib white and eof check ; ⟨ Scan the entry’s list of fields 275 ⟩;

exit : end;

This code is used in section 211.

238. This module skips over everything until hitting an at sign or the end of the file. It also updates bib line num, the line counter. ⟨ Skip to the next database entry or command 238 ⟩ ≡

while (¬scan1 (at sign)) do { no at sign; get next line }

begin if (¬input ln(cur bib file)) then { end-of-file }

return; incr (bib line num); buf ptr2 ← 0; end

This code is used in section 237.

239. This module reads an at sign and an entry type (like ‘book’ or ‘article’) or a command. If it’s an entry type, it must be defined in the file if this entry is to be included in the reference list. ⟨ Scan the entry type or scan and process the command 239 ⟩ ≡

begin if (scan char ≠ at sign) then confusion(´ ␣ ´ , xchr [at sign], ´ ␣ ´ ); incr (buf ptr2 ); { skip over the at sign } eat bib white and eof check ; scan identifier (left brace, left paren, left paren); bib identifier scan check (´ ␣ ␣ ´ ); trace trace pr token; trace pr ln(´ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ´ ); ecart lower case(buffer , buf ptr1 , token len); { ignore case differences } command num ← ilk info[str lookup(buffer , buf ptr1 , token len, bib command ilk , dont insert )]; if (hash found ) then ⟨ Process a command 240 ⟩ else begin { process an entry type }

entry type loc ← str lookup(buffer , buf ptr1 , token len, bst fn ilk , dont insert ); if ((¬hash found ) ∨ (fn type[entry type loc] ≠ wiz defined )) then

type exists ← false { no such entry type defined in the file } else type exists ← true; end;

end

This code is used in section 237.

240. Here we determine which command we’re about to process, then go to it. ⟨ Process a command 240 ⟩ ≡

begin at bib command ← true; case (command num) of n bib comment : ⟨ Process a command 242 ⟩; n bib preamble: ⟨ Process a command 243 ⟩; n bib string : ⟨ Process a command 244 ⟩;

othercases bib cmd confusion

endcases; end

This code is used in section 239.

241. Here’s another bug. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure bib cmd confusion;

begin confusion(´ ␣ ␣ ´ ); end;

242. The command is implemented for SCRIBE compatibility. It’s not really needed because BibTEX treats (flushes) everything not within an entry as a comment anyway. ⟨ Process a command 242 ⟩ ≡

begin return; { flush comments } end

This code is used in section 240.

243. The command lets a user have TEX stuff inserted (by the standard styles, at least) directly into the file. It is intended primarily for allowing TEX macro definitions used within the bibliography entries (for better sorting, for example). One command per file should suffice.

A command has either braces or parentheses as outer delimiters. Inside is the preamble string, which has the same syntax as a field value: a nonempty list of field tokens separated by concat char s. There are three types of field tokens—nonnegative numbers, macro names, and delimited strings.

This module does all the scanning (that’s not subcontracted), but the -specific scanning function scan and store the field value and eat white actually stores the value. ⟨ Process a command 243 ⟩ ≡

begin if (preamble ptr = max bib files ) then

bib err (´ ´ ´ ␣ ␣´ , max bib files : 0, ´ ␣ ␣ ´ ); eat bib white and eof check ; if (scan char = left brace) then right outer delim ← right brace else if (scan char = left paren) then right outer delim ← right paren

else bib one of two expected err (left brace, left paren); incr (buf ptr2 ); { skip over the left-delimiter } eat bib white and eof check ; store field ← true; if (¬scan and store the field value and eat white) then return; if (scan char ≠ right outer delim) then

bib err (´ ␣ ´ , xchr [right outer delim], ´ ␣ ␣ ␣ ´ ); incr (buf ptr2 ); { skip over the right outer delim } return; end

This code is used in section 240.

244. The command is implemented both for SCRIBE compatibility and for allowing a user: to override a -file command, to define one that the file doesn’t, or to engage in good, wholesome, typing laziness.

The command does mostly the same thing as the -file’s command (but the syntax is different and the command compresses white space). In fact, later in this program, the term “macro” refers to either a “macro” or a “string” (when it’s clear from the context that it’s not a macro).

A command has either braces or parentheses as outer delimiters. Inside is the string’s name (it must be a legal identifier, and case differences are ignored—all upper-case letters are converted to lower case), then an equals sign, and the string’s definition, which has the same syntax as a field value: a nonempty list of field tokens separated by concat char s. There are three types of field tokens—nonnegative numbers, macro names, and delimited strings. ⟨ Process a command 244 ⟩ ≡

begin eat bib white and eof check ; ⟨ Scan the string’s name 245 ⟩; eat bib white and eof check ; ⟨ Scan the string’s definition field 247 ⟩; return; end

This code is used in section 240.

245. This module reads a left outer-delimiter and a string name. ⟨ Scan the string’s name 245 ⟩ ≡

begin if (scan char = left brace) then right outer delim ← right brace else if (scan char = left paren) then right outer delim ← right paren

else bib one of two expected err (left brace, left paren); incr (buf ptr2 ); { skip over the left-delimiter } eat bib white and eof check ; scan identifier (equals sign, equals sign, equals sign); bib identifier scan check (´ ␣ ␣ ´ ); ⟨ Store the string’s name 246 ⟩; end

This code is used in section 244.

246. This module marks this string as macro ilk ; the commented-out code will give a warning message when overwriting a previously defined macro. ⟨ Store the string’s name 246 ⟩ ≡

begin trace trace pr token; trace pr ln(´ ␣ ␣ ␣ ␣ ´ ); ecart lower case(buffer , buf ptr1 , token len); { ignore case differences } cur macro loc ← str lookup(buffer , buf ptr1 , token len, macro ilk , do insert ); ilk info[cur macro loc] ← hash text [cur macro loc]; { default in case of error }

if (hash found ) then { already seen macro } macro name warning (´ ␣ ␣ ␣ ´ );

end

This code is used in section 245.

247. This module skips over the equals sign, reads and stores the list of field tokens that defines this macro (compressing white space), and reads a right outer delim. ⟨ Scan the string’s definition field 247 ⟩ ≡

begin if (scan char ≠ equals sign) then bib equals sign expected err ; incr (buf ptr2 ); { skip over the equals sign } eat bib white and eof check ; store field ← true; if (¬scan and store the field value and eat white) then return; if (scan char ≠ right outer delim) then

bib err (´ ␣ ´ , xchr [right outer delim], ´ ␣ ␣ ␣ ´ ); incr (buf ptr2 ); { skip over the right outer delim } end

This code is used in section 244.

248. The variables for the function scan and store the field value and eat white must be global since the functions it calls use them too. The alias kludge helps make the stack space not overflow on some machines.

define field vl str ≡ ex buf { aliases, used “only” for this function } define field end ≡ ex buf ptr { the end marker for the field-value string } define field start ≡ ex buf xptr { and the start marker }

⟨ Globals in the outer block 16 ⟩ +≡ bib brace level : integer ; { brace nesting depth (excluding str delims) }

249. Since the function scan and store the field value and eat white calls several other yet-to-be-described functions (one directly and two indirectly), we must perform some topological gymnastics. ⟨ Procedures and functions for input scanning 84 ⟩ +≡

⟨ The scanning function compress bib white 253 ⟩ ⟨ The scanning function scan balanced braces 254 ⟩ ⟨ The scanning function scan a field token and eat white 251 ⟩

250. This function scans the list of field tokens that define the field value string. If store field is true it accumulates (indirectly) in field vl str the concatenation of all the field tokens, compressing nonnull white space to a single space and, if the field value is for a field (rather than a string definition), removing any leading or trailing white space; when it’s finished it puts the string into the hash table. It returns false if there was a serious syntax error. ⟨ Procedures and functions for input scanning 84 ⟩ +≡ function scan and store the field value and eat white: boolean;

label exit ; begin scan and store the field value and eat white ← false; { now it’s easy to exit if necessary } field end ← 0; if (¬scan a field token and eat white) then return; while (scan char = concat char ) do { scan remaining field tokens }

begin incr (buf ptr2 ); { skip over the concat char }

eat bib white and eof check ;

if (¬scan a field token and eat white) then return;

end; if (store field ) then ⟨ Store the field value string 262 ⟩; scan and store the field value and eat white ← true;

exit : end; 251. Each field token is either a nonnegative number, a macro name (like ‘jan’), or a brace-balanced string delimited by either double quotes or braces. Thus there are four possibilities for the first character of the field token: If it’s a left brace or a double quote, the token (with balanced braces, up to the matching right str delim) is a string; if it’s numeric, the token is a number; if it’s anything else, the token is a macro name (and should thus have been defined by either the -file’s command or the -file’s command). This function returns false if there was a serious syntax error. ⟨ The scanning function scan a field token and eat white 251 ⟩ ≡ function scan a field token and eat white: boolean;

label exit ;

begin scan a field token and eat white ← false; { now it’s easy to exit if necessary } case (scan char ) of left brace: begin right str delim ← right brace;

if (¬scan balanced braces ) then return; end;

double quote: begin right str delim ← double quote; if (¬scan balanced braces ) then return; end;

, , , , , , , , , : ⟨ Scan a number 259 ⟩;

othercases ⟨ Scan a macro name 260 ⟩

endcases; eat bib white and eof check ; scan a field token and eat white ← true; exit : end;

This code is used in section 249.

252. Now we come to the stuff that actually accumulates the field value to be stored. This module copies a character into field vl str if it will fit; since it’s so low level, it’s implemented as a macro.

define copy char (#) ≡ begin if (field end = buf size) then bib field too long err else begin field vl str [field end ] ← #; incr (field end );

end; end 253. The -specific scanning function compress bib white skips over white space characters within a string until hitting a nonwhite character; in fact, it does everything eat bib white space does, but it also adds a space to field vl str . This function is never called if there are no white space characters (or ends-of-line) to be scanned (though the associated macro might be). The function returns false if there is a serious syntax error.

define check for and compress bib white space ≡

begin if ((lex class [scan char ] = white space) ∨ (buf ptr2 = last )) then

if (¬compress bib white) then return; end

⟨ The scanning function compress bib white 253 ⟩ ≡ function compress bib white: boolean;

label exit ; begin compress bib white ← false; { now it’s easy to exit if necessary } copy char (space); while (¬scan white space) do { no characters left; read another line }

begin if (¬input ln(cur bib file)) then { end-of-file; complain } begin eat bib print ; return; end;

incr (bib line num); buf ptr2 ← 0;

end; compress bib white ← true;

exit : end;

This code is used in section 249.

254. This -specific function scans a string with balanced braces, stopping just past the matching right str delim. How much work it does depends on whether store field = true. It returns false if there was a serious syntax error. ⟨ The scanning function scan balanced braces 254 ⟩ ≡ function scan balanced braces : boolean;

label loop exit , exit ; begin scan balanced braces ← false; { now it’s easy to exit if necessary } incr (buf ptr2 ); { skip over the left-delimiter } check for and compress bib white space; if (field end > 1) then

if (field vl str [field end − 1] = space) then

if (field vl str [field end − 2] = space) then { remove wrongly added space }

decr (field end ); bib brace level ← 0; { and we’re at a nonwhite space character } if (store field ) then ⟨ Do a full brace-balanced scan 257 ⟩ else ⟨ Do a quick brace-balanced scan 255 ⟩; incr (buf ptr2 ); { skip over the right str delim } scan balanced braces ← true;

exit : end;

This code is used in section 249.

255. This module scans over a brace-balanced string without keeping track of anything but the brace level. It starts with bib brace level = 0 and at a nonwhite space character. ⟨ Do a quick brace-balanced scan 255 ⟩ ≡

begin while (scan char ≠ right str delim) do { we’re at bib brace level = 0 }

if (scan char = left brace) then begin incr (bib brace level ); incr (buf ptr2 ); { skip over the left brace } eat bib white and eof check ; while (bib brace level > 0) do ⟨ Do a quick scan with bib brace level > 0 256 ⟩; end

else if (scan char = right brace) then bib unbalanced braces err

else begin incr (buf ptr2 ); { skip over some other character } if (¬scan3 (right str delim, left brace, right brace)) then eat bib white and eof check ; end

end

This code is used in section 254.

256. This module does the same as above but, because bib brace level > 0, it doesn’t have to look for a right str delim. ⟨ Do a quick scan with bib brace level > 0 256 ⟩ ≡

begin { top part of the while loop—we’re always at a nonwhite character } if (scan char = right brace) then

begin decr (bib brace level ); incr (buf ptr2 ); { skip over the right brace } eat bib white and eof check ; end

else if (scan char = left brace) then begin incr (bib brace level ); incr (buf ptr2 ); { skip over the left brace } eat bib white and eof check ; end

else begin incr (buf ptr2 ); { skip over some other character } if (¬scan2 (right brace, left brace)) then eat bib white and eof check ; end

end

This code is used in section 255.

257. This module scans over a brace-balanced string, compressing multiple white space characters into a single space. It starts with bib brace level = 0 and starts at a nonwhite space character. ⟨ Do a full brace-balanced scan 257 ⟩ ≡

begin while (scan char ≠ right str delim) do case (scan char ) of left brace: begin incr (bib brace level ); copy char (left brace);

incr (buf ptr2 ); { skip over the left brace } check for and compress bib white space; ⟨ Do a full scan with bib brace level > 0 258 ⟩; end;

right brace: bib unbalanced braces err ; othercases begin copy char (scan char ); incr (buf ptr2 ); { skip over some other character }

check for and compress bib white space; end

endcases; end

This code is used in section 254.

258. This module is similar to the last but starts with bib brace level > 0 (and, like the last, it starts at a nonwhite space character). ⟨ Do a full scan with bib brace level > 0 258 ⟩ ≡

begin loop

case (scan char ) of right brace: begin decr (bib brace level ); copy char (right brace);

incr (buf ptr2 ); { skip over the right brace } check for and compress bib white space; if (bib brace level = 0) then goto loop exit ; end;

left brace: begin incr (bib brace level ); copy char (left brace); incr (buf ptr2 ); { skip over the left brace } check for and compress bib white space; end;

othercases begin copy char (scan char ); incr (buf ptr2 ); { skip over some other character } check for and compress bib white space; end

endcases; loop exit : end

This code is used in section 257.

259. This module scans a nonnegative number and copies it to field vl str if it’s to store the field. ⟨ Scan a number 259 ⟩ ≡

begin if (¬scan nonneg integer ) then confusion(´ ␣ ␣ ´ ); if (store field ) then

begin tmp ptr ← buf ptr1 ; while (tmp ptr < buf ptr2 ) do

begin copy char (buffer [tmp ptr ]); incr (tmp ptr ); end;

end; end

This code is used in section 251.

260. This module scans a macro name and copies its string to field vl str if it’s to store the field, complaining if the macro is recursive or undefined. ⟨ Scan a macro name 260 ⟩ ≡

begin scan identifier (comma, right outer delim, concat char ); bib identifier scan check (´ ␣ ␣ ´ ); if (store field ) then

begin lower case(buffer , buf ptr1 , token len); { ignore case differences } macro name loc ← str lookup(buffer , buf ptr1 , token len, macro ilk , dont insert ); store token ← true; if (at bib command ) then

if (command num = n bib string ) then

if (macro name loc = cur macro loc) then begin store token ← false; macro name warning (´ ␣ ␣ ␣ ␣ ´ ); end;

if (¬hash found ) then begin store token ← false; macro name warning (´ ´ ); end;

if (store token) then ⟨ Copy the macro string to field vl str 261 ⟩; end;

end

This code is used in section 251.

261. The macro definition may have white space that needs compressing, because it may have been defined in the file. ⟨ Copy the macro string to field vl str 261 ⟩ ≡

begin tmp ptr ← str start [ilk info[macro name loc]]; tmp end ptr ← str start [ilk info[macro name loc] + 1]; if (field end = 0) then

if ((lex class [str pool [tmp ptr ]] = white space) ∧ (tmp ptr < tmp end ptr )) then begin { compress leading white space of first nonnull token } copy char (space); incr (tmp ptr ); while ((lex class [str pool [tmp ptr ]] = white space) ∧ (tmp ptr < tmp end ptr )) do incr (tmp ptr ); end; { the next remaining character is nonwhite space }

while (tmp ptr < tmp end ptr ) do begin if (lex class [str pool [tmp ptr ]] ≠ white space) then copy char (str pool [tmp ptr ]) else if (field vl str [field end − 1] ≠ space) then copy char (space); incr (tmp ptr ); end;

end

This code is used in section 260.

262. Now it’s time to store the field value in the hash table, and store an appropriate pointer to it (depending on whether it’s for a database entry or command). But first, if necessary, we remove a trailing space and a leading space if these exist. (Hey, if we had some ham we could make ham-and-eggs if we had some eggs.) ⟨ Store the field value string 262 ⟩ ≡

begin if (¬at bib command ) then { chop trailing space for a field }

if (field end > 0) then

if (field vl str [field end − 1] = space) then decr (field end ); if ((¬at bib command ) ∧ (field vl str [0] = space) ∧ (field end > 0)) then { chop leading space for a field }

field start ← 1 else field start ← 0; field val loc ← str lookup(field vl str , field start , field end − field start , text ilk , do insert ); fn type[field val loc] ← str literal ; { set the fn class } trace trace pr (´ ´ ); trace pr pool str (hash text [field val loc]); trace pr ln(´ ␣ ␣ ␣ ␣ ´ ); ecart if (at bib command ) then { for a or command }

⟨ Store the field value for a command 263 ⟩ else { for a database entry } ⟨ Store the field value for a database entry 264 ⟩; end

This code is used in section 250.

263. Here’s where we store the goods when we’re dealing with a command rather than an entry. ⟨ Store the field value for a command 263 ⟩ ≡

begin case (command num) of n bib preamble: begin s preamble[preamble ptr ] ← hash text [field val loc]; incr (preamble ptr );

end; n bib string : ilk info[cur macro loc] ← hash text [field val loc];

othercases bib cmd confusion

endcases; end

This code is used in section 262.

264. And here, an entry. ⟨ Store the field value for a database entry 264 ⟩ ≡

begin field ptr ← entry cite ptr ∗ num fields + fn info[field name loc]; if (field info[field ptr ] ≠ missing ) then

begin print (´ ´ ´ ␣ ␣´ ); print pool str (cite list [entry cite ptr ]); print (´ ´ ´ ␣ ␣ ´ ); print pool str (hash text [field name loc]); bib warn newline(´ ␣ ´ ); end

else begin { the field was empty, store its new value } field info[field ptr ] ← hash text [field val loc]; if ((fn info[field name loc] = crossref num) ∧ (¬all entries )) then

⟨ Add or update a cross reference on cite list if necessary 265 ⟩; end;

end

This code is used in section 262.

265. If the cross-referenced entry isn’t already on cite list we add it (at least temporarily); if it is already on cite list we update the cross-reference count, if necessary. Note that all entries is false here. The alias kludge helps make the stack space not overflow on some machines.

define extra buf ≡ out buf { an alias, used only in this module } ⟨ Add or update a cross reference on cite list if necessary 265 ⟩ ≡

begin tmp ptr ← field start ; while (tmp ptr < field end ) do

begin extra buf [tmp ptr ] ← field vl str [tmp ptr ]; incr (tmp ptr );

end; lower case(extra buf , field start , field end − field start ); { convert to ‘canonical’ form } lc cite loc ← str lookup(extra buf , field start , field end − field start , lc cite ilk , do insert ); if (hash found ) then

begin cite loc ← ilk info[lc cite loc]; { even if there’s a case mismatch } if (ilk info[cite loc] ≥ old num cites ) then { a previous }

incr (cite info[ilk info[cite loc]]); end

else begin { it’s a new } cite loc ← str lookup(field vl str , field start , field end − field start , cite ilk , do insert ); if (hash found ) then hash cite confusion; add database cite(cite ptr ); { this increments cite ptr } cite info[ilk info[cite loc]] ← 1; { the first cross-ref for this cite key } end;

end

This code is used in section 264.

266. This procedure adds (or restores) to cite list a cite key; it is called only when all entries is true or when adding cross references, and it assumes that cite loc and lc cite loc are set. It also increments its argument. ⟨ Procedures and functions for handling numbers, characters, and strings 55 ⟩ +≡ procedure add database cite(var new cite : cite number );

begin check cite overflow (new cite); { make sure this cite will fit } check field overflow (num fields ∗ new cite); cite list [new cite] ← hash text [cite loc]; ilk info[cite loc] ← new cite; ilk info[lc cite loc] ← cite loc; incr (new cite); end; 267. And now, back to processing an entry (rather than a command). This module reads a left outerdelimiter and a database key. ⟨ Scan the entry’s database key 267 ⟩ ≡

begin if (scan char = left brace) then right outer delim ← right brace else if (scan char = left paren) then right outer delim ← right paren

else bib one of two expected err (left brace, left paren); incr (buf ptr2 ); { skip over the left-delimiter } eat bib white and eof check ; if (right outer delim = right paren) then { to allow it in a database key }

begin if (scan1 white(comma)) then { ok if database key ends line }

do nothing ; end

else if (scan2 white(comma, right brace)) then { right brace = right outer delim }

do nothing ; ⟨ Check for a database key of interest 268 ⟩; end

This code is used in section 237.

268. The lower-case version of this database key must correspond to one in cite list , or else all entries must be true, if this entry is to be included in the reference list. Accordingly, this module sets store entry , which determines whether the relevant information for this entry is stored. The alias kludge helps make the stack space not overflow on some machines.

define ex buf3 ≡ ex buf { an alias, used only in this module } ⟨ Check for a database key of interest 268 ⟩ ≡

begin trace trace pr token; trace pr ln(´ ␣ ␣ ␣ ␣ ´ ); ecart tmp ptr ← buf ptr1 ; while (tmp ptr < buf ptr2 ) do

begin ex buf3 [tmp ptr ] ← buffer [tmp ptr ]; incr (tmp ptr );

end; lower case(ex buf3 , buf ptr1 , token len); { convert to ‘canonical’ form } if (all entries ) then lc cite loc ← str lookup(ex buf3 , buf ptr1 , token len, lc cite ilk , do insert ) else lc cite loc ← str lookup(ex buf3 , buf ptr1 , token len, lc cite ilk , dont insert ); if (hash found ) then

begin entry cite ptr ← ilk info[ilk info[lc cite loc]];

⟨ Check for a duplicate or -matching database key 269 ⟩; end;

store entry ← true; { unless (¬hash found ) ∧ (¬all entries ) } if (all entries ) then ⟨ Put this cite key in its place 273 ⟩ else if (¬hash found ) then store entry ← false; { no such cite key exists on cite list } if (store entry ) then ⟨ Make sure this entry is ok before proceeding 274 ⟩; end

This code is used in section 267.

269. It’s illegal to have two (or more) entries with the same database key (even if there are case differrences), and we skip the rest of the entry for such a repeat occurrence. Also, we make this entry’s database key the official cite list key if it’s on cite list only because of cross references. ⟨ Check for a duplicate or -matching database key 269 ⟩ ≡

begin if ((¬all entries ) ∨ (entry cite ptr < all marker ) ∨ (entry cite ptr ≥ old num cites )) then

begin if (type list [entry cite ptr ] = empty ) then begin ⟨ Make sure this entry’s database key is on cite list 270 ⟩; goto first time entry ; end;

end else if (¬entry exists [entry cite ptr ]) then

begin ⟨ Find the lower-case equivalent of the cite info key 271 ⟩; if (lc xcite loc = lc cite loc) then goto first time entry ; end;

{ oops—repeated entry—issue a reprimand } if (type list [entry cite ptr ] = empty ) then confusion(´ ␣ ␣ ␣ ␣ ␣ ´ ); bib err (´ ␣ ´ );

first time entry : { note that when we leave normally, hash found is true }

end

This code is used in section 268.

270. An entry that’s on cite list only because of cross referencing must have its database key (rather than one of the keys) as the official cite list string. Here’s where we assure that. The variable hash found is true upon entrance to and exit from this module. ⟨ Make sure this entry’s database key is on cite list 270 ⟩ ≡

begin if ((¬all entries ) ∧ (entry cite ptr ≥ old num cites )) then begin cite loc ← str lookup(buffer , buf ptr1 , token len, cite ilk , do insert ); if (¬hash found ) then

begin { it’s not on cite list —put it there } ilk info[lc cite loc] ← cite loc; ilk info[cite loc] ← entry cite ptr ; cite list [entry cite ptr ] ← hash text [cite loc]; hash found ← true; { restore this value for later use } end;

end; end

This code is used in section 269.

271. This module, a simpler version of the find cite locs for this cite key function, exists primarily to compute lc xcite loc. When this code is executed we have (all entries ) ∧ (entry cite ptr ≥ all marker ) ∧ (¬entry exists [entry cite ptr ]). The alias kludge helps make the stack space not overflow on some machines.

define ex buf4 ≡ ex buf { aliases, used only }

define ex buf4 ptr ≡ ex buf ptr { in this module } ⟨ Find the lower-case equivalent of the cite info key 271 ⟩ ≡

begin ex buf4 ptr ← 0; tmp ptr ← str start [cite info[entry cite ptr ]];

tmp end ptr ← str start [cite info[entry cite ptr ] + 1];

while (tmp ptr < tmp end ptr ) do begin ex buf4 [ex buf4 ptr ] ← str pool [tmp ptr ]; incr (ex buf4 ptr ); incr (tmp ptr ); end;

lower case(ex buf4 , 0, length(cite info[entry cite ptr ])); { convert to ‘canonical’ form } lc xcite loc ← str lookup(ex buf4 , 0, length(cite info[entry cite ptr ]), lc cite ilk , dont insert ); if (¬hash found ) then cite key disappeared confusion; end

This code is used in section 269.

272. Here’s another bug complaint. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure cite key disappeared confusion;

begin confusion(´ ␣ ␣ ␣ ´ );

end;

273. This module, which gets executed only when all entries is true, does one of three things, depending on whether or not, and where, the cite key appears on cite list : If it’s on cite list before all marker , there’s nothing to be done; if it’s after all marker , it must be reinserted (at the current place) and we must note that its corresponding entry exists; and if it’s not on cite list at all, it must be inserted for the first time. The goto construct must stay as is, partly because some PASCAL compilers might complain if “∧” were to connect the two boolean expressions (since entry cite ptr could be uninitialized when hash found is false). ⟨ Put this cite key in its place 273 ⟩ ≡

begin if (hash found ) then begin if (entry cite ptr < all marker ) then goto cite already set { that is, do nothing } else begin entry exists [entry cite ptr ] ← true; cite loc ← ilk info[lc cite loc];

end; end

else begin { this is a new key } cite loc ← str lookup(buffer , buf ptr1 , token len, cite ilk , do insert ); if (hash found ) then hash cite confusion; end;

entry cite ptr ← cite ptr ; add database cite(cite ptr ); { this increments cite ptr } cite already set : end

This code is used in section 268.

274. We must give a warning if this entry type doesn’t exist. Also, we point the appropriate entry of type list to the entry type just read above.

For SCRIBE compatibility, the code to give a warning for a case mismatch between a cite key and a database key has been commented out. In fact, SCRIBE is the reason that it doesn’t produce an error message outright. (Note: Case mismatches between two cite keys produce full-blown errors.) ⟨ Make sure this entry is ok before proceeding 274 ⟩ ≡

begin dummy loc ← str lookup(buffer , buf ptr1 , token len, cite ilk , dont insert ); if (¬hash found ) then { give a warning if there is a case difference }

begin print (´ ␣ ␣ ␣ ␣ ´ ); print token; print (´ ␣ ␣ ␣ ´ ); print pool str (cite list [entry cite ptr ]); bib warn newline(´ ´ ); end;

if (type exists ) then type list [entry cite ptr ] ← entry type loc else begin type list [entry cite ptr ] ← undefined ; print (´ ␣ ␣ ␣ ´ ); print token;

bib warn newline(´ ␣ ´ ´ ␣ ␣ ´ ); end;

end

This code is used in section 268.

275. This module reads a comma and a field as many times as it can, and then reads a right outer delim, ending the current entry. ⟨ Scan the entry’s list of fields 275 ⟩ ≡

begin while (scan char ≠ right outer delim) do begin if (scan char ≠ comma) then bib one of two expected err (comma, right outer delim); incr (buf ptr2 ); { skip over the comma } eat bib white and eof check ; if (scan char = right outer delim) then goto loop exit ; ⟨ Get the next field name 276 ⟩; eat bib white and eof check ; if (¬scan and store the field value and eat white) then return; end;

loop exit : incr (buf ptr2 ); { skip over the right outer delim }

end

This code is used in section 237.

276. This module reads a field name; its contents won’t be stored unless it was declared in the file and store entry = true. ⟨ Get the next field name 276 ⟩ ≡

begin scan identifier (equals sign, equals sign, equals sign); bib identifier scan check (´ ␣ ␣ ´ ); trace trace pr token; trace pr ln(´ ␣ ␣ ␣ ␣ ´ ); ecart store field ← false; if (store entry ) then

begin lower case(buffer , buf ptr1 , token len); { ignore case differences } field name loc ← str lookup(buffer , buf ptr1 , token len, bst fn ilk , dont insert ); if (hash found ) then

if (fn type[field name loc] = field ) then

store field ← true; { field name was pre-defined or -declared } end;

eat bib white and eof check ; if (scan char ≠ equals sign) then bib equals sign expected err ; incr (buf ptr2 ); { skip over the equals sign } end

This code is used in section 275.

277. This gets things ready for further processing. ⟨ Final initialization for processing the entries 277 ⟩ ≡

begin num cites ← cite ptr ; { to include database and cite keys, too } num preamble strings ← preamble ptr ; { number of commands seen } ⟨ Add cross-reference information 278 ⟩; ⟨ Subtract cross-reference information 280 ⟩; ⟨ Remove missing entries or those cross referenced too few times 284 ⟩; ⟨ Initialize the int entry var s 288 ⟩; ⟨ Initialize the str entry var s 289 ⟩; ⟨ Initialize the sorted cites 290 ⟩; end

This code is used in section 224.

278. Now we update any entry (here called a child entry) that cross referenced another (here called a parent entry); this cross referencing occurs when the child’s field (value) consists of the parent’s database key. To do the update, we replace the child’s missing fields by the corresponding fields of the parent. Also, we make sure the field contains the case-correct version. Finally, although it is technically illegal to nest cross references, and although we give a warning (a few modules hence) when someone tries, we do what we can to accommodate the attempt. ⟨ Add cross-reference information 278 ⟩ ≡

begin cite ptr ← 0;

while (cite ptr < num cites ) do begin field ptr ← cite ptr ∗ num fields + crossref num; if (field info[field ptr ] ≠ missing ) then

if (find cite locs for this cite key (field info[field ptr ])) then begin cite loc ← ilk info[lc cite loc]; field info[field ptr ] ← hash text [cite loc]; cite parent ptr ← ilk info[cite loc]; field ptr ← cite ptr ∗ num fields + num pre defined fields ; field end ptr ← field ptr − num pre defined fields + num fields ; field parent ptr ← cite parent ptr ∗ num fields + num pre defined fields ; while (field ptr < field end ptr ) do

begin if (field info[field ptr ] = missing ) then field info[field ptr ] ← field info[field parent ptr ]; incr (field ptr ); incr (field parent ptr ); end; end; incr (cite ptr ); end;

end

This code is used in section 277.

279. Occasionally we need to figure out the hash-table location of a given cite-key string and its lower-case equivalent. This function does that. To perform the task it needs to borrow a buffer, a need that gives rise to the alias kludge—it helps make the stack space not overflow on some machines (and while it’s at it, it’ll borrow a pointer, too). Finally, the function returns true if the cite key exists on cite list , and its sets cite hash found according to whether or not it found the actual version (before lower caseing) of the cite key; however, its raison d’être (literally, “to eat a raisin”) is to compute cite loc and lc cite loc.

define ex buf5 ≡ ex buf { aliases, used only }

define ex buf5 ptr ≡ ex buf ptr { in this module } ⟨ Procedures and functions for handling numbers, characters, and strings 55 ⟩ +≡ function find cite locs for this cite key (cite str : str number ): boolean;

begin ex buf5 ptr ← 0; tmp ptr ← str start [cite str ]; tmp end ptr ← str start [cite str + 1]; while (tmp ptr < tmp end ptr ) do

begin ex buf5 [ex buf5 ptr ] ← str pool [tmp ptr ]; incr (ex buf5 ptr ); incr (tmp ptr ); end;

cite loc ← str lookup(ex buf5 , 0, length(cite str ), cite ilk , dont insert ); cite hash found ← hash found ; lower case(ex buf5 , 0, length(cite str )); { convert to ‘canonical’ form } lc cite loc ← str lookup(ex buf5 , 0, length(cite str ), lc cite ilk , dont insert ); if (hash found ) then find cite locs for this cite key ← true else find cite locs for this cite key ← false; end; 280. Here we remove the field value for each child whose parent was cross referenced too few times. We also issue any necessary warnings arising from a bad cross reference. ⟨ Subtract cross-reference information 280 ⟩ ≡

begin cite ptr ← 0;

while (cite ptr < num cites ) do begin field ptr ← cite ptr ∗ num fields + crossref num; if (field info[field ptr ] ≠ missing ) then

if (¬find cite locs for this cite key (field info[field ptr ])) then begin { the parent is not on cite list } if (cite hash found ) then hash cite confusion; nonexistent cross reference error ; field info[field ptr ] ← missing ; { remove the ptr } end

else begin { the parent exists on cite list } if (cite loc ≠ ilk info[lc cite loc]) then hash cite confusion; cite parent ptr ← ilk info[cite loc]; if (type list [cite parent ptr ] = empty ) then begin nonexistent cross reference error ; field info[field ptr ] ← missing ; { remove the ptr } end

else begin { the parent exists in the database too } field parent ptr ← cite parent ptr ∗ num fields + crossref num; if (field info[field parent ptr ] ≠ missing ) then ⟨ Complain about a nested cross reference 283 ⟩; if ((¬all entries )∧(cite parent ptr ≥ old num cites )∧(cite info[cite parent ptr ] < min crossrefs ))

then field info[field ptr ] ← missing ; { remove the ptr }

end; end; incr (cite ptr ); end;

end

This code is used in section 277.

281. This procedure exists to save space, since it’s used twice—once for each of the two succeeding modules. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure bad cross reference print (s : str number );

begin print (´ ␣ ´ ); print pool str (cur cite str ); print ln(´ ´ ); print (´ ␣ ␣ ␣ ´ ); print pool str (s); end;

282. When an entry being cross referenced doesn’t exist on cite list , we complain. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure nonexistent cross reference error ;

begin print (´ ␣ ␣ ␣ ´ ); bad cross reference print (field info[field ptr ]); print ln(´ ␣ ␣ ´ ´ ␣ ´ ); mark error ; end; 283. We also complain when an entry being cross referenced has a nonmissing field itself, but this one is just a warning, not a full-blown error. ⟨ Complain about a nested cross reference 283 ⟩ ≡

begin print (´ ´ ´ ␣ ␣ ␣ ´ ); bad cross reference print (cite list [cite parent ptr ]); print ln(´ ␣ ␣ ␣ ␣ ␣ ´ ); mark warning ; end

This code is used in section 280.

284. We remove (and give a warning for) each cite key on the original cite list without a corresponding database entry. And we remove any entry that was included on cite list only because it was cross referenced, yet was cross referenced fewer than min crossrefs times. Throughout this module, cite ptr points to the next cite key to be checked and cite xptr points to the next permanent spot on cite list . ⟨ Remove missing entries or those cross referenced too few times 284 ⟩ ≡

begin cite ptr ← 0; while (cite ptr < num cites ) do

begin if (type list [cite ptr ] = empty ) then print missing entry (cur cite str )

else if ((all entries ) ∨ (cite ptr < old num cites ) ∨ (cite info[cite ptr ] ≥ min crossrefs )) then begin if (cite ptr > cite xptr ) then ⟨ Slide this cite key down to its permanent spot 286 ⟩; incr (cite xptr ); end;

incr (cite ptr );

end; num cites ← cite xptr ; if (all entries ) then ⟨ Complain about missing entries whose cite keys got overwritten 287 ⟩; end

This code is used in section 277.

285. When a cite key on the original cite list (or added to cite list because of cross referencing) didn’t appear in the database, complain. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure print missing entry (s : str number );

begin print (´ ␣ ´ ´ ␣ ␣ ␣ ␣ ␣ ␣ ´ ); print pool str (s); print ln(´ ´ ); mark warning ; end;

286. We have to move to its final resting place all the entry information associated with the exact location in cite list of this cite key. ⟨ Slide this cite key down to its permanent spot 286 ⟩ ≡

begin cite list [cite xptr ] ← cite list [cite ptr ]; type list [cite xptr ] ← type list [cite ptr ]; if (¬find cite locs for this cite key (cite list [cite ptr ])) then cite key disappeared confusion; if ((¬cite hash found ) ∨ (cite loc ≠ ilk info[lc cite loc])) then hash cite confusion; ilk info[cite loc] ← cite xptr ; field ptr ← cite xptr ∗ num fields ; field end ptr ← field ptr + num fields ; tmp ptr ← cite ptr ∗ num fields ; while (field ptr < field end ptr ) do

begin field info[field ptr ] ← field info[tmp ptr ]; incr (field ptr ); incr (tmp ptr );

end; end

This code is used in section 284.

287. We need this module only when we’re including the whole database. It’s for missing entries whose cite key originally resided in cite list at a spot that another cite key (might have) claimed. ⟨ Complain about missing entries whose cite keys got overwritten 287 ⟩ ≡

begin cite ptr ← all marker ; while (cite ptr < old num cites ) do

begin if (¬entry exists [cite ptr ]) then print missing entry (cite info[cite ptr ]); incr (cite ptr ); end;

end

This code is used in section 284.

288. This module initializes all int entry var s of all entries to 0, the value to which all integers are initialized. ⟨ Initialize the int entry var s 288 ⟩ ≡

begin if (num ent ints ∗ num cites > max ent ints ) then begin print (num ent ints ∗ num cites , ´ ␣´ ); overflow (´ ␣ ␣ ␣ ␣ ␣´ , max ent ints ); end;

int ent ptr ← 0; while (int ent ptr < num ent ints ∗ num cites ) do

begin entry ints [int ent ptr ] ← 0; incr (int ent ptr );

end; end

This code is used in section 277.

289. This module initializes all str entry var s of all entries to the null string, the value to which all strings are initialized. ⟨ Initialize the str entry var s 289 ⟩ ≡

begin if (num ent strs ∗ num cites > max ent strs ) then begin print (num ent strs ∗ num cites , ´ ␣´ ); overflow (´ ␣ ␣ ␣ ␣ ␣´ , max ent strs ); end;

str ent ptr ← 0; while (str ent ptr < num ent strs ∗ num cites ) do

begin entry strs [str ent ptr ][0] ← end of string ; incr (str ent ptr );

end; end

This code is used in section 277.

290. The array sorted cites initially specifies that the entries are to be processed in order of cite-key occurrence. The command may change this to whatever it likes (which, we hope, is whatever the style-designer instructs it to like). We make sorted cites an alias to save space; this works fine because we’re done with cite info.

define sorted cites ≡ cite info { an alias used for the rest of the program } ⟨ Initialize the sorted cites 290 ⟩ ≡

begin cite ptr ← 0; while (cite ptr < num cites ) do

begin sorted cites [cite ptr ] ← cite ptr ; incr (cite ptr );

end; end

This code is used in section 277.

§291 BibTEX EXECUTING THE STYLE FILE 97

291. Executing the style file. This part of the program produces the output by executing the - file commands , , , and . To do this it uses a stack (consisting of the two arrays lit stack and lit stk type) for storing literals, a buffer ex buf for manipulating strings, and an array sorted cites for holding pointers to the sorted cite keys (sorted cites is an alias of cite info). ⟨ Globals in the outer block 16 ⟩ +≡ lit stack : array [lit stk loc] of integer ; { the literal function stack } lit stk type: array [lit stk loc] of stk type; { their corresponding types } lit stk ptr : lit stk loc; { points just above the top of the stack } cmd str ptr : str number ; { stores value of str ptr during execution } ent chr ptr : 0 . . ent str size; { points at a str entry var character } glob chr ptr : 0 . . glob str size; { points at a str global var character } ex buf : buf type; { a buffer for manipulating strings } ex buf ptr : buf pointer ; { general ex buf location } ex buf length: buf pointer ; { the length of the current string in ex buf } out buf : buf type; { the output buffer } out buf ptr : buf pointer ; { general out buf location } out buf length: buf pointer ; { the length of the current string in out buf } mess with entries : boolean; { true if functions can use entry info } sort cite ptr : cite number ; { a loop index for the sorted cite keys } sort key num: str ent loc; { index for the str entry var $ } brace level : integer ; { the brace nesting depth within a string }

292. Where lit stk loc is a stack location, and where stk type gives one of the three types of literals (an integer, a string, or a function) or a special marker. If a lit stk type element is a stk int then the corresponding lit stack element is an integer; if a stk str , then a pointer to a str pool string; and if a stk fn, then a pointer to the function’s hash-table location. However, if the literal should have been a stk str that was the value of a field that happened to be missing , then the special value stk field missing goes on the stack instead; its corresponding lit stack element is a pointer to the field-name’s string. Finally, stk empty is the type of a literal popped from an empty stack.

define stk int = 0 { an integer literal }

define stk str = 1 { a string literal }

define stk fn = 2 { a function literal }

define stk field missing = 3 { a special marker: a field value was missing } define stk empty = 4 { another: the stack was empty when this was popped } define last lit type = 4 { the same number as on the line above }

⟨ Types in the outer block 22 ⟩ +≡ lit stk loc = 0 . . lit stk size; { the stack range } stk type = 0 . . last lit type; { the literal types }

293. And the first output line requires this initialization. ⟨ Set initial values of key variables 20 ⟩ +≡

98  EXECUTING THE STYLE FILE  BibTEX §294

out buf length ← 0; 294. When there’s an error while executing functions, what we do depends on whether the function is messing with the entries. Furthermore this error is serious enough to classify as an error message instead of a warning message. These messages (that is, from bst ex warn) are meant both for the user and for the style designer while debugging.

define bst ex warn(#) ≡ begin { error while executing some function } print (#); bst ex warn print ; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure bst ex warn print ;

begin if (mess with entries ) then begin print (´ ␣ ␣ ␣´ ); print pool str (cur cite str ); end;

print newline; print (´ ␣ ´ ); bst ln num print ; mark error ; end;

295. When an error is so harmless, we print a warning message instead of an error message.

define bst mild ex warn(#) ≡ begin { error while executing some function } print (#); bst mild ex warn print ; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure bst mild ex warn print ;

begin if (mess with entries ) then begin print (´ ␣ ␣ ␣´ ); print pool str (cur cite str ); end;

print newline; bst warn(´ ␣ ´ ); { This does the mark warning } end;

296. It’s illegal to mess with the entry information at certain times; here’s a complaint for these times. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure bst cant mess with entries print ;

begin bst ex warn(´ ␣ ´ ´ ␣ ␣ ␣ ␣ ´ );

end;

297. This module executes a single specified function once. It can’t do anything with the entries. ⟨ Perform an command 297 ⟩ ≡

begin init command execution; mess with entries ← false; execute fn(fn loc); check command execution; end

This code is used in section 179.

298. This module iterates a single specified function for all entries specified by cite list . ⟨ Perform an command 298 ⟩ ≡

begin init command execution; mess with entries ← true; sort cite ptr ← 0; while (sort cite ptr < num cites ) do

begin cite ptr ← sorted cites [sort cite ptr ];

trace trace pr pool str (hash text [fn loc]); trace pr (´ ␣ ␣ ␣ ␣ ␣´ ); trace pr pool str (cur cite str ); trace pr newline; ecart execute fn(fn loc); check command execution; incr (sort cite ptr ); end;

end

This code is used in section 204.

299. This module iterates a single specified function for all entries specified by cite list , but does it in reverse order. ⟨ Perform a command 299 ⟩ ≡

begin init command execution; mess with entries ← true; if (num cites > 0) then

begin sort cite ptr ← num cites ;

repeat decr (sort cite ptr ); cite ptr ← sorted cites [sort cite ptr ]; trace trace pr pool str (hash text [fn loc]); trace pr (´ ␣ ␣ ␣ ␣ ␣ ␣ ␣´ ); trace pr pool str (cur cite str ); trace pr newline; ecart execute fn(fn loc); check command execution;

until (sort cite ptr = 0);

end; end

This code is used in section 213.

300. This module sorts the entries based on $; it is a stable sort. ⟨ Perform a command 300 ⟩ ≡

begin trace trace pr ln(´ ␣ ␣ ´ ); ecart if (num cites > 1) then quick sort (0, num cites − 1); trace trace pr ln(´ ␣ ´ ); ecart end

This code is used in section 215.

301. These next two procedures (actually, one procedures and one function, but who’s counting) are subroutines for quick sort , which follows. The swap procedure exchanges the two elements its arguments point to. ⟨ Procedures and functions for handling numbers, characters, and strings 55 ⟩ +≡ procedure swap(swap1 , swap2 : cite number );

var innocent bystander : cite number ; { the temporary element in an exchange } begin innocent bystander ← sorted cites [swap2 ]; sorted cites [swap2 ] ← sorted cites [swap1 ]; sorted cites [swap1 ] ← innocent bystander ; end; 302. The function less than compares the two $s indirectly pointed to by its arguments and returns true if the first argument’s $ is lexicographically less than the second’s (that is, alphabetically earlier). In case of ties the function compares the indices arg1 and arg2 , which are assumed to be different, and returns true if the first is smaller. This function uses ASCII codes to compare, so it might give “interesting” results when handling nonletters.

define compare return(#) ≡ begin { the compare is finished } less than ← #; return; end

⟨ Procedures and functions for handling numbers, characters, and strings 55 ⟩ +≡ function less than(arg1 , arg2 : cite number ): boolean;

label exit ; var char ptr : 0 . . ent str size; { character index into compared strings }

ptr1 , ptr2 : str ent loc; { the two $ pointers } char1 , char2 : ASCII code; { the two characters being compared }

begin ptr1 ← arg1 ∗ num ent strs + sort key num; ptr2 ← arg2 ∗ num ent strs + sort key num; char ptr ← 0; loop

begin char1 ← entry strs [ptr1 ][char ptr ]; char2 ← entry strs [ptr2 ][char ptr ]; if (char1 = end of string ) then

if (char2 = end of string ) then if (arg1 < arg2 ) then compare return(true) else if (arg1 > arg2 ) then compare return(false)

else { arg1 = arg2 } confusion(´ ␣ ␣ ´ )

else { char2 ≠ end of string }

compare return(true) else { char1 ≠ end of string }

if (char2 = end of string ) then compare return(false) else if (char1 < char2 ) then compare return(true)

else if (char1 > char2 ) then compare return(false); incr (char ptr ); end;

exit : end; 303. The recursive procedure quick sort sorts the entries indirectly pointed to by the sorted cites elements between left end and right end , inclusive, based on the value of the str entry var $. It’s a fairly standard quicksort (for example, see Algorithm 5.2.2Q in The Art of Computer Programming), but uses the median-of-three method to choose the partition element just in case the entries are already sorted (or nearly sorted—humans and ASCII might have different ideas on lexicographic ordering); it is a stable sort. This code generally prefers clarity to assembler-type execution-time efficiency since cite list s will rarely be huge.

The value short list , which must be at least 2 ∗ end offset + 2 for this code to work, tells us the list-length at which the list is small enough to warrant switching over to straight insertion sort from the recursive quicksort. The values here come from modest empirical tests aimed at minimizing, for large cite list s (five hundred or so), the number of comparisons (between keys) plus the number of calls to quick sort . The value end offset must be positive; this helps avoid n^{2} behavior observed when the list starts out nearly, but not completely, sorted (and fairly frequently large cite list s come from entire databases, which fairly frequently are nearly sorted).

define short list = 10 { use straight insertion sort at or below this length }

define end offset = 4 { the index end-offsets for choosing a median-of-three } ⟨ Check the “constant” values for consistency 17 ⟩ +≡

if (short list < 2 ∗ end offset + 2) then bad ← 100 ∗ bad + 22;

304. Here’s the actual procedure.

define next insert = 24 { now insert the next element } ⟨ Procedures and functions for handling numbers, characters, and strings 55 ⟩ +≡ procedure quick sort (left end , right end : cite number );

label next insert ;

var left , right : cite number ; { two general sorted cites pointers } insert ptr : cite number ; { the to-be-(straight)-inserted element } middle: cite number ; { the (left end + right end ) div 2 element } partition: cite number ; { the median-of-three partition element }

begin trace trace pr ln(´ ␣´ , left end : 0, ´ ␣ ␣´ , right end : 0);

ecart

if (right end − left end < short list ) then ⟨ Do a straight insertion sort 305 ⟩

else begin ⟨ Draw out the median-of-three partition element 306 ⟩; ⟨ Do the partitioning and the recursive calls 307 ⟩; end;

end;

305. This code sorts the entries between left end and right end when the difference is less than short list . Each iteration of the outer loop inserts the element indicated by insert ptr into its proper place among the (sorted) elements from left end through insert ptr − 1. ⟨ Do a straight insertion sort 305 ⟩ ≡

begin for insert ptr ← left end + 1 to right end do

begin for right ← insert ptr downto left end + 1 do begin if (less than(sorted cites [right − 1], sorted cites [right ])) then goto next insert ; swap(right − 1, right ); end;

next insert : end;

end

This code is used in section 304.

306. Now we find the median of the three $s to which the three elements sorted cites [left end + end offset ], sorted cites [right end ]−end offset , and sorted cites [(left end +right end )div2] point (a nonzero end offset avoids using as the leftmost of the three elements the one that was swapped there when the old partition element was swapped into its final spot; this turns out to avoid n^{2} behavior when the list is nearly sorted to start with). This code determines which of the six possible permutations we’re dealing with and moves the median element to left end . The comments next to the swap actions give the known orderings of the corresponding elements of sorted cites before the action. ⟨ Draw out the median-of-three partition element 306 ⟩ ≡

begin left ← left end + end offset ; middle ← (left end + right end ) div 2; right ← right end − end offset ; if (less than(sorted cites [left ], sorted cites [middle])) then

if (less than(sorted cites [middle], sorted cites [right ])) then { left < middle < right }

swap(left end , middle) else if (less than(sorted cites [left ], sorted cites [right ])) then { left < right < middle }

swap(left end , right ) else { right < left < middle }

swap(left end , left ) else if (less than(sorted cites [right ], sorted cites [middle])) then { right < middle < left }

swap(left end , middle) else if (less than(sorted cites [right ], sorted cites [left ])) then { middle < right < left }

swap(left end , right ) else { middle < left < right }

swap(left end , left );

end

This code is used in section 304.

307. This module uses the median-of-three computed above to partition the elements into those less than and those greater than the median. Equal $s are sorted by order of occurrence (in cite list ). ⟨ Do the partitioning and the recursive calls 307 ⟩ ≡

begin partition ← sorted cites [left end ]; left ← left end + 1; right ← right end ;

repeat while (less than(sorted cites [left ], partition)) do incr (left );

while (less than(partition, sorted cites [right ])) do decr (right );

{ now sorted cites [right ] < partition < sorted cites [left ] } if (left < right ) then

begin swap(left , right ); incr (left ); decr (right ); end;

until (left = right + 1); { pointers have crossed }

swap(left end , right ); { restoring the partition element to its right ful place }

quick sort (left end , right − 1); quick sort (left , right end );

end

This code is used in section 304.

308. Ok, that’s it for sorting; now we’ll play with the literal stack. This procedure pushes a literal onto the stack, checking for stack overflow. ⟨ Procedures and functions for style-file function execution 308 ⟩ ≡ procedure push lit stk (push lt : integer ; push type : stk type);

trace var dum ptr : lit stk loc; { used just as an index variable }

ecart begin lit stack [lit stk ptr ] ← push lt ; lit stk type[lit stk ptr ] ← push type; trace for dum ptr ← 0 to lit stk ptr do trace pr (´ ␣␣´ ); trace pr (´ ␣´ ); case (lit stk type[lit stk ptr ]) of stk int : trace pr ln(lit stack [lit stk ptr ] : 0); stk str : begin trace pr (´ ´ ); trace pr pool str (lit stack [lit stk ptr ]); trace pr ln(´ ´ );

end; stk fn: begin trace pr (´ ` ´ ); trace pr pool str (hash text [lit stack [lit stk ptr ]]); trace pr ln(´ ´ ´ ´ );

end; stk field missing : begin trace pr (´ ␣ ␣` ´ ); trace pr pool str (lit stack [lit stk ptr ]);

trace pr ln(´ ´ ´ ´ ); end;

stk empty : trace pr ln(´ ␣ ␣ ␣ ␣ ␣ ␣ ´ );

othercases unknwn literal confusion

endcases; ecart if (lit stk ptr = lit stk size) then overflow (´ ␣ ␣´ , lit stk size); incr (lit stk ptr ); end;

See also sections 310, 313, 315, 316, 317, 318, 319, 321, 323, and 343. This code is used in section 12.

309. This macro pushes the last thing, necessarily a string, that was popped. And this module, along with others that push the literal stack without explicitly calling push lit stack , have an index entry under “push the literal stack”; these implicit pushes collectively speed up the program by about ten percent.

define repush string ≡ begin if (lit stack [lit stk ptr ] ≥ cmd str ptr ) then unflush string ; incr (lit stk ptr ); end 310. This procedure pops the stack, checking for, and trying to recover from, stack underflow. (Actually, this procedure is really a function, since it returns the two values through its var parameters.) Also, if the literal being popped is a stk str that’s been created during the execution of the current command, pop it from str pool as well (it will be the string corresponding to str ptr − 1). Note that when this happens, the string is no longer ‘officially’ available so that it must be used before anything else is added to str pool . ⟨ Procedures and functions for style-file function execution 308 ⟩ +≡ procedure pop lit stk (var pop lit : integer ; var pop type : stk type);

begin if (lit stk ptr = 0) then begin bst ex warn(´ ␣ ´ ´ ␣ ␣ ␣ ␣ ␣ ´ ); pop type ← stk empty ; { this is an error recovery attempt } end

else begin decr (lit stk ptr ); pop lit ← lit stack [lit stk ptr ]; pop type ← lit stk type[lit stk ptr ];

if (pop type = stk str ) then

if (pop lit ≥ cmd str ptr ) then begin if (pop lit ≠ str ptr − 1) then confusion(´ ␣ ␣ ␣ ␣ ´ ); flush string ; end;

end; end;

311. More bug complaints, this time about bad literals. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure illegl literal confusion;

begin confusion(´ ␣ ␣ ´ ); end;

procedure unknwn literal confusion; begin confusion(´ ␣ ␣ ´ ); end;

312. Occasionally we’ll want to know what’s on the literal stack. Here we print out a stack literal, giving its type. This procedure should never be called after popping an empty stack. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure print stk lit (stk lt : integer ; stk tp : stk type);

begin case (stk tp) of stk int : print (stk lt : 0, ´ ␣ ␣ ␣ ␣ ´ ); stk str : begin print (´ ´ ); print pool str (stk lt ); print (´ ␣ ␣ ␣ ␣ ´ );

end; stk fn: begin print (´ ` ´ ); print pool str (hash text [stk lt ]); print (´ ´ ´ ␣ ␣ ␣ ␣ ´ );

end; stk field missing : begin print (´ ` ´ ); print pool str (stk lt ); print (´ ´ ´ ␣ ␣ ␣ ␣ ´ );

end; stk empty : illegl literal confusion;

othercases unknwn literal confusion

endcases; end; 313. This procedure appropriately chastises the style designer; however, if the wrong literal came from popping an empty stack, the procedure pop lit stack will have already done the chastising (because this procedure is called only after popping the stack) so there’s no need for more. ⟨ Procedures and functions for style-file function execution 308 ⟩ +≡ procedure print wrong stk lit (stk lt : integer ; stk tp1 , stk tp2 : stk type);

begin if (stk tp1 ≠ stk empty ) then begin print stk lit (stk lt , stk tp1 ); case (stk tp2 ) of stk int : print (´ ␣ ␣ ␣ ´ ); stk str : print (´ ␣ ␣ ␣ ´ ); stk fn: print (´ ␣ ␣ ␣ ´ ); stk field missing , stk empty : illegl literal confusion;

othercases unknwn literal confusion

endcases; bst ex warn print ;

end; end;

314. This is similar to print stk lit , but here we don’t give the literal’s type, and here we end with a new line. This procedure should never be called after popping an empty stack. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure print lit (stk lt : integer ; stk tp : stk type);

begin case (stk tp) of stk int : print ln(stk lt : 0); stk str : begin print pool str (stk lt ); print newline;

end; stk fn: begin print pool str (hash text [stk lt ]); print newline;

end; stk field missing : begin print pool str (stk lt ); print newline;

end; stk empty : illegl literal confusion;

othercases unknwn literal confusion

endcases; end;

315. This procedure pops and prints the top of the stack; when the stack is empty the procedure pop lit stk complains. ⟨ Procedures and functions for style-file function execution 308 ⟩ +≡ procedure pop top and print ;

var stk lt : integer ; stk tp: stk type; begin pop lit stk (stk lt , stk tp); if (stk tp = stk empty ) then print ln(´ ␣ ´ ) else print lit (stk lt , stk tp); end;

316. This procedure pops and prints the whole stack. ⟨ Procedures and functions for style-file function execution 308 ⟩ +≡ procedure pop whole stack ;

begin while (lit stk ptr > 0) do pop top and print ; end; 317. At the beginning of a -command execution we make the stack empty and record how much of str pool has been used. ⟨ Procedures and functions for style-file function execution 308 ⟩ +≡ procedure init command execution;

begin lit stk ptr ← 0; { make the stack empty }

cmd str ptr ← str ptr ; { we’ll check this when we finish command execution } end;

318. At the end of a command-execution we check that the stack and str pool are still in good shape. ⟨ Procedures and functions for style-file function execution 308 ⟩ +≡ procedure check command execution;

begin if (lit stk ptr ≠ 0) then begin print ln(´ ´ , lit stk ptr : 0, ´ ␣ ´ ); pop whole stack ; bst ex warn(´ ␣ ␣ ␣ ´ ´ ␣ ´ ); end;

if (cmd str ptr ≠ str ptr ) then begin trace print ln(´ ␣ ␣´ , str ptr : 0, ´ ␣ ␣ ␣ ␣´ , cmd str ptr : 0); ecart confusion(´ ␣ ␣ ␣ ´ ); end;

end;

319. This procedure adds to str pool the string from ex buf [0] through ex buf [ex buf length − 1] if it will fit. It assumes the global variable ex buf length gives the length of the current string in ex buf . It then pushes this string onto the literal stack. ⟨ Procedures and functions for style-file function execution 308 ⟩ +≡ procedure add pool buf and push;

begin str room(ex buf length); { make sure this string will fit }

ex buf ptr ← 0;

while (ex buf ptr < ex buf length) do begin append char (ex buf [ex buf ptr ]); incr (ex buf ptr ); end;

push lit stk (make string , stk str ); { and push it onto the stack }

end;

320. These macros append a character to ex buf . Which is called depends on whether the character is known to fit.

define append ex buf char (#) ≡ begin ex buf [ex buf ptr ] ← #; incr (ex buf ptr ); end

define append ex buf char and check (#) ≡ begin if (ex buf ptr = buf size) then buffer overflow ; append ex buf char (#); end 321. This procedure adds to the execution buffer the given string in str pool if it will fit. It assumes the global variable ex buf length gives the length of the current string in ex buf , and thus also gives the location of the next character. ⟨ Procedures and functions for style-file function execution 308 ⟩ +≡ procedure add buf pool (p str : str number );

begin p ptr1 ← str start [p str ]; p ptr2 ← str start [p str + 1];

if (ex buf length + (p ptr2 − p ptr1 ) > buf size) then buffer overflow ; ex buf ptr ← ex buf length; while (p ptr1 < p ptr2 ) do

begin { copy characters into the buffer }

append ex buf char (str pool [p ptr1 ]); incr (p ptr1 );

end; ex buf length ← ex buf ptr ; end;

322. This procedure actually writes onto the file a line of output (the characters from out buf [0] to out buf [out buf length − 1], after removing trailing white space characters). It also updates bbl line num, the line counter. It writes a blank line if and only if out buf is empty. The program uses this procedure in such a way that out buf will be nonempty if there have been characters put in it since the most recent

$.

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure output bbl line;

label loop exit , exit ;

begin if (out buf length ≠ 0) then { the buffer’s not empty }

begin while (out buf length > 0) do { remove trailing white space } if (lex class [out buf [out buf length − 1]] = white space) then decr (out buf length) else goto loop exit ;

loop exit : if (out buf length = 0) then { ignore a line of just white space }

return; out buf ptr ← 0; while (out buf ptr < out buf length) do

begin write(bbl file, xchr [out buf [out buf ptr ]]); incr (out buf ptr );

end; end;

write ln(bbl file); incr (bbl line num); { update line number }

out buf length ← 0; { make the next line empty } exit : end; 323. This procedure adds to the output buffer the given string in str pool . It assumes the global variable out buf length gives the length of the current string in out buf , and thus also gives the location for the next character. If there are enough characters present in the output buffer, it writes one or more lines out to the file. It may break a line at any white space character it likes, but if it does, it will add two spaces to the next output line. ⟨ Procedures and functions for style-file function execution 308 ⟩ +≡ procedure add out pool (p str : str number );

var break ptr : buf pointer ; { the first character following the line break }

end ptr : buf pointer ; { temporary end-of-buffer pointer } begin p ptr1 ← str start [p str ]; p ptr2 ← str start [p str + 1]; if (out buf length + (p ptr2 − p ptr1 ) > buf size) then overflow (´ ␣ ␣ ␣´ , buf size); out buf ptr ← out buf length; while (p ptr1 < p ptr2 ) do

begin { copy characters into the buffer }

out buf [out buf ptr ] ← str pool [p ptr1 ]; incr (p ptr1 ); incr (out buf ptr );

end; out buf length ← out buf ptr ; while (out buf length > max print line) do ⟨ Break that line 324 ⟩; end;

324. Here we break the line by looking for a white space character, backwards from out buf [max print line] until out buf [min print line]; we break at the white space and indent the next line two spaces. The next module handles things when there’s no white space character to break at. ⟨ Break that line 324 ⟩ ≡

begin end ptr ← out buf length; out buf ptr ← max print line; while ((lex class [out buf [out buf ptr ]] ≠ white space) ∧ (out buf ptr ≥ min print line)) do

decr (out buf ptr ); if (out buf ptr = min print line − 1) then { no white space character }

⟨ Break that unbreakable line 325 ⟩ else begin { hit a white space character }

out buf length ← out buf ptr ; break ptr ← out buf length + 1; output bbl line; { output what we can } out buf [0] ← space; out buf [1] ← space; { start the next line with two spaces } out buf ptr ← 2; tmp ptr ← break ptr ; while (tmp ptr < end ptr ) do { and slide the rest down }

begin out buf [out buf ptr ] ← out buf [tmp ptr ]; incr (out buf ptr ); incr (tmp ptr ); end;

out buf length ← end ptr − break ptr + 2;

end; end

This code is used in section 323.

325. If there’s no white space character to break the line at, we break it at out buf [max print line − 1], append a comment character, and don’t indent the next line. ⟨ Break that unbreakable line 325 ⟩ ≡

begin out buf [end ptr ] ← out buf [max print line − 1]; { save this character } out buf [max print line − 1] ← comment ; { so TEX does the thing right } out buf length ← max print line; break ptr ← out buf length − 1; { the ‘−1’ allows for the restoration } output bbl line; { output what we can, } out buf [max print line − 1] ← out buf [end ptr ]; { restore this character } out buf ptr ← 0; tmp ptr ← break ptr ; while (tmp ptr < end ptr ) do { and slide the rest down }

begin out buf [out buf ptr ] ← out buf [tmp ptr ]; incr (out buf ptr ); incr (tmp ptr ); end;

out buf length ← end ptr − break ptr ; end

This code is used in section 324.

326. This procedure executes a single specified function; it is the single execution-primitive that does everything (except windows, and it takes Tuesdays off). ⟨ execute fn itself 326 ⟩ ≡ procedure execute fn(ex fn loc : hash loc);

⟨ Declarations for executing built in functions 344 ⟩wiz ptr : wiz fn loc; { general wiz functions location } begin trace trace pr (´ ␣` ´ ); trace pr pool str (hash text [ex fn loc]); trace pr ln(´ ´ ´ ´ ); ecart case (fn type[ex fn loc]) of built in: ⟨ Execute a built in function 342 ⟩; wiz defined : ⟨ Execute a wiz defined function 327 ⟩; int literal : push lit stk (fn info[ex fn loc], stk int ); str literal : push lit stk (hash text [ex fn loc], stk str ); field : ⟨ Execute a field 328 ⟩; int entry var : ⟨ Execute an int entry var 329 ⟩; str entry var : ⟨ Execute a str entry var 330 ⟩; int global var : push lit stk (fn info[ex fn loc], stk int ); str global var : ⟨ Execute a str global var 331 ⟩;

othercases unknwn function class confusion

endcases; end;

This code is used in section 343.

327. To execute a wiz defined function, we just execute all those functions in its definition, except that the special marker quote next fn means we push the next function onto the stack. ⟨ Execute a wiz defined function 327 ⟩ ≡

begin wiz ptr ← fn info[ex fn loc]; while (wiz functions [wiz ptr ] ≠ end of def ) do

begin if (wiz functions [wiz ptr ] ≠ quote next fn) then execute fn(wiz functions [wiz ptr ])

else begin incr (wiz ptr ); push lit stk (wiz functions [wiz ptr ], stk fn);

end; incr (wiz ptr ); end;

end

This code is used in section 326.

328. This module pushes the string given by the field onto the literal stack unless it’s missing , in which case it pushes a special value onto the stack. ⟨ Execute a field 328 ⟩ ≡

begin if (¬mess with entries ) then bst cant mess with entries print else begin field ptr ← cite ptr ∗ num fields + fn info[ex fn loc];

if (field info[field ptr ] = missing ) then push lit stk (hash text [ex fn loc], stk field missing )

else push lit stk (field info[field ptr ], stk str );

end end

This code is used in section 326.

329. This module pushes the integer given by an int entry var onto the literal stack. ⟨ Execute an int entry var 329 ⟩ ≡

begin if (¬mess with entries ) then bst cant mess with entries print else push lit stk (entry ints [cite ptr ∗ num ent ints + fn info[ex fn loc]], stk int ); end

This code is used in section 326.

330. This module adds the string given by a str entry var to str pool via the execution buffer and pushes it onto the literal stack. ⟨ Execute a str entry var 330 ⟩ ≡

begin if (¬mess with entries ) then bst cant mess with entries print else begin str ent ptr ← cite ptr ∗ num ent strs + fn info[ex fn loc];

ex buf ptr ← 0; { also serves as ent chr ptr }

while (entry strs [str ent ptr ][ex buf ptr ] ≠ end of string ) do { copy characters into the buffer }

append ex buf char (entry strs [str ent ptr ][ex buf ptr ]); ex buf length ← ex buf ptr ; add pool buf and push; { push this string onto the stack } end;

end

This code is used in section 326.

331. This module pushes the string given by a str global var onto the literal stack, but it copies the string to str pool (character by character) only if it has to—it doesn’t have to if the string is static (that is, if the string isn’t at the top, temporary part of the string pool). ⟨ Execute a str global var 331 ⟩ ≡

begin str glb ptr ← fn info[ex fn loc]; if (glb str ptr [str glb ptr ] > 0) then { we’re dealing with a static string }

push lit stk (glb str ptr [str glb ptr ], stk str ) else begin str room(glb str end [str glb ptr ]); glob chr ptr ← 0;

while (glob chr ptr < glb str end [str glb ptr ]) do { copy the string } begin append char (global strs [str glb ptr ][glob chr ptr ]); incr (glob chr ptr ); end;

push lit stk (make string , stk str ); { and push it onto the stack }

end; end

This code is used in section 326.

§332 BibTEX THE BUILT-IN FUNCTIONS 111

332. The built-in functions. This section gives the all the code for all the built-in functions (including pre-defined field s, str entry var s, and int global var s, which technically aren’t classified as built in). To modify or add one, we needn’t go anywhere else (with one exception: The constant max pop, which gives the maximum number of literals that any of these functions pops off the stack, is defined earlier because it’s needed earlier; thus, if we need to update it, which will happen if some new built in functions uses more than max pop literals from the stack, we’ll have to go outside this section). Adding a built in function entails modifying (at least four of) the five modules marked by “add a built-in function” in the index, in addition to adding the code to execute the function.

These variables all begin with b and specify the hash-table locations of the built in functions, except that b default is pseudo-built in—either it will point to the no-op $ or to the -defined function ; it’s used when an entry has a type that’s not defined in the file. ⟨ Globals in the outer block 16 ⟩ +≡ b equals : hash loc; { } b greater than: hash loc; { } b less than: hash loc; { } b plus : hash loc; { (this may be changed to an a minus ) } b minus : hash loc; { } b concatenate: hash loc; { } b gets : hash loc; { (formerly, b gat ) } b add period : hash loc; { $ } b call type: hash loc; { $ } b change case: hash loc; { $ } b chr to int : hash loc; { $ } b cite: hash loc; { $ } b duplicate: hash loc; { $ } b empty : hash loc; { $ } b format name: hash loc; { $ } b if : hash loc; { $ } b int to chr : hash loc; { $ } b int to str : hash loc; { $ } b missing : hash loc; { $ } b newline: hash loc; { $ } b num names : hash loc; { $ } b pop: hash loc; { $ } b preamble: hash loc; { $ } b purify : hash loc; { $ } b quote: hash loc; { $ } b skip: hash loc; { $ } b stack : hash loc; { $ } b substring : hash loc; { $ } b swap: hash loc; { $ } b text length: hash loc; { $ } b text prefix : hash loc; { $ } b top stack : hash loc; { $ } b type: hash loc; { $ } b warning : hash loc; { $ } b while: hash loc; { $ } b width: hash loc; { $ } b write: hash loc; { $ } b default : hash loc; { either $ or }

112  THE BUILT-IN FUNCTIONS  BibTEX §332

stat blt in loc: array [blt in range] of hash loc; { for execution counts } execution count : array [blt in range] of integer ; { the same } total ex count : integer ; { the sum of all execution count s } blt in ptr : blt in range; { a pointer into blt in loc }

tats

333. Where blt in range gives the legal built in function numbers. ⟨ Types in the outer block 22 ⟩ +≡

blt in range = 0 . . num blt in fns ;

334. These constants all begin with n and are used for the case statement that determines which built in function to execute.

define n equals = 0 { } define n greater than = 1 { } define n less than = 2 { } define n plus = 3 { } define n minus = 4 { } define n concatenate = 5 { } define n gets = 6 { } define n add period = 7 { $ } define n call type = 8 { $ } define n change case = 9 { $ } define n chr to int = 10 { $ } define n cite = 11 { $ (this may start a riot) } define n duplicate = 12 { $ } define n empty = 13 { $ } define n format name = 14 { $ } define n if = 15 { $ } define n int to chr = 16 { $ } define n int to str = 17 { $ } define n missing = 18 { $ } define n newline = 19 { $ } define n num names = 20 { $ } define n pop = 21 { $ } define n preamble = 22 { $ } define n purify = 23 { $ } define n quote = 24 { $ } define n skip = 25 { $ } define n stack = 26 { $ } define n substring = 27 { $ } define n swap = 28 { $ } define n text length = 29 { $ } define n text prefix = 30 { $ } define n top stack = 31 { $ } define n type = 32 { $ } define n warning = 33 { $ } define n while = 34 { $ } define n width = 35 { $ } define n write = 36 { $ }

⟨ Constants in the outer block 14* ⟩ +≡ num blt in fns = 37; { one more than the previous number } 335. It’s time for us to insert more pre-defined strings into str pool (and thus the hash table) and to insert the built in functions into the hash table. The strings corresponding to these functions should contain no upper-case letters, and they must all be exactly longest pds characters long. The build in routine (to appear shortly) does the work.

Important note: These pre-definitions must not have any glitches or the program may bomb because the log file hasn’t been opened yet. ⟨ Pre-define certain strings 76 ⟩ +≡

build in(´ ␣␣␣␣␣␣␣␣␣␣␣´ , 1, b equals , n equals ); build in(´ ␣␣␣␣␣␣␣␣␣␣␣´ , 1, b greater than, n greater than); build in(´ ␣␣␣␣␣␣␣␣␣␣␣´ , 1, b less than, n less than); build in(´ ␣␣␣␣␣␣␣␣␣␣␣´ , 1, b plus , n plus ); build in(´ ␣␣␣␣␣␣␣␣␣␣␣´ , 1, b minus , n minus ); build in(´ ␣␣␣␣␣␣␣␣␣␣␣´ , 1, b concatenate, n concatenate); build in(´ ␣␣␣␣␣␣␣␣␣␣´ , 2, b gets , n gets ); build in(´ $␣´ , 11, b add period , n add period ); build in(´ $␣␣´ , 10, b call type, n call type); build in(´ $´ , 12, b change case, n change case); build in(´ $␣´ , 11, b chr to int , n chr to int ); build in(´ $␣␣␣␣␣␣␣´ , 5, b cite, n cite); build in(´ $␣␣´ , 10, b duplicate, n duplicate); build in(´ $␣␣␣␣␣␣´ , 6, b empty , n empty ); build in(´ $´ , 12, b format name, n format name); build in(´ $␣␣␣␣␣␣␣␣␣´ , 3, b if , n if ); build in(´ $␣´ , 11, b int to chr , n int to chr ); build in(´ $␣´ , 11, b int to str , n int to str ); build in(´ $␣␣␣␣´ , 8, b missing , n missing ); build in(´ $␣␣␣␣´ , 8, b newline, n newline); build in(´ $␣␣´ , 10, b num names , n num names ); build in(´ $␣␣␣␣␣␣␣␣´ , 4, b pop, n pop); build in(´ $␣␣␣´ , 9, b preamble, n preamble); build in(´ $␣␣␣␣␣´ , 7, b purify , n purify ); build in(´ $␣␣␣␣␣␣´ , 6, b quote, n quote); build in(´ $␣␣␣␣␣␣␣´ , 5, b skip, n skip); build in(´ $␣␣␣␣␣␣´ , 6, b stack , n stack ); build in(´ $␣␣´ , 10, b substring , n substring ); build in(´ $␣␣␣␣␣␣␣´ , 5, b swap, n swap); build in(´ $´ , 12, b text length, n text length); build in(´ $´ , 12, b text prefix , n text prefix ); build in(´ $␣␣␣␣␣␣␣␣´ , 4, b top stack , n top stack ); build in(´ $␣␣␣␣␣␣␣´ , 5, b type, n type); build in(´ $␣␣␣␣´ , 8, b warning , n warning ); build in(´ $␣␣␣␣␣␣´ , 6, b width, n width); build in(´ $␣␣␣␣␣␣´ , 6, b while, n while); build in(´ $␣␣␣␣␣␣´ , 6, b width, n width); build in(´ $␣␣␣␣␣␣´ , 6, b write, n write);

336. This procedure inserts a built in function into the hash table and initializes the corresponding predefined string (of length at most longest pds ). The array fn info contains a number from 0 through the number of built in functions minus 1 (i.e., num blt in fns − 1 if we’re keeping statistics); this number is used by a case statement to execute this function and is used for keeping execution counts when keeping statistics. ⟨ Procedures and functions for handling numbers, characters, and strings 55 ⟩ +≡ procedure build in(pds : pds type; len : pds len; var fn hash loc : hash loc; blt in num : blt in range);

begin pre define(pds , len, bst fn ilk ); fn hash loc ← pre def loc; { the pre define routine sets pre def loc } fn type[fn hash loc] ← built in; fn info[fn hash loc] ← blt in num; stat blt in loc[blt in num] ← fn hash loc; execution count [blt in num] ← 0; { initialize the function-execution count } tats end; 337. This is a procedure so that initialize is smaller. ⟨ Procedures and functions for handling numbers, characters, and strings 55 ⟩ +≡ procedure pre def certain strings ;

begin ⟨ Pre-define certain strings 76 ⟩

end;

338. These variables all begin with s and specify the locations in str pool of certain often-used strings that the commands need. The s preamble array is big enough to allow an average of one $ command per file. ⟨ Globals in the outer block 16 ⟩ +≡ s null : str number ; { the null string } s default : str number ; { , for unknown entry types } s t : str number ; { , for title lowers case conversion } s l : str number ; { , for all lowers case conversion } s u: str number ; { , for all uppers case conversion } s preamble: array [bib number ] of str number ; { for the $ built in function }

339. These constants all begin with n and are used for the case statement that determines which, if any, control sequence we’re dealing with; a control sequence of interest will be either one of the undotted characters ‘ ’ or ‘ ’ or one of the foreign characters in Table 3.2 of the LaTEX manual.

define n i = 0 { , for the undotted character } define n j = 1 { , for the undotted character } define n oe = 2 { , for the foreign character } define n oe upper = 3 { , for the foreign character } define n ae = 4 { , for the foreign character } define n ae upper = 5 { , for the foreign character } define n aa = 6 { , for the foreign character } define n aa upper = 7 { , for the foreign character } define n o = 8 { , for the foreign character } define n o upper = 9 { , for the foreign character } define n l = 10 { , for the foreign character } define n l upper = 11 { , for the foreign character } define n ss = 12 { , for the foreign character } 340. Here we pre-define a few strings used in executing the file: the null string, which is sometimes pushed onto the stack; a string used for default entry types; and some control sequences used to spot foreign characters. We also initialize the s preamble array to empty. These pre-defined strings must all be exactly longest pds characters long.

Important note: These pre-definitions must not have any glitches or the program may bomb because the log file hasn’t been opened yet, and text ilk s should be pre-defined here, not earlier, for -function-execution purposes. ⟨ Pre-define certain strings 76 ⟩ +≡

pre define(´ ␣␣␣␣␣␣␣␣␣␣␣␣´ , 0, text ilk ); s null ← hash text [pre def loc]; fn type[pre def loc] ← str literal ; pre define(´ ´ , 12, text ilk ); s default ← hash text [pre def loc]; fn type[pre def loc] ← str literal ; b default ← b skip; { this may be changed to the function } preamble ptr ← 0; { initialize the s preamble array } pre define(´ ␣␣␣␣␣␣␣␣␣␣␣´ , 1, control seq ilk ); ilk info[pre def loc] ← n i ; pre define(´ ␣␣␣␣␣␣␣␣␣␣␣´ , 1, control seq ilk ); ilk info[pre def loc] ← n j ; pre define(´ ␣␣␣␣␣␣␣␣␣␣´ , 2, control seq ilk ); ilk info[pre def loc] ← n oe; pre define(´ ␣␣␣␣␣␣␣␣␣␣´ , 2, control seq ilk ); ilk info[pre def loc] ← n oe upper ; pre define(´ ␣␣␣␣␣␣␣␣␣␣´ , 2, control seq ilk ); ilk info[pre def loc] ← n ae; pre define(´ ␣␣␣␣␣␣␣␣␣␣´ , 2, control seq ilk ); ilk info[pre def loc] ← n ae upper ; pre define(´ ␣␣␣␣␣␣␣␣␣␣´ , 2, control seq ilk ); ilk info[pre def loc] ← n aa; pre define(´ ␣␣␣␣␣␣␣␣␣␣´ , 2, control seq ilk ); ilk info[pre def loc] ← n aa upper ; pre define(´ ␣␣␣␣␣␣␣␣␣␣␣´ , 1, control seq ilk ); ilk info[pre def loc] ← n o; pre define(´ ␣␣␣␣␣␣␣␣␣␣␣´ , 1, control seq ilk ); ilk info[pre def loc] ← n o upper ; pre define(´ ␣␣␣␣␣␣␣␣␣␣␣´ , 1, control seq ilk ); ilk info[pre def loc] ← n l ; pre define(´ ␣␣␣␣␣␣␣␣␣␣␣´ , 1, control seq ilk ); ilk info[pre def loc] ← n l upper ; pre define(´ ␣␣␣␣␣␣␣␣␣␣´ , 2, control seq ilk ); ilk info[pre def loc] ← n ss ;

341. Now we pre-define any built-in field s, str entry var s, and int global var s; these strings must all be exactly longest pds characters long. Note that although these are built-in functions, we classify them (in the fn type array) otherwise.

Important note: These pre-definitions must not have any glitches or the program may bomb because the log file hasn’t been opened yet. ⟨ Pre-define certain strings 76 ⟩ +≡

pre define(´ ␣␣␣␣´ , 8, bst fn ilk ); fn type[pre def loc] ← field ; fn info[pre def loc] ← num fields ; { give this field a number } crossref num ← num fields ; incr (num fields ); num pre defined fields ← num fields ; { that’s it for pre-defined field s } pre define(´ $␣␣␣´ , 9, bst fn ilk ); fn type[pre def loc] ← str entry var ; fn info[pre def loc] ← num ent strs ; { give this str entry var a number } sort key num ← num ent strs ; incr (num ent strs ); pre define(´ $␣␣´ , 10, bst fn ilk ); fn type[pre def loc] ← int global var ; fn info[pre def loc] ← ent str size; { initialize this int global var } pre define(´ $␣´ , 11, bst fn ilk ); fn type[pre def loc] ← int global var ; fn info[pre def loc] ← glob str size; { initialize this int global var } 342. This module branches to the code for the appropriate built in function. Only three— $ , $, and $—do a recursive call. ⟨ Execute a built in function 342 ⟩ ≡

begin stat { update this function’s execution count } incr (execution count [fn info[ex fn loc]]); tats case (fn info[ex fn loc]) of n equals : x equals ; n greater than: x greater than; n less than: x less than; n plus : x plus ; n minus : x minus ; n concatenate: x concatenate; n gets : x gets ; n add period : x add period ; n call type: ⟨ execute fn( $ ) 364 ⟩; n change case: x change case; n chr to int : x chr to int ; n cite: x cite; n duplicate: x duplicate; n empty : x empty ; n format name: x format name; n if : ⟨ execute fn( $) 422 ⟩; n int to chr : x int to chr ; n int to str : x int to str ; n missing : x missing ; n newline: ⟨ execute fn( $) 426 ⟩; n num names : x num names ; n pop: ⟨ execute fn( $) 429 ⟩; n preamble: x preamble; n purify : x purify ; n quote: x quote; n skip: ⟨ execute fn( $) 436 ⟩; n stack : ⟨ execute fn( $) 437 ⟩; n substring : x substring ; n swap: x swap; n text length: x text length; n text prefix : x text prefix ; n top stack : ⟨ execute fn( $) 447 ⟩; n type: x type; n warning : x warning ; n while: ⟨ execute fn( $) 450 ⟩; n width: x width; n write: x write; othercases confusion(´ ␣ ␣ ´ ) endcases; end

This code is used in section 326.

343. This extra level of module-pointing allows a uniformity of module names for the built in functions, regardless of whether they do a recursive call to execute fn or are trivial (a single statement). Those that do a recursive call are left as part of execute fn, avoiding PASCAL’s forward procedure mechanism, and those that don’t (except for the single-statement ones) are made into procedures so that execute fn doesn’t get too large. ⟨ Procedures and functions for style-file function execution 308 ⟩ +≡

⟨ execute fn( ) 346 ⟩ ⟨ execute fn( ) 347 ⟩ ⟨ execute fn( ) 348 ⟩ ⟨ execute fn( ) 349 ⟩ ⟨ execute fn( ) 350 ⟩ ⟨ execute fn( ) 351 ⟩ ⟨ execute fn( ) 355 ⟩ ⟨ execute fn( $ ) 361 ⟩ ⟨ execute fn( $ ) 365 ⟩ ⟨ execute fn( $ ) 378 ⟩ ⟨ execute fn( $) 379 ⟩ ⟨ execute fn( $ ) 380 ⟩ ⟨ execute fn( $) 381 ⟩ ⟨ execute fn( $ ) 383 ⟩ ⟨ execute fn( $ ) 423 ⟩ ⟨ execute fn( $ ) 424 ⟩ ⟨ execute fn( $) 425 ⟩ ⟨ execute fn( $ ) 427 ⟩ ⟨ execute fn( $) 430 ⟩ ⟨ execute fn( $) 431 ⟩ ⟨ execute fn( $) 435 ⟩ ⟨ execute fn( $ ) 438 ⟩ ⟨ execute fn( $) 440 ⟩ ⟨ execute fn( $ ) 442 ⟩ ⟨ execute fn( $ ) 444 ⟩ ⟨ execute fn( $) 448 ⟩ ⟨ execute fn( $) 449 ⟩ ⟨ execute fn( $) 451 ⟩ ⟨ execute fn( $) 455 ⟩ ⟨ execute fn itself 326 ⟩

344. Now it’s time to declare some things for executing built in functions only. These (and only these) variables are used recursively, so they can’t be global.

define end while = 51 { stop executing the $ function } ⟨ Declarations for executing built in functions 344 ⟩ ≡ label end while; var r pop lt1 , r pop lt2 : integer ; { stack literals for $ }

r pop tp1 , r pop tp2 : stk type; { stack types for $ }

This code is used in section 326.

345. These are nonrecursive variables that execute fn uses. Declaring them here (instead of in the previous module) saves execution time and stack space on most machines.

define name buf ≡ sv buffer { an alias, a buffer for manipulating names } ⟨ Globals in the outer block 16 ⟩ +≡ pop lit1 , pop lit2 , pop lit3 : integer ; { stack literals } pop typ1 , pop typ2 , pop typ3 : stk type; { stack types } sp ptr : pool pointer ; { for manipulating str pool strings } sp xptr1 , sp xptr2 : pool pointer ; { more of the same } sp end : pool pointer ; { marks the end of a str pool string } sp length, sp2 length: pool pointer ; { lengths of str pool strings } sp brace level : integer ; { for scanning str pool strings } ex buf xptr , ex buf yptr : buf pointer ; { extra ex buf locations } control seq loc: hash loc; { hash-table loc of a control sequence } preceding white: boolean; { used in scanning strings } and found : boolean; { to stop the loop that looks for an “and” } num names : integer ; { for counting names } name bf ptr : buf pointer ; { general name buf location } name bf xptr , name bf yptr : buf pointer ; { and two more } nm brace level : integer ; { for scanning name buf strings } name tok : packed array [buf pointer ] of buf pointer ; { name-token ptr list } name sep char : packed array [buf pointer ] of ASCII code; { token-ending chars } num tokens : buf pointer ; { this counts name tokens } token starting : boolean; { used in scanning name tokens } alpha found : boolean; { used in scanning the format string } double letter , end of group, to be written: boolean; { the same } first start : buf pointer ; { start-ptr into name tok for the first name } first end : buf pointer ; { end-ptr into name tok for the first name } last end : buf pointer ; { end-ptr into name tok for the last name } von start : buf pointer ; { start-ptr into name tok for the von name } von end : buf pointer ; { end-ptr into name tok for the von name } jr end : buf pointer ; { end-ptr into name tok for the jr name } cur token, last token: buf pointer ; { name tok ptrs for outputting tokens } use default : boolean; { for the inter-token intra-name part string } num commas : buf pointer ; { used to determine the name syntax } comma1 , comma2 : buf pointer ; { ptrs into name tok } num text chars : buf pointer ; { special characters count as one } 346. The built in function pops the top two (integer or string) literals, compares them, and pushes the integer 1 if they’re equal, 0 otherwise. If they’re not either both string or both integer, it complains and pushes the integer 0. ⟨ execute fn( ) 346 ⟩ ≡ procedure x equals ;

begin pop lit stk (pop lit1 , pop typ1 ); pop lit stk (pop lit2 , pop typ2 ); if (pop typ1 ≠ pop typ2 ) then

begin if ((pop typ1 ≠ stk empty ) ∧ (pop typ2 ≠ stk empty )) then begin print stk lit (pop lit1 , pop typ1 ); print (´ ␣´ ); print stk lit (pop lit2 , pop typ2 ); print newline; bst ex warn(´ ␣ ´ ´ ␣ ␣ ␣ ␣ ´ ); end;

push lit stk (0, stk int );

end else if ((pop typ1 ≠ stk int ) ∧ (pop typ1 ≠ stk str )) then

begin if (pop typ1 ≠ stk empty ) then begin print stk lit (pop lit1 , pop typ1 ); bst ex warn(´ ␣ ␣ ␣ ␣ ␣ ␣ ´ ); end;

push lit stk (0, stk int );

end else if (pop typ1 = stk int ) then

if (pop lit2 = pop lit1 ) then push lit stk (1, stk int )

else push lit stk (0, stk int ) else if (str eq str (pop lit2 , pop lit1 )) then push lit stk (1, stk int )

else push lit stk (0, stk int ); end;

This code is used in section 343.

347. The built in function pops the top two (integer) literals, compares them, and pushes the integer 1 if the second is greater than the first, 0 otherwise. If either isn’t an integer literal, it complains and pushes the integer 0. ⟨ execute fn( ) 347 ⟩ ≡ procedure x greater than;

begin pop lit stk (pop lit1 , pop typ1 ); pop lit stk (pop lit2 , pop typ2 ); if (pop typ1 ≠ stk int ) then

begin print wrong stk lit (pop lit1 , pop typ1 , stk int ); push lit stk (0, stk int ); end

else if (pop typ2 ≠ stk int ) then begin print wrong stk lit (pop lit2 , pop typ2 , stk int ); push lit stk (0, stk int ); end

else if (pop lit2 > pop lit1 ) then push lit stk (1, stk int )

else push lit stk (0, stk int ); end;

This code is used in section 343.

348. The built in function pops the top two (integer) literals, compares them, and pushes the integer 1 if the second is less than the first, 0 otherwise. If either isn’t an integer literal, it complains and pushes the integer 0. ⟨ execute fn( ) 348 ⟩ ≡ procedure x less than;

begin pop lit stk (pop lit1 , pop typ1 ); pop lit stk (pop lit2 , pop typ2 ); if (pop typ1 ≠ stk int ) then

begin print wrong stk lit (pop lit1 , pop typ1 , stk int ); push lit stk (0, stk int ); end

else if (pop typ2 ≠ stk int ) then begin print wrong stk lit (pop lit2 , pop typ2 , stk int ); push lit stk (0, stk int ); end

else if (pop lit2 < pop lit1 ) then push lit stk (1, stk int )

else push lit stk (0, stk int ); end;

This code is used in section 343.

349. The built in function pops the top two (integer) literals and pushes their sum. If either isn’t an integer literal, it complains and pushes the integer 0. ⟨ execute fn( ) 349 ⟩ ≡ procedure x plus ;

begin pop lit stk (pop lit1 , pop typ1 ); pop lit stk (pop lit2 , pop typ2 ); if (pop typ1 ≠ stk int ) then

begin print wrong stk lit (pop lit1 , pop typ1 , stk int ); push lit stk (0, stk int ); end

else if (pop typ2 ≠ stk int ) then begin print wrong stk lit (pop lit2 , pop typ2 , stk int ); push lit stk (0, stk int ); end

else push lit stk (pop lit2 + pop lit1 , stk int ); end;

This code is used in section 343.

350. The built in function pops the top two (integer) literals and pushes their difference (the first subtracted from the second). If either isn’t an integer literal, it complains and pushes the integer 0. ⟨ execute fn( ) 350 ⟩ ≡ procedure x minus ;

begin pop lit stk (pop lit1 , pop typ1 ); pop lit stk (pop lit2 , pop typ2 ); if (pop typ1 ≠ stk int ) then

begin print wrong stk lit (pop lit1 , pop typ1 , stk int ); push lit stk (0, stk int ); end

else if (pop typ2 ≠ stk int ) then begin print wrong stk lit (pop lit2 , pop typ2 , stk int ); push lit stk (0, stk int ); end

else push lit stk (pop lit2 − pop lit1 , stk int ); end;

This code is used in section 343.

351. The built in function pops the top two (string) literals, concatenates them (in reverse order, that is, the order in which pushed), and pushes the resulting string back onto the stack. If either isn’t a string literal, it complains and pushes the null string. ⟨ execute fn( ) 351 ⟩ ≡ procedure x concatenate;

begin pop lit stk (pop lit1 , pop typ1 ); pop lit stk (pop lit2 , pop typ2 );

if (pop typ1 ≠ stk str ) then begin print wrong stk lit (pop lit1 , pop typ1 , stk str ); push lit stk (s null , stk str ); end

else if (pop typ2 ≠ stk str ) then begin print wrong stk lit (pop lit2 , pop typ2 , stk str ); push lit stk (s null , stk str ); end

else ⟨ Concatenate the two strings and push 352 ⟩; end;

This code is used in section 343.

352. Often both strings will be at the top of the string pool, in which case we just move some pointers. Furthermore, it’s worth doing some special stuff in case either string is null, since empirically this seems to happen about 20% of the time. In any case, we don’t need the execution buffer—we simple move the strings around in the string pool when necessary. ⟨ Concatenate the two strings and push 352 ⟩ ≡

begin if (pop lit2 ≥ cmd str ptr ) then

if (pop lit1 ≥ cmd str ptr ) then begin str start [pop lit1 ] ← str start [pop lit1 + 1]; unflush string ; incr (lit stk ptr ); end

else if (length(pop lit2 ) = 0) then push lit stk (pop lit1 , stk str ) else { pop lit2 is nonnull, only pop lit1 is below cmd str ptr }

begin pool ptr ← str start [pop lit2 + 1]; str room(length(pop lit1 )); sp ptr ← str start [pop lit1 ]; sp end ← str start [pop lit1 + 1]; while (sp ptr < sp end ) do

begin append char (str pool [sp ptr ]); incr (sp ptr );

end; push lit stk (make string , stk str ); { and push it onto the stack } end

else ⟨ Concatenate them and push when pop lit2 < cmd str ptr 353 ⟩;

end

This code is used in section 351.

353. We simply continue the previous module. ⟨ Concatenate them and push when pop lit2 < cmd str ptr 353 ⟩ ≡

begin if (pop lit1 ≥ cmd str ptr ) then

if (length(pop lit2 ) = 0) then begin unflush string ; lit stack [lit stk ptr ] ← pop lit1 ; incr (lit stk ptr ); end

else if (length(pop lit1 ) = 0) then incr (lit stk ptr )

else { both strings nonnull, only pop lit2 is below cmd str ptr } begin sp length ← length(pop lit1 ); sp2 length ← length(pop lit2 ); str room(sp length + sp2 length); sp ptr ← str start [pop lit1 + 1]; sp end ← str start [pop lit1 ]; sp xptr1 ← sp ptr + sp2 length; while (sp ptr > sp end ) do { slide up pop lit1 }

begin decr (sp ptr ); decr (sp xptr1 ); str pool [sp xptr1 ] ← str pool [sp ptr ]; end;

sp ptr ← str start [pop lit2 ]; sp end ← str start [pop lit2 + 1]; while (sp ptr < sp end ) do { slide up pop lit2 }

begin append char (str pool [sp ptr ]); incr (sp ptr );

end; pool ptr ← pool ptr + sp length; push lit stk (make string , stk str ); { and push it onto the stack } end

else ⟨ Concatenate them and push when pop lit1 , pop lit2 < cmd str ptr 354 ⟩;

end

This code is used in section 352.

354. Again, we simply continue the previous module. ⟨ Concatenate them and push when pop lit1 , pop lit2 < cmd str ptr 354 ⟩ ≡

begin if (length(pop lit1 ) = 0) then incr (lit stk ptr ) else if (length(pop lit2 ) = 0) then push lit stk (pop lit1 , stk str )

else { both strings are nonnull, and both are below cmd str ptr } begin str room(length(pop lit1 ) + length(pop lit2 )); sp ptr ← str start [pop lit2 ]; sp end ← str start [pop lit2 + 1]; while (sp ptr < sp end ) do { slide up pop lit2 }

begin append char (str pool [sp ptr ]); incr (sp ptr );

end; sp ptr ← str start [pop lit1 ]; sp end ← str start [pop lit1 + 1]; while (sp ptr < sp end ) do { slide up pop lit1 }

begin append char (str pool [sp ptr ]); incr (sp ptr );

end; push lit stk (make string , stk str ); { and push it onto the stack } end; end

This code is used in section 353.

355. The built in function pops the top two literals and assigns to the first (which must be an int entry var , a str entry var , an int global var , or a str global var ) the value of the second; it complains if the value isn’t of the appropriate type. ⟨ execute fn( ) 355 ⟩ ≡ procedure x gets ;

begin pop lit stk (pop lit1 , pop typ1 ); pop lit stk (pop lit2 , pop typ2 ); if (pop typ1 ≠ stk fn) then print wrong stk lit (pop lit1 , pop typ1 , stk fn) else if ((¬mess with entries ) ∧ ((fn type[pop lit1 ] = str entry var ) ∨ (fn type[pop lit1 ] = int entry var )))

then bst cant mess with entries print

else case (fn type[pop lit1 ]) of int entry var : ⟨ Assign to an int entry var 356 ⟩; str entry var : ⟨ Assign to a str entry var 358 ⟩; int global var : ⟨ Assign to an int global var 359 ⟩; str global var : ⟨ Assign to a str global var 360 ⟩; othercases begin print (´ ␣ ´ ´ ␣ ␣ ␣ ␣´ ); print fn class (pop lit1 );

bst ex warn(´ ␣ ␣ ␣ ␣ ´ ); end endcases;

end;

This code is used in section 343.

356. This module checks that what we’re about to assign is really an integer, and then assigns. ⟨ Assign to an int entry var 356 ⟩ ≡

if (pop typ2 ≠ stk int ) then print wrong stk lit (pop lit2 , pop typ2 , stk int ) else entry ints [cite ptr ∗ num ent ints + fn info[pop lit1 ]] ← pop lit2

This code is used in section 355.

357. It’s time for a complaint if either of the two (entry or global) string lengths is exceeded.

define bst string size exceeded (#) ≡ begin bst 1print string size exceeded ; print (#); bst 2print string size exceeded ; end

⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure bst 1print string size exceeded ;

begin print (´ ´ ´ ␣ ␣´ ); end;

procedure bst 2print string size exceeded ; begin print (´ ´ ); bst mild ex warn print ; print ln(´ ␣ ␣ ␣ ␣ ´ ); end; 358. This module checks that what we’re about to assign is really a string, and then assigns. ⟨ Assign to a str entry var 358 ⟩ ≡

begin if (pop typ2 ≠ stk str ) then print wrong stk lit (pop lit2 , pop typ2 , stk str ) else begin str ent ptr ← cite ptr ∗ num ent strs + fn info[pop lit1 ]; ent chr ptr ← 0;

sp ptr ← str start [pop lit2 ]; sp xptr1 ← str start [pop lit2 + 1]; if (sp xptr1 − sp ptr > ent str size) then

begin bst string size exceeded (ent str size : 0, ´ ␣ ␣ ´ ); sp xptr1 ← sp ptr + ent str size; end;

while (sp ptr < sp xptr1 ) do begin { copy characters into entry strs } entry strs [str ent ptr ][ent chr ptr ] ← str pool [sp ptr ]; incr (ent chr ptr ); incr (sp ptr ); end;

entry strs [str ent ptr ][ent chr ptr ] ← end of string ; end

end

This code is used in section 355.

359. This module checks that what we’re about to assign is really an integer, and then assigns. ⟨ Assign to an int global var 359 ⟩ ≡

if (pop typ2 ≠ stk int ) then print wrong stk lit (pop lit2 , pop typ2 , stk int ) else fn info[pop lit1 ] ← pop lit2

This code is used in section 355.

360. This module checks that what we’re about to assign is really a string, and then assigns. ⟨ Assign to a str global var 360 ⟩ ≡

begin if (pop typ2 ≠ stk str ) then print wrong stk lit (pop lit2 , pop typ2 , stk str ) else begin str glb ptr ← fn info[pop lit1 ];

if (pop lit2 < cmd str ptr ) then glb str ptr [str glb ptr ] ← pop lit2 else begin glb str ptr [str glb ptr ] ← 0; glob chr ptr ← 0; sp ptr ← str start [pop lit2 ];

sp end ← str start [pop lit2 + 1]; if (sp end − sp ptr > glob str size) then

begin bst string size exceeded (glob str size : 0, ´ ␣ ␣ ´ ); sp end ← sp ptr + glob str size; end;

while (sp ptr < sp end ) do begin { copy characters into global strs } global strs [str glb ptr ][glob chr ptr ] ← str pool [sp ptr ]; incr (glob chr ptr ); incr (sp ptr ); end;

glb str end [str glb ptr ] ← glob chr ptr ; end;

end end

This code is used in section 355.

361. The built in function $ pops the top (string) literal, adds a period to a nonnull string if its last nonright brace character isn’t a period , question mark , or exclamation mark , and pushes this resulting string back onto the stack. If the literal isn’t a string, it complains and pushes the null string. ⟨ execute fn( $ ) 361 ⟩ ≡ procedure x add period ;

label loop exit ; begin pop lit stk (pop lit1 , pop typ1 ); if (pop typ1 ≠ stk str ) then

begin print wrong stk lit (pop lit1 , pop typ1 , stk str ); push lit stk (s null , stk str );

end else if (length(pop lit1 ) = 0) then { don’t add period to the null string }

push lit stk (s null , stk str ) else ⟨ Add the period , if necessary, and push 362 ⟩;

end;

This code is used in section 343.

362. Here we scan backwards from the end of the string, skipping nonright brace characters, to see if we have to add the period . ⟨ Add the period , if necessary, and push 362 ⟩ ≡

begin sp ptr ← str start [pop lit1 + 1]; sp end ← str start [pop lit1 ]; while (sp ptr > sp end ) do { find a nonright brace }

begin decr (sp ptr );

if (str pool [sp ptr ] ≠ right brace) then goto loop exit ;

end; loop exit : case (str pool [sp ptr ]) of

period , question mark , exclamation mark : repush string ; othercases ⟨ Add the period (it’s necessary) and push 363 ⟩ endcases; end

This code is used in section 361.

363. Ok guys, we really have to do it. ⟨ Add the period (it’s necessary) and push 363 ⟩ ≡

begin if (pop lit1 < cmd str ptr ) then begin str room(length(pop lit1 ) + 1); sp ptr ← str start [pop lit1 ]; sp end ← str start [pop lit1 + 1]; while (sp ptr < sp end ) do { slide pop lit1 atop the string pool }

begin append char (str pool [sp ptr ]); incr (sp ptr ); end;

end else { the string is already there } begin pool ptr ← str start [pop lit1 + 1]; str room(1); end; append char (period ); push lit stk (make string , stk str ); end

This code is used in section 362.

364. The built in function $ executes the function specified in type list for this entry unless it’s undefined , in which case it executes the default function defined in the file, or unless it’s empty , in which case it does nothing. ⟨ execute fn( $ ) 364 ⟩ ≡

begin if (¬mess with entries ) then bst cant mess with entries print else if (type list [cite ptr ] = undefined ) then execute fn(b default )

else if (type list [cite ptr ] = empty ) then do nothing

else execute fn(type list [cite ptr ]); end

This code is used in section 342.

365. The built in function $ pops the top two (string) literals; it changes the case of the second according to the specifications of the first, as follows. (Note: The word ‘letters’ in the next sentence refers only to those at brace-level 0, the top-most brace level; no other characters are changed, except perhaps for special characters, described shortly.) If the first literal is the string , it converts to lower case all letters except the very first character in the string, which it leaves alone, and except the first character following any colon and then nonnull white space, which it also leaves alone; if it’s the string , it converts all letters to lower case; if it’s the string , it converts all letters to upper case; and if it’s anything else, it complains and does no conversion. It then pushes this resulting string. If either type is incorrect, it complains and pushes the null string; however, if both types are correct but the specification string (i.e., the first string) isn’t one of the legal ones, it merely pushes the second back onto the stack, after complaining. (Another note: It ignores case differences in the specification string; for example, the strings and are equivalent for the purposes of this built in function.)

define ok pascal i give up = 21 ⟨ execute fn( $ ) 365 ⟩ ≡ procedure x change case;

label ok pascal i give up;

begin pop lit stk (pop lit1 , pop typ1 ); pop lit stk (pop lit2 , pop typ2 ); if (pop typ1 ≠ stk str ) then

begin print wrong stk lit (pop lit1 , pop typ1 , stk str ); push lit stk (s null , stk str ); end

else if (pop typ2 ≠ stk str ) then begin print wrong stk lit (pop lit2 , pop typ2 , stk str ); push lit stk (s null , stk str ); end

else begin ⟨ Determine the case-conversion type 367 ⟩; ex buf length ← 0; add buf pool (pop lit2 ); ⟨ Perform the case conversion 371 ⟩; add pool buf and push; { push this string onto the stack } end;

end;

This code is used in section 343.

366. First we define a few variables for case conversion. The constant definitions, to be used in case statements, are in order of probable frequency.

define title lowers = 0 { representing the string }

define all lowers = 1 { representing the string }

define all uppers = 2 { representing the string }

define bad conversion = 3 { representing any illegal case-conversion string } ⟨ Globals in the outer block 16 ⟩ +≡ conversion type: 0 . . bad conversion; { the possible cases } prev colon: boolean; { true if just past a colon } 367. Now we determine which of the three case-conversion types we’re dealing with: , , or . ⟨ Determine the case-conversion type 367 ⟩ ≡

begin case (str pool [str start [pop lit1 ]]) of , : conversion type ← title lowers ; , : conversion type ← all lowers ; , : conversion type ← all uppers ; othercases conversion type ← bad conversion endcases; if ((length(pop lit1 ) ≠ 1) ∨ (conversion type = bad conversion)) then

begin conversion type ← bad conversion; print pool str (pop lit1 ); bst ex warn(´ ␣ ␣ ␣ ␣ ␣ ´ ); end;

end

This code is used in section 365.

368. This procedure complains if the just-encountered right brace would make brace level negative. ⟨ Procedures and functions for name-string processing 368 ⟩ ≡ procedure decr brace level (pop lit var : str number );

begin if (brace level = 0) then braces unbalanced complaint (pop lit var ) else decr (brace level ); end;

See also sections 370, 385, 398, 402, 405, 407, 419, and 421. This code is used in section 12.

369. This complaint often arises because the style designer has to type lots of braces. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure braces unbalanced complaint (pop lit var : str number );

begin print (´ ´ ); print pool str (pop lit var ); bst mild ex warn(´ ␣ ´ ´ ␣ ␣ ␣ ´ ); end;

370. This one makes sure that brace level = 0 (it’s called at a point in a string where braces must be balanced). ⟨ Procedures and functions for name-string processing 368 ⟩ +≡ procedure check brace level (pop lit var : str number );

begin if (brace level > 0) then braces unbalanced complaint (pop lit var ); end; 371. Here’s where we actually go through the string and do the case conversion. ⟨ Perform the case conversion 371 ⟩ ≡

begin brace level ← 0; { this is the top level } ex buf ptr ← 0; { we start with the string’s first character } while (ex buf ptr < ex buf length) do

begin if (ex buf [ex buf ptr ] = left brace) then begin incr (brace level ); if (brace level ≠ 1) then goto ok pascal i give up; if (ex buf ptr + 4 > ex buf length) then goto ok pascal i give up else if (ex buf [ex buf ptr + 1] ≠ backslash) then goto ok pascal i give up; if (conversion type = title lowers ) then

if (ex buf ptr = 0) then goto ok pascal i give up

else if ((prev colon) ∧ (lex class [ex buf [ex buf ptr − 1]] = white space)) then

goto ok pascal i give up; ⟨ Convert a special character 372 ⟩;

ok pascal i give up: prev colon ← false;

end else if (ex buf [ex buf ptr ] = right brace) then

begin decr brace level (pop lit2 ); prev colon ← false;

end else if (brace level = 0) then ⟨ Convert a brace level = 0 character 377 ⟩;

incr (ex buf ptr ); end;

check brace level (pop lit2 ); end

This code is used in section 365.

372. We’re dealing with a special character (usually either an undotted ‘ı’ or ‘ȷ’, or an accent like one in Table 3.1 of the LaTEX manual, or a foreign character like one in Table 3.2) if the first character after the left brace is a backslash; the special character ends with the matching right brace. How we handle what’s in between depends on the special character. In general, this code will do reasonably well if there is other stuff, too, between braces, but it doesn’t try to do anything special with colons. ⟨ Convert a special character 372 ⟩ ≡

begin incr (ex buf ptr ); { skip over the left brace } while ((ex buf ptr < ex buf length) ∧ (brace level > 0)) do

begin incr (ex buf ptr ); { skip over the backslash } ex buf xptr ← ex buf ptr ; while ((ex buf ptr < ex buf length) ∧ (lex class [ex buf [ex buf ptr ]] = alpha)) do incr (ex buf ptr );

{ this scans the control sequence } control seq loc ← str lookup(ex buf , ex buf xptr , ex buf ptr − ex buf xptr , control seq ilk , dont insert ); if (hash found ) then ⟨ Convert the accented or foreign character, if necessary 373 ⟩; ex buf xptr ← ex buf ptr ; while ((ex buf ptr < ex buf length) ∧ (brace level > 0) ∧ (ex buf [ex buf ptr ] ≠ backslash)) do

begin { this scans to the next control sequence }

if (ex buf [ex buf ptr ] = right brace) then decr (brace level )

else if (ex buf [ex buf ptr ] = left brace) then incr (brace level ); incr (ex buf ptr ); end;

⟨ Convert a noncontrol sequence 376 ⟩; end;

decr (ex buf ptr ); { unskip the right brace } end

This code is used in section 371.

373. A control sequence, for the purposes of this program, consists just of the consecutive alphabetic characters following the backslash; it might be empty (although ones in this section aren’t). ⟨ Convert the accented or foreign character, if necessary 373 ⟩ ≡

begin case (conversion type) of title lowers , all lowers : case (ilk info[control seq loc]) of

n l upper , n o upper , n oe upper , n ae upper , n aa upper :

lower case(ex buf , ex buf xptr , ex buf ptr − ex buf xptr );

othercases do nothing

endcases; all uppers : case (ilk info[control seq loc]) of

n l , n o, n oe, n ae, n aa: upper case(ex buf , ex buf xptr , ex buf ptr − ex buf xptr ); n i , n j , n ss : ⟨ Convert, then remove the control sequence 375 ⟩;

othercases do nothing

endcases; bad conversion: do nothing ;

othercases case conversion confusion

endcases; end

This code is used in section 372.

374. Another bug complaint. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure case conversion confusion;

begin confusion(´ ␣ ␣ ␣ ␣ ´ ); end;

375. After converting the control sequence, we need to remove the preceding backslash and any following white space. ⟨ Convert, then remove the control sequence 375 ⟩ ≡

begin upper case(ex buf , ex buf xptr , ex buf ptr − ex buf xptr ); while (ex buf xptr < ex buf ptr ) do

begin { remove preceding backslash and shift down }

ex buf [ex buf xptr − 1] ← ex buf [ex buf xptr ]; incr (ex buf xptr );

end; decr (ex buf xptr ); while ((ex buf ptr < ex buf length) ∧ (lex class [ex buf [ex buf ptr ]] = white space)) do incr (ex buf ptr );

{ remove white space trailing the control seq } tmp ptr ← ex buf ptr ; while (tmp ptr < ex buf length) do

begin { more shifting down }

ex buf [tmp ptr − (ex buf ptr − ex buf xptr )] ← ex buf [tmp ptr ]; incr (tmp ptr )

end; ex buf length ← tmp ptr − (ex buf ptr − ex buf xptr ); ex buf ptr ← ex buf xptr ; end

This code is used in section 373.

376. There are no control sequences in what we’re about to convert, so a straight conversion suffices. ⟨ Convert a noncontrol sequence 376 ⟩ ≡

begin case (conversion type) of title lowers , all lowers : lower case(ex buf , ex buf xptr , ex buf ptr − ex buf xptr ); all uppers : upper case(ex buf , ex buf xptr , ex buf ptr − ex buf xptr ); bad conversion: do nothing ;

othercases case conversion confusion

endcases; end

This code is used in section 372.

377. This code does any needed conversion for an ordinary character; it won’t touch nonletters. ⟨ Convert a brace level = 0 character 377 ⟩ ≡

begin case (conversion type) of title lowers : begin if (ex buf ptr = 0) then do nothing

else if ((prev colon) ∧ (lex class [ex buf [ex buf ptr − 1]] = white space)) then do nothing

else lower case(ex buf , ex buf ptr , 1); if (ex buf [ex buf ptr ] = colon) then prev colon ← true else if (lex class [ex buf [ex buf ptr ]] ≠ white space) then prev colon ← false; end;

all lowers : lower case(ex buf , ex buf ptr , 1); all uppers : upper case(ex buf , ex buf ptr , 1); bad conversion: do nothing ;

othercases case conversion confusion

endcases; end

This code is used in section 371.

378. The built in function $ pops the top (string) literal, makes sure it’s a single character, converts it to the corresponding ASCII code integer, and pushes this integer. If the literal isn’t an appropriate string, it complains and pushes the integer 0. ⟨ execute fn( $ ) 378 ⟩ ≡ procedure x chr to int ;

begin pop lit stk (pop lit1 , pop typ1 ); if (pop typ1 ≠ stk str ) then

begin print wrong stk lit (pop lit1 , pop typ1 , stk str ); push lit stk (0, stk int ); end

else if (length(pop lit1 ) ≠ 1) then begin print (´ ´ ); print pool str (pop lit1 ); bst ex warn(´ ␣ ´ ´ ␣ ␣ ␣ ´ ); push lit stk (0, stk int ); end

else push lit stk (str pool [str start [pop lit1 ]], stk int ); { push the (ASCII code) integer } end;

This code is used in section 343.

379. The built in function $ pushes the appropriate string from cite list onto the stack. ⟨ execute fn( $) 379 ⟩ ≡ procedure x cite;

begin if (¬mess with entries ) then bst cant mess with entries print else push lit stk (cur cite str , stk str ); end;

This code is used in section 343.

380. The built in function $ pops the top literal from the stack and pushes two copies of it. ⟨ execute fn( $ ) 380 ⟩ ≡ procedure x duplicate;

begin pop lit stk (pop lit1 , pop typ1 ); if (pop typ1 ≠ stk str ) then

begin push lit stk (pop lit1 , pop typ1 ); push lit stk (pop lit1 , pop typ1 );

end else begin repush string ;

if (pop lit1 < cmd str ptr ) then push lit stk (pop lit1 , pop typ1 )

else begin str room(length(pop lit1 )); sp ptr ← str start [pop lit1 ]; sp end ← str start [pop lit1 + 1];

while (sp ptr < sp end ) do begin append char (str pool [sp ptr ]); incr (sp ptr ); end;

push lit stk (make string , stk str ); { and push it onto the stack } end;

end; end;

This code is used in section 343.

381. The built in function $ pops the top literal and pushes the integer 1 if it’s a missing field or a string having no nonwhite space characters, 0 otherwise. If the literal isn’t a missing field or a string, it complains and pushes 0. ⟨ execute fn( $) 381 ⟩ ≡ procedure x empty ;

label exit ; begin pop lit stk (pop lit1 , pop typ1 ); case (pop typ1 ) of stk str : ⟨ Push 0 if the string has a nonwhite space char, else 1 382 ⟩; stk field missing : push lit stk (1, stk int ); stk empty : push lit stk (0, stk int ); othercases begin print stk lit (pop lit1 , pop typ1 );

bst ex warn(´ ␣ ␣ ␣ ␣ ␣ ␣ ´ ); push lit stk (0, stk int );

end endcases;

exit : end;

This code is used in section 343.

382. When we arrive here we’re dealing with a legitimate string. If it has no characters, or has nothing but white space characters, we push 1, otherwise we push 0. ⟨ Push 0 if the string has a nonwhite space char, else 1 382 ⟩ ≡

begin sp ptr ← str start [pop lit1 ]; sp end ← str start [pop lit1 + 1]; while (sp ptr < sp end ) do

begin if (lex class [str pool [sp ptr ]] ≠ white space) then begin push lit stk (0, stk int ); return; end;

incr (sp ptr );

end; push lit stk (1, stk int ); end

This code is used in section 381.

383. The built in function $ pops the top three literals (they are a string, an integer, and a string literal, in that order). The last string literal represents a name list (each name corresponding to a person), the integer literal specifies which name to pick from this list, and the first string literal specifies how to format this name, as described in the BibTEX documentation. Finally, this function pushes the formatted name. If any of the types is incorrect, it complains and pushes the null string.

define von found = 52 { for when a von token is found } ⟨ execute fn( $ ) 383 ⟩ ≡ procedure x format name;

label loop1 exit , loop2 exit , von found ;

begin pop lit stk (pop lit1 , pop typ1 ); pop lit stk (pop lit2 , pop typ2 ); pop lit stk (pop lit3 , pop typ3 ); if (pop typ1 ≠ stk str ) then

begin print wrong stk lit (pop lit1 , pop typ1 , stk str ); push lit stk (s null , stk str ); end

else if (pop typ2 ≠ stk int ) then begin print wrong stk lit (pop lit2 , pop typ2 , stk int ); push lit stk (s null , stk str ); end

else if (pop typ3 ≠ stk str ) then begin print wrong stk lit (pop lit3 , pop typ3 , stk str ); push lit stk (s null , stk str ); end

else begin ex buf length ← 0; add buf pool (pop lit3 ); ⟨ Isolate the desired name 384 ⟩; ⟨ Copy name and count commas to determine syntax 388 ⟩; ⟨ Find the parts of the name 396 ⟩; ex buf length ← 0; add buf pool (pop lit1 ); figure out the formatted name; add pool buf and push; { push the formatted string onto the stack } end;

end;

This code is used in section 343.

384. This module skips over undesired names in pop lit3 and it throws away the “and” from the end of the name if it exists. When it’s done, ex buf xptr points to its first character and ex buf ptr points just past its last. ⟨ Isolate the desired name 384 ⟩ ≡

begin ex buf ptr ← 0; num names ← 0;

while ((num names < pop lit2 ) ∧ (ex buf ptr < ex buf length)) do begin incr (num names ); ex buf xptr ← ex buf ptr ; name scan for and (pop lit3 ); end;

if (ex buf ptr < ex buf length) then { remove the “and” }

ex buf ptr ← ex buf ptr − 4; if (num names < pop lit2 ) then

begin if (pop lit2 = 1) then print (´ ␣ ␣ ␣ ␣ ␣ ´ ) else print (´ ␣ ´ ´ ␣´ , pop lit2 : 0, ´ ␣ ␣ ␣ ´ ); print pool str (pop lit3 ); bst ex warn(´ ´ ); end

end

This code is used in section 383.

385. This module, starting at ex buf ptr , looks in ex buf for an “and” surrounded by nonnull white space. It stops either at ex buf length or just past the “and”, whichever comes first, setting ex buf ptr accordingly. Its parameter pop lit var is either pop lit3 or pop lit1 , depending on whether $ or $ calls it. ⟨ Procedures and functions for name-string processing 368 ⟩ +≡ procedure name scan for and (pop lit var : str number );

begin brace level ← 0; preceding white ← false; and found ← false; while ((¬and found ) ∧ (ex buf ptr < ex buf length)) do

case (ex buf [ex buf ptr ]) of

, : begin incr (ex buf ptr ); if (preceding white) then ⟨ See if we have an “and” 387 ⟩; { if so, and found ← true } preceding white ← false; end;

left brace: begin incr (brace level ); incr (ex buf ptr ); ⟨ Skip over ex buf stuff at brace level > 0 386 ⟩; preceding white ← false; end;

right brace: begin decr brace level (pop lit var ); { this checks for an error } incr (ex buf ptr ); preceding white ← false; end;

othercases if (lex class [ex buf [ex buf ptr ]] = white space) then begin incr (ex buf ptr ); preceding white ← true; end

else begin incr (ex buf ptr ); preceding white ← false;

end endcases;

check brace level (pop lit var );

end;

386. When we come here ex buf ptr is just past the left brace, and when we leave it’s either at ex buf length or just past the matching right brace. ⟨ Skip over ex buf stuff at brace level > 0 386 ⟩ ≡

while ((brace level > 0) ∧ (ex buf ptr < ex buf length)) do begin if (ex buf [ex buf ptr ] = right brace) then decr (brace level ) else if (ex buf [ex buf ptr ] = left brace) then incr (brace level ); incr (ex buf ptr ); end

This code is used in section 385.

387. When we come here ex buf ptr is just past the “a” or “A”, and when we leave it’s either at the same place or, if we found an “and”, at the following white space character. ⟨ See if we have an “and” 387 ⟩ ≡

begin if (ex buf ptr ≤ (ex buf length − 3)) then { enough characters are left }

if ((ex buf [ex buf ptr ] = ) ∨ (ex buf [ex buf ptr ] = )) then

if ((ex buf [ex buf ptr + 1] = ) ∨ (ex buf [ex buf ptr + 1] = )) then

if (lex class [ex buf [ex buf ptr + 2]] = white space) then begin ex buf ptr ← ex buf ptr + 2; and found ← true; end;

end

This code is used in section 385.

388. When we arrive here, the desired name is in ex buf [ex buf xptr ] through ex buf [ex buf ptr − 1]. This module does its thing for characters only at brace level = 0; the rest get processed verbatim. It removes leading white space (and sep char s), and trailing white space (and sep char s) and commas, complaining for each trailing comma. It then copies the name into name buf , removing all white space, sep char s and commas, counting commas, and constructing a list of name tokens, which are sequences of characters separated (at brace level = 0) by white space, sep char s or commas. Each name token but the first has an associated name sep char , the character that separates it from the preceding token. If there are too many (more than two) commas, a complaint is in order. ⟨ Copy name and count commas to determine syntax 388 ⟩ ≡

begin ⟨ Remove leading and trailing junk, complaining if necessary 389 ⟩; name bf ptr ← 0; num commas ← 0; num tokens ← 0; token starting ← true; { to indicate that a name token is starting } while (ex buf xptr < ex buf ptr ) do

case (ex buf [ex buf xptr ]) of

comma: ⟨ Name-process a comma 390 ⟩; left brace: ⟨ Name-process a left brace 391 ⟩; right brace: ⟨ Name-process a right brace 392 ⟩; othercases case (lex class [ex buf [ex buf xptr ]]) of white space: ⟨ Name-process a white space 393 ⟩; sep char : ⟨ Name-process a sep char 394 ⟩; othercases ⟨ Name-process some other character 395 ⟩ endcases endcases;

name tok [num tokens ] ← name bf ptr ; { this is an end-marker }

end

This code is used in section 383.

389. This module removes all leading white space (and sep char s), and trailing white space (and sep char s) and commas. It complains for each trailing comma. ⟨ Remove leading and trailing junk, complaining if necessary 389 ⟩ ≡

begin while ((ex buf xptr < ex buf ptr ) ∧ (lex class [ex buf [ex buf ptr ]] = white space) ∧ (lex class [ex buf [ex buf ptr ]] = sep char )) do incr (ex buf xptr ); { this removes leading stuff }

while (ex buf ptr > ex buf xptr ) do { now remove trailing stuff } case (lex class [ex buf [ex buf ptr − 1]]) of white space, sep char : decr (ex buf ptr ); othercases if (ex buf [ex buf ptr − 1] = comma) then

begin print (´ ␣´ , pop lit2 : 0, ´ ␣ ␣ ´ ); print pool str (pop lit3 ); print (´ ␣ ␣ ␣ ␣ ␣ ␣ ´ ); bst ex warn print ; decr (ex buf ptr ); end

else goto loop1 exit

endcases; loop1 exit : end

This code is used in section 388.

390. Here we mark the token number at which this comma has occurred. ⟨ Name-process a comma 390 ⟩ ≡

begin if (num commas = 2) then begin print (´ ␣ ␣ ␣ ␣ ␣´ , pop lit2 : 0, ´ ␣ ␣ ´ ); print pool str (pop lit3 ); print (´ ´ ); bst ex warn print ; end

else begin incr (num commas ); if (num commas = 1) then comma1 ← num tokens else comma2 ← num tokens ; { num commas = 2 } name sep char [num tokens ] ← comma; end;

incr (ex buf xptr ); token starting ← true; end

This code is used in section 388.

391. We copy the stuff up through the matching right brace verbatim. ⟨ Name-process a left brace 391 ⟩ ≡

begin incr (brace level ); if (token starting ) then

begin name tok [num tokens ] ← name bf ptr ; incr (num tokens );

end; name buf [name bf ptr ] ← ex buf [ex buf xptr ]; incr (name bf ptr ); incr (ex buf xptr ); while ((brace level > 0) ∧ (ex buf xptr < ex buf ptr )) do

begin if (ex buf [ex buf xptr ] = right brace) then decr (brace level )

else if (ex buf [ex buf xptr ] = left brace) then incr (brace level );

name buf [name bf ptr ] ← ex buf [ex buf xptr ]; incr (name bf ptr ); incr (ex buf xptr ); end;

token starting ← false; end

This code is used in section 388.

392. We don’t copy an extra right brace; this code will almost never be executed. ⟨ Name-process a right brace 392 ⟩ ≡

begin if (token starting ) then begin name tok [num tokens ] ← name bf ptr ; incr (num tokens ); end;

print (´ ␣´ , pop lit2 : 0, ´ ␣ ␣ ´ ); print pool str (pop lit3 ); bst ex warn(´ ␣ ´ ´ ␣ ␣ ´ ); incr (ex buf xptr ); token starting ← false; end

This code is used in section 388.

393. A token will be starting soon in a buffer near you, one way… ⟨ Name-process a white space 393 ⟩ ≡

begin if (¬token starting ) then name sep char [num tokens ] ← space; incr (ex buf xptr ); token starting ← true; end

This code is used in section 388.

394. or another. If one of the valid sep char s appears between tokens, we usually use it instead of a space. If the user has been silly enough to have multiple sep char s, or to have both white space and a sep char , we use the first such character. ⟨ Name-process a sep char 394 ⟩ ≡

begin if (¬token starting ) then name sep char [num tokens ] ← ex buf [ex buf xptr ]; incr (ex buf xptr ); token starting ← true; end

This code is used in section 388.

395. For ordinary characters, we just copy the character. ⟨ Name-process some other character 395 ⟩ ≡

begin if (token starting ) then begin name tok [num tokens ] ← name bf ptr ; incr (num tokens ); end;

name buf [name bf ptr ] ← ex buf [ex buf xptr ]; incr (name bf ptr ); incr (ex buf xptr ); token starting ← false; end

This code is used in section 388.

396. Here we set all the pointers for the various parts of the name, depending on which of the three possible syntaxes this name uses. ⟨ Find the parts of the name 396 ⟩ ≡

begin if (num commas = 0) then begin first start ← 0; last end ← num tokens ; jr end ← last end ; ⟨ Determine where the first name ends and von name starts and ends 397 ⟩; end

else if (num commas = 1) then begin von start ← 0; last end ← comma1 ; jr end ← last end ; first start ← jr end ; first end ← num tokens ; von name ends and last name starts stuff ; end

else if (num commas = 2) then begin von start ← 0; last end ← comma1 ; jr end ← comma2 ; first start ← jr end ; first end ← num tokens ; von name ends and last name starts stuff ; end

else confusion(´ ␣ ␣ ␣ ´ ); end

This code is used in section 383.

397. When there are no brace-level-0 commas in the name, the von name starts with the first nonlast token whose first brace-level-0 letter is in lower case (for the purposes of this determination, an accented or foreign character at brace-level-1 that’s in lower case will do, as well). A module following this one determines where the von name ends and the last starts. ⟨ Determine where the first name ends and von name starts and ends 397 ⟩ ≡

begin von start ← 0;

while (von start < last end − 1) do begin name bf ptr ← name tok [von start ]; name bf xptr ← name tok [von start + 1]; if (von token found ) then

begin von name ends and last name starts stuff ; goto von found ; end;

incr (von start );

end; { there’s no von name, so } while (von start > 0) do { backtrack if there are connected tokens }

begin if ((lex class [name sep char [von start ]] ≠ sep char ) ∨ (name sep char [von start ] = tie)) then

goto loop2 exit ; decr (von start ); end;

loop2 exit : von end ← von start ; von found : first end ← von start ;

end

This code is used in section 396.

398. It’s a von token if there exists a first brace-level-0 letter (or brace-level-1 special character), and it’s in lower case; in this case we return true. The token is in name buf , starting at name bf ptr and ending just before name bf xptr .

define return von found ≡ begin von token found ← true; return; end

⟨ Procedures and functions for name-string processing 368 ⟩ +≡ function von token found : boolean;

label exit ;

begin nm brace level ← 0; von token found ← false; { now it’s easy to exit if necessary } while (name bf ptr < name bf xptr ) do

if ((name buf [name bf ptr ] ≥ ) ∧ (name buf [name bf ptr ] ≤ )) then return

else if ((name buf [name bf ptr ] ≥ ) ∧ (name buf [name bf ptr ] ≤ )) then return von found

else if (name buf [name bf ptr ] = left brace) then begin incr (nm brace level ); incr (name bf ptr ); if ((name bf ptr + 2 < name bf xptr ) ∧ (name buf [name bf ptr ] = backslash)) then

⟨ Check the special character (and return) 399 ⟩ else ⟨ Skip over name buf stuff at nm brace level > 0 401 ⟩; end

else incr (name bf ptr );

exit : end; 399. When we come here name bf ptr is just past the left brace, but we always leave by returning. ⟨ Check the special character (and return) 399 ⟩ ≡

begin incr (name bf ptr ); { skip over the backslash } name bf yptr ← name bf ptr ; while ((name bf ptr < name bf xptr ) ∧ (lex class [name buf [name bf ptr ]] = alpha)) do

incr (name bf ptr ); { this scans the control sequence } control seq loc ← str lookup(name buf , name bf yptr , name bf ptr − name bf yptr , control seq ilk ,

dont insert ); if (hash found ) then ⟨ Handle this accented or foreign character (and return) 400 ⟩; while ((name bf ptr < name bf xptr ) ∧ (nm brace level > 0)) do

begin if ((name buf [name bf ptr ] ≥ ) ∧ (name buf [name bf ptr ] ≤ )) then return else if ((name buf [name bf ptr ] ≥ ) ∧ (name buf [name bf ptr ] ≤ )) then return von found

else if (name buf [name bf ptr ] = right brace) then decr (nm brace level ) else if (name buf [name bf ptr ] = left brace) then incr (nm brace level );

incr (name bf ptr );

end; return; end

This code is used in section 398.

400. The accented or foreign character is either ‘ ’ or ‘ ’ or one of the eleven alphabetic foreign characters in Table 3.2 of the LaTEX manual. ⟨ Handle this accented or foreign character (and return) 400 ⟩ ≡

begin case (ilk info[control seq loc]) of n oe upper , n ae upper , n aa upper , n o upper , n l upper : return; n i , n j , n oe, n ae, n aa, n o, n l , n ss : return von found ; othercases confusion(´ ␣ ␣ ´ ) endcases; end

This code is used in section 399.

401. When we come here name bf ptr is just past the left brace; when we leave it’s either at name bf xptr or just past the matching right brace. ⟨ Skip over name buf stuff at nm brace level > 0 401 ⟩ ≡

while ((nm brace level > 0) ∧ (name bf ptr < name bf xptr )) do begin if (name buf [name bf ptr ] = right brace) then decr (nm brace level ) else if (name buf [name bf ptr ] = left brace) then incr (nm brace level ); incr (name bf ptr ); end

This code is used in section 398.

402. The last name starts just past the last token, before the first comma (if there is no comma, there is deemed to be one at the end of the string), for which there exists a first brace-level-0 letter (or brace-level-1 special character), and it’s in lower case, unless this last token is also the last token before the comma, in which case the last name starts with this token (unless this last token is connected by a sep char other than a tie to the previous token, in which case the last name starts with as many tokens earlier as are connected by nonties to this last one (except on Tuesdays …), although this module never sees such a case). Note that if there are any tokens in either the von or last names, then the last name has at least one, even if it starts with a lower-case letter. ⟨ Procedures and functions for name-string processing 368 ⟩ +≡ procedure von name ends and last name starts stuff ;

label exit ;

begin { there may or may not be a von name }

von end ← last end − 1;

while (von end > von start ) do begin name bf ptr ← name tok [von end − 1]; name bf xptr ← name tok [von end ]; if (von token found ) then return; decr (von end ); end;

exit : end;

403. This module uses the information in pop lit1 to format the name. Everything at sp brace level = 0 is copied verbatim to the formatted string; the rest is described in the succeeding modules. ⟨ Figure out the formatted name 403 ⟩ ≡

begin ex buf ptr ← 0; sp brace level ← 0; sp ptr ← str start [pop lit1 ]; sp end ← str start [pop lit1 + 1]; while (sp ptr < sp end ) do

if (str pool [sp ptr ] = left brace) then begin incr (sp brace level ); incr (sp ptr ); ⟨ Format this part of the name 404 ⟩; end

else if (str pool [sp ptr ] = right brace) then begin braces unbalanced complaint (pop lit1 ); incr (sp ptr ); end

else begin append ex buf char and check (str pool [sp ptr ]); incr (sp ptr );

end; if (sp brace level > 0) then braces unbalanced complaint (pop lit1 ); ex buf length ← ex buf ptr ; end

This code is used in section 421.

404. When we arrive here we’re at sp brace level = 1, just past the left brace. Letters at this sp brace level other than those denoting the parts of the name (i.e., the first letters of ‘first,’ ‘last,’ ‘von,’ and ‘jr,’ ignoring case) are illegal. We do two passes over this group; the first determines whether we’re to output anything, and, if we are, the second actually outputs it. ⟨ Format this part of the name 404 ⟩ ≡

begin sp xptr1 ← sp ptr ; alpha found ← false; double letter ← false; end of group ← false; to be written ← true; while ((¬end of group) ∧ (sp ptr < sp end )) do

if (lex class [str pool [sp ptr ]] = alpha) then begin incr (sp ptr ); ⟨ Figure out what this letter means 406 ⟩; end

else if (str pool [sp ptr ] = right brace) then begin decr (sp brace level ); incr (sp ptr ); end of group ← true; end

else if (str pool [sp ptr ] = left brace) then begin incr (sp brace level ); incr (sp ptr ); skip stuff at sp brace level greater than one; end

else incr (sp ptr ); if ((end of group) ∧ (to be written)) then { do the second pass }

⟨ Finally format this part of the name 412 ⟩; end

This code is used in section 403.

405. When we come here sp ptr is just past the left brace, and when we leave it’s either at sp end or just past the matching right brace. ⟨ Procedures and functions for name-string processing 368 ⟩ +≡ procedure skip stuff at sp brace level greater than one;

begin while ((sp brace level > 1) ∧ (sp ptr < sp end )) do begin if (str pool [sp ptr ] = right brace) then decr (sp brace level ) else if (str pool [sp ptr ] = left brace) then incr (sp brace level ); incr (sp ptr ); end;

end; 406. We won’t output anything for this part of the name if this is a second occurrence of an sp brace level = 1 letter, if it’s an illegal letter, or if there are no tokens corresponding to this part. We also determine if we’re we to output complete tokens (indicated by a double letter). ⟨ Figure out what this letter means 406 ⟩ ≡

begin if (alpha found ) then begin brace lvl one letters complaint ; to be written ← false; end

else begin case (str pool [sp ptr − 1]) of , : ⟨ Figure out what tokens we’ll output for the ‘first’ name 408 ⟩; , : ⟨ Figure out what tokens we’ll output for the ‘von’ name 409 ⟩; , : ⟨ Figure out what tokens we’ll output for the ‘last’ name 410 ⟩; , : ⟨ Figure out what tokens we’ll output for the ‘jr’ name 411 ⟩; othercases begin brace lvl one letters complaint ; to be written ← false;

end endcases; if (double letter ) then incr (sp ptr ); end;

alpha found ← true; end

This code is used in section 404.

407. At most one of the important letters, perhaps doubled, may appear at sp brace level = 1. ⟨ Procedures and functions for name-string processing 368 ⟩ +≡ procedure brace lvl one letters complaint ;

begin print (´ ␣ ␣ ␣ ´ ); print pool str (pop lit1 ); bst ex warn(´ ␣ ␣ ␣ ␣ ␣ ´ ); end;

408. Here we set pointers into name tok and note whether we’ll be dealing with a full first-name tokens (double letter = true) or abbreviations (double letter = false). ⟨ Figure out what tokens we’ll output for the ‘first’ name 408 ⟩ ≡

begin cur token ← first start ; last token ← first end ; if (cur token = last token) then to be written ← false; if ((str pool [sp ptr ] = ) ∨ (str pool [sp ptr ] = )) then double letter ← true; end

This code is used in section 406.

409. The same as above but for von-name tokens. ⟨ Figure out what tokens we’ll output for the ‘von’ name 409 ⟩ ≡

begin cur token ← von start ; last token ← von end ; if (cur token = last token) then to be written ← false; if ((str pool [sp ptr ] = ) ∨ (str pool [sp ptr ] = )) then double letter ← true; end

This code is used in section 406.

410. The same as above but for last-name tokens. ⟨ Figure out what tokens we’ll output for the ‘last’ name 410 ⟩ ≡

begin cur token ← von end ; last token ← last end ; if (cur token = last token) then to be written ← false; if ((str pool [sp ptr ] = ) ∨ (str pool [sp ptr ] = )) then double letter ← true; end

This code is used in section 406.

411. The same as above but for jr-name tokens. ⟨ Figure out what tokens we’ll output for the ‘jr’ name 411 ⟩ ≡

begin cur token ← last end ; last token ← jr end ; if (cur token = last token) then to be written ← false; if ((str pool [sp ptr ] = ) ∨ (str pool [sp ptr ] = )) then double letter ← true; end

This code is used in section 406.

412. This is the second pass over this part of the name; here we actually write stuff out to ex buf . ⟨ Finally format this part of the name 412 ⟩ ≡

begin ex buf xptr ← ex buf ptr ; sp ptr ← sp xptr1 ; sp brace level ← 1; while (sp brace level > 0) do

if ((lex class [str pool [sp ptr ]] = alpha) ∧ (sp brace level = 1)) then begin incr (sp ptr ); ⟨ Figure out how to output the name tokens, and do it 413 ⟩; end

else if (str pool [sp ptr ] = right brace) then begin decr (sp brace level ); incr (sp ptr ); if (sp brace level > 0) then append ex buf char and check (right brace); end

else if (str pool [sp ptr ] = left brace) then begin incr (sp brace level ); incr (sp ptr ); append ex buf char and check (left brace); end

else begin append ex buf char and check (str pool [sp ptr ]); incr (sp ptr );

end;

if (ex buf ptr > 0) then

if (ex buf [ex buf ptr − 1] = tie) then ⟨ Handle a discretionary tie 420 ⟩; end

This code is used in section 404.

413. When we come here, sp ptr is just past the letter indicating the part of the name for which we’re about to output tokens. When we leave, it’s at the first character of the rest of the group. ⟨ Figure out how to output the name tokens, and do it 413 ⟩ ≡

begin if (double letter ) then incr (sp ptr ); use default ← true; sp xptr2 ← sp ptr ; if (str pool [sp ptr ] = left brace) then { find the inter-token string }

begin use default ← false; incr (sp brace level ); incr (sp ptr ); sp xptr1 ← sp ptr ; skip stuff at sp brace level greater than one; sp xptr2 ← sp ptr − 1; end;

⟨ Finally output the name tokens 414 ⟩; if (¬use default ) then sp ptr ← sp xptr2 + 1; end

This code is used in section 412.

414. Here, for each token in this part, we output either a full or an abbreviated token and the inter-token string for all but the last token of this part. ⟨ Finally output the name tokens 414 ⟩ ≡

while (cur token < last token) do begin if (double letter ) then ⟨ Finally output a full token 415 ⟩ else ⟨ Finally output an abbreviated token 416 ⟩; incr (cur token); if (cur token < last token) then ⟨ Finally output the inter-token string 418 ⟩; end

This code is used in section 413.

415. Here we output all the characters in the token, verbatim. ⟨ Finally output a full token 415 ⟩ ≡

begin name bf ptr ← name tok [cur token]; name bf xptr ← name tok [cur token + 1]; if (ex buf length + (name bf xptr − name bf ptr ) > buf size) then buffer overflow ; while (name bf ptr < name bf xptr ) do

begin append ex buf char (name buf [name bf ptr ]); incr (name bf ptr ); end;

end

This code is used in section 414.

416. Here we output the first alphabetic or special character of the token; brace level is irrelevant for an alphabetic (but not a special) character. ⟨ Finally output an abbreviated token 416 ⟩ ≡

begin name bf ptr ← name tok [cur token]; name bf xptr ← name tok [cur token + 1]; while (name bf ptr < name bf xptr ) do

begin if (lex class [name buf [name bf ptr ]] = alpha) then begin append ex buf char and check (name buf [name bf ptr ]); goto loop exit ; end

else if ((name buf [name bf ptr ] = left brace) ∧ (name bf ptr + 1 < name bf xptr )) then

if (name buf [name bf ptr + 1] = backslash) then

⟨ Finally output a special character and exit loop 417 ⟩; incr (name bf ptr ); end;

loop exit : end

This code is used in section 414.

417. We output a special character here even if the user has been silly enough to make it nonalphabetic (and even if the user has been sillier still by not having a matching right brace). ⟨ Finally output a special character and exit loop 417 ⟩ ≡

begin if (ex buf ptr + 2 > buf size) then buffer overflow ; append ex buf char (left brace); append ex buf char (backslash); name bf ptr ← name bf ptr + 2; nm brace level ← 1; while ((name bf ptr < name bf xptr ) ∧ (nm brace level > 0)) do

begin if (name buf [name bf ptr ] = right brace) then decr (nm brace level ) else if (name buf [name bf ptr ] = left brace) then incr (nm brace level ); append ex buf char and check (name buf [name bf ptr ]); incr (name bf ptr ); end;

goto loop exit ; end

This code is used in section 416.

418. Here we output either the  given string if it exists, or else the  sep char if it exists, or else

the default string. A tie is the default space character between the last two tokens of the name part, and between the first two tokens if the first token is short enough; otherwise, a space is the default.

define long token = 3 { a token this length or longer is “long” } ⟨ Finally output the inter-token string 418 ⟩ ≡

begin if (use default ) then begin if (¬double letter ) then append ex buf char and check (period ); if (lex class [name sep char [cur token]] = sep char ) then

append ex buf char and check (name sep char [cur token]) else if ((cur token = last token − 1) ∨ (¬enough text chars (long token))) then

append ex buf char and check (tie) else append ex buf char and check (space);

end else begin if (ex buf length + (sp xptr2 − sp xptr1 ) > buf size) then buffer overflow ;

sp ptr ← sp xptr1 ; while (sp ptr < sp xptr2 ) do

begin append ex buf char (str pool [sp ptr ]); incr (sp ptr ); end

end; end

This code is used in section 414.

419. This function looks at the string in ex buf , starting at ex buf xptr and ending just before ex buf ptr , and it returns true if there are enough chars , where a special character (even if it’s missing its matching right brace) counts as a single charcter. This procedure is called only for strings that don’t have too many right braces. ⟨ Procedures and functions for name-string processing 368 ⟩ +≡ function enough text chars (enough chars : buf pointer ): boolean;

begin num text chars ← 0; ex buf yptr ← ex buf xptr ; while ((ex buf yptr < ex buf ptr ) ∧ (num text chars < enough chars )) do

begin incr (ex buf yptr ); if (ex buf [ex buf yptr − 1] = left brace) then

begin incr (brace level );

if ((brace level = 1) ∧ (ex buf yptr < ex buf ptr )) then

if (ex buf [ex buf yptr ] = backslash) then begin incr (ex buf yptr ); { skip over the backslash } while ((ex buf yptr < ex buf ptr ) ∧ (brace level > 0)) do

begin if (ex buf [ex buf yptr ] = right brace) then decr (brace level ) else if (ex buf [ex buf yptr ] = left brace) then incr (brace level ); incr (ex buf yptr ); end; end;

end else if (ex buf [ex buf yptr − 1] = right brace) then decr (brace level ); incr (num text chars ); end;

if (num text chars < enough chars ) then enough text chars ← false else enough text chars ← true; end; 420. If the last character output for this name part is a tie but the previous character it isn’t, we’re dealing with a discretionary tie; thus we replace it by a space if there are enough characters in the rest of the name part.

define long name = 3 { a name this length or longer is “long” } ⟨ Handle a discretionary tie 420 ⟩ ≡

begin decr (ex buf ptr ); { remove the previous tie } if (ex buf [ex buf ptr − 1] = tie) then { it’s not a discretionary tie }

do nothing else if (¬enough text chars (long name)) then { this is a short name part }

incr (ex buf ptr ) { so restore the tie } else { replace it by a space }

append ex buf char (space); end

This code is used in section 412.

421. This is a procedure so that x format name is smaller. ⟨ Procedures and functions for name-string processing 368 ⟩ +≡ procedure figure out the formatted name;

label loop exit ; begin ⟨ Figure out the formatted name 403 ⟩; end;

422. The built in function $ pops the top three literals (they are two function literals and an integer literal, in that order); if the integer is greater than 0, it executes the second literal, else it executes the first. If any of the types is incorrect, it complains but does nothing else. ⟨ execute fn( $) 422 ⟩ ≡

begin pop lit stk (pop lit1 , pop typ1 ); pop lit stk (pop lit2 , pop typ2 ); pop lit stk (pop lit3 , pop typ3 ); if (pop typ1 ≠ stk fn) then print wrong stk lit (pop lit1 , pop typ1 , stk fn) else if (pop typ2 ≠ stk fn) then print wrong stk lit (pop lit2 , pop typ2 , stk fn)

else if (pop typ3 ≠ stk int ) then print wrong stk lit (pop lit3 , pop typ3 , stk int )

else if (pop lit3 > 0) then execute fn(pop lit2 )

else execute fn(pop lit1 ); end

This code is used in section 342.

423. The built in function $ pops the top (integer) literal, interpreted as the ASCII code of a single character, converts it to the corresponding single-character string, and pushes this string. If the literal isn’t an appropriate integer, it complains and pushes the null string. ⟨ execute fn( $ ) 423 ⟩ ≡ procedure x int to chr ;

begin pop lit stk (pop lit1 , pop typ1 ); if (pop typ1 ≠ stk int ) then

begin print wrong stk lit (pop lit1 , pop typ1 , stk int ); push lit stk (s null , stk str ); end

else if ((pop lit1 < 0) ∨ (pop lit1 > 127)) then begin bst ex warn(pop lit1 : 0, ´ ␣ ´ ´ ␣ ␣ ´ ); push lit stk (s null , stk str ); end

else begin str room(1); append char (pop lit1 ); push lit stk (make string , stk str );

end; end;

This code is used in section 343.

424. The built in function $ pops the top (integer) literal, converts it to its (unique) string equivalent, and pushes this string. If the literal isn’t an integer, it complains and pushes the null string. ⟨ execute fn( $ ) 424 ⟩ ≡ procedure x int to str ;

begin pop lit stk (pop lit1 , pop typ1 );

if (pop typ1 ≠ stk int ) then begin print wrong stk lit (pop lit1 , pop typ1 , stk int ); push lit stk (s null , stk str ); end

else begin int to ASCII (pop lit1 , ex buf , 0, ex buf length); add pool buf and push; { push this string onto the stack } end;

end;

This code is used in section 343.

425. The built in function $ pops the top literal and pushes the integer 1 if it’s a missing field, 0 otherwise. If the literal isn’t a missing field or a string, it complains and pushes 0. Unlike $, this function should be called only when mess with entries is true. ⟨ execute fn( $) 425 ⟩ ≡ procedure x missing ;

begin pop lit stk (pop lit1 , pop typ1 );

if (¬mess with entries ) then bst cant mess with entries print else if ((pop typ1 ≠ stk str ) ∧ (pop typ1 ≠ stk field missing )) then

begin if (pop typ1 ≠ stk empty ) then begin print stk lit (pop lit1 , pop typ1 ); bst ex warn(´ ␣ ␣ ␣ ␣ ␣ ␣ ´ ); end;

push lit stk (0, stk int );

end else if (pop typ1 = stk field missing ) then push lit stk (1, stk int )

else push lit stk (0, stk int ); end;

This code is used in section 343.

426. The built in function $ writes whatever has accumulated in the output buffer out buf onto the file. ⟨ execute fn( $) 426 ⟩ ≡

begin output bbl line;

end

This code is used in section 342.

427. The built in function $ pops the top (string) literal; it pushes the number of names the string represents—one plus the number of occurrences of the substring “and” (ignoring case differences) surrounded by nonnull white space at the top brace level. If the literal isn’t a string, it complains and pushes the value 0. ⟨ execute fn( $ ) 427 ⟩ ≡ procedure x num names ;

begin pop lit stk (pop lit1 , pop typ1 );

if (pop typ1 ≠ stk str ) then begin print wrong stk lit (pop lit1 , pop typ1 , stk str ); push lit stk (0, stk int ); end

else begin ex buf length ← 0; add buf pool (pop lit1 ); ⟨ Determine the number of names 428 ⟩; push lit stk (num names , stk int ); end;

end;

This code is used in section 343.

428. This module, while scanning the list of names, counts the occurrences of “and” (ignoring case differences) surrounded by nonnull white space, and adds 1. ⟨ Determine the number of names 428 ⟩ ≡

begin ex buf ptr ← 0; num names ← 0;

while (ex buf ptr < ex buf length) do begin name scan for and (pop lit1 ); incr (num names ); end;

end

This code is used in section 427.

429. The built in function $ pops the top of the stack but doesn’t print it. ⟨ execute fn( $) 429 ⟩ ≡

begin pop lit stk (pop lit1 , pop typ1 );

end

This code is used in section 342.

430. The built in function  $ pushes onto the stack the concatenation of all the  strings

read from the database files. ⟨ execute fn( $) 430 ⟩ ≡ procedure x preamble;

begin ex buf length ← 0; preamble ptr ← 0;

while (preamble ptr < num preamble strings ) do begin add buf pool (s preamble[preamble ptr ]); incr (preamble ptr ); end;

add pool buf and push; { push the concatenation string onto the stack }

end;

This code is used in section 343.

431. The built in function $ pops the top (string) literal, removes nonalphanumeric characters except for white space and sep char characters (these get converted to a space) and removes certain alphabetic characters contained in the control sequences associated with a special character, and pushes the resulting string. If the literal isn’t a string, it complains and pushes the null string. ⟨ execute fn( $) 431 ⟩ ≡ procedure x purify ;

begin pop lit stk (pop lit1 , pop typ1 );

if (pop typ1 ≠ stk str ) then begin print wrong stk lit (pop lit1 , pop typ1 , stk str ); push lit stk (s null , stk str ); end

else begin ex buf length ← 0; add buf pool (pop lit1 ); ⟨ Perform the purification 432 ⟩; add pool buf and push; { push this string onto the stack } end;

end;

This code is used in section 343.

432. The resulting string has nonalphanumeric characters removed, and each white space or sep char character converted to a space. The next module handles special characters. This code doesn’t complain if the string isn’t brace balanced. ⟨ Perform the purification 432 ⟩ ≡

begin brace level ← 0; { this is the top level }

ex buf xptr ← 0; { this pointer is for the purified string }

ex buf ptr ← 0; { and this one is for the original string }

while (ex buf ptr < ex buf length) do begin case (lex class [ex buf [ex buf ptr ]]) of white space, sep char : begin ex buf [ex buf xptr ] ← space; incr (ex buf xptr );

end; alpha, numeric: begin ex buf [ex buf xptr ] ← ex buf [ex buf ptr ]; incr (ex buf xptr );

end; othercases if (ex buf [ex buf ptr ] = left brace) then

begin incr (brace level );

if ((brace level = 1) ∧ (ex buf ptr + 1 < ex buf length)) then

if (ex buf [ex buf ptr + 1] = backslash) then ⟨ Purify a special character 433 ⟩; end

else if (ex buf [ex buf ptr ] = right brace) then if (brace level > 0) then decr (brace level )

endcases; incr (ex buf ptr );

end; ex buf length ← ex buf xptr ; end

This code is used in section 431.

433. Special characters (even without a matching right brace) are purified by removing the control sequences (but restoring the correct thing for ‘ ’ and ‘ ’ as well as the eleven alphabetic foreign characters in Table 3.2 of the LaTEX manual) and removing all nonalphanumeric characters (including white space and sep char s). ⟨ Purify a special character 433 ⟩ ≡

begin incr (ex buf ptr ); { skip over the left brace } while ((ex buf ptr < ex buf length) ∧ (brace level > 0)) do

begin incr (ex buf ptr ); { skip over the backslash }

ex buf yptr ← ex buf ptr ; { mark the beginning of the control sequence }

while ((ex buf ptr < ex buf length) ∧ (lex class [ex buf [ex buf ptr ]] = alpha)) do

incr (ex buf ptr ); { this scans the control sequence } control seq loc ← str lookup(ex buf , ex buf yptr , ex buf ptr − ex buf yptr , control seq ilk , dont insert ); if (hash found ) then ⟨ Purify this accented or foreign character 434 ⟩; while ((ex buf ptr < ex buf length) ∧ (brace level > 0) ∧ (ex buf [ex buf ptr ] ≠ backslash)) do

begin { this scans to the next control sequence }

case (lex class [ex buf [ex buf ptr ]]) of

alpha, numeric: begin ex buf [ex buf xptr ] ← ex buf [ex buf ptr ]; incr (ex buf xptr );

end; othercases if (ex buf [ex buf ptr ] = right brace) then decr (brace level ) else if (ex buf [ex buf ptr ] = left brace) then incr (brace level )

endcases; incr (ex buf ptr );

end; end;

decr (ex buf ptr ); { unskip the right brace (or last character) } end

This code is used in section 432.

434. We consider the purified character to be either the first alphabetic character of its control sequence, or perhaps both alphabetic characters. ⟨ Purify this accented or foreign character 434 ⟩ ≡

begin ex buf [ex buf xptr ] ← ex buf [ex buf yptr ]; { the first alphabetic character } incr (ex buf xptr ); case (ilk info[control seq loc]) of n oe, n oe upper , n ae, n ae upper , n ss : begin { and the second }

ex buf [ex buf xptr ] ← ex buf [ex buf yptr + 1]; incr (ex buf xptr );

end;

othercases do nothing

endcases; end

This code is used in section 433.

435. The built in function $ pushes the string consisting of the double quote character. ⟨ execute fn( $) 435 ⟩ ≡ procedure x quote;

begin str room(1); append char (double quote); push lit stk (make string , stk str ); end;

This code is used in section 343.

436. The built in function $ is a no-op. ⟨ execute fn( $) 436 ⟩ ≡

begin do nothing ;

end

This code is used in section 342.

437. The built in function $ pops and prints the whole stack; it’s meant to be used for style designers while debugging. ⟨ execute fn( $) 437 ⟩ ≡

begin pop whole stack ;

end

This code is used in section 342.

438. The built in function $ pops the top three literals (they are the two integers literals pop lit1 and pop lit2 and a string literal, in that order). It pushes the substring of the (at most) pop lit1 consecutive characters starting at the pop lit2 th character (assuming 1-based indexing) if pop lit2 is positive, and ending at the −pop lit2 th character from the end if pop lit2 is negative (where the first character from the end is the last character). If any of the types is incorrect, it complain and pushes the null string. ⟨ execute fn( $ ) 438 ⟩ ≡ procedure x substring ;

label exit ;

begin pop lit stk (pop lit1 , pop typ1 ); pop lit stk (pop lit2 , pop typ2 ); pop lit stk (pop lit3 , pop typ3 ); if (pop typ1 ≠ stk int ) then

begin print wrong stk lit (pop lit1 , pop typ1 , stk int ); push lit stk (s null , stk str ); end

else if (pop typ2 ≠ stk int ) then begin print wrong stk lit (pop lit2 , pop typ2 , stk int ); push lit stk (s null , stk str ); end

else if (pop typ3 ≠ stk str ) then begin print wrong stk lit (pop lit3 , pop typ3 , stk str ); push lit stk (s null , stk str ); end

else begin sp length ← length(pop lit3 );

if (pop lit1 ≥ sp length) then

if ((pop lit2 = 1) ∨ (pop lit2 = −1)) then begin repush string ; return; end;

if ((pop lit1 ≤ 0) ∨ (pop lit2 = 0) ∨ (pop lit2 > sp length) ∨ (pop lit2 < −sp length)) then begin push lit stk (s null , stk str ); return; end

else ⟨ Form the appropriate substring 439 ⟩;

end;

exit : end;

This code is used in section 343.

439. This module finds the substring as described in the last section, and slides it into place in the string pool, if necessary. ⟨ Form the appropriate substring 439 ⟩ ≡

begin if (pop lit2 > 0) then begin if (pop lit1 > sp length − (pop lit2 − 1)) then pop lit1 ← sp length − (pop lit2 − 1); sp ptr ← str start [pop lit3 ] + (pop lit2 − 1); sp end ← sp ptr + pop lit1 ; if (pop lit2 = 1) then

if (pop lit3 ≥ cmd str ptr ) then { no shifting—merely change pointers } begin str start [pop lit3 + 1] ← sp end ; unflush string ; incr (lit stk ptr ); return; end;

end else { −ex buf length ≤ pop lit2 < 0 } begin pop lit2 ← −pop lit2 ; if (pop lit1 > sp length − (pop lit2 − 1)) then pop lit1 ← sp length − (pop lit2 − 1); sp end ← str start [pop lit3 + 1] − (pop lit2 − 1); sp ptr ← sp end − pop lit1 ; end; while (sp ptr < sp end ) do { shift the substring }

begin append char (str pool [sp ptr ]); incr (sp ptr );

end; push lit stk (make string , stk str ); { and push it onto the stack } end

This code is used in section 438.

440. The built in function $ pops the top two literals from the stack and pushes them back swapped. ⟨ execute fn( $) 440 ⟩ ≡ procedure x swap;

begin pop lit stk (pop lit1 , pop typ1 ); pop lit stk (pop lit2 , pop typ2 ); if ((pop typ1 ≠ stk str ) ∨ (pop lit1 < cmd str ptr )) then

begin push lit stk (pop lit1 , pop typ1 );

if ((pop typ2 = stk str ) ∧ (pop lit2 ≥ cmd str ptr )) then unflush string ;

push lit stk (pop lit2 , pop typ2 );

end else if ((pop typ2 ≠ stk str ) ∨ (pop lit2 < cmd str ptr )) then

begin unflush string ; { this is pop lit1 }

push lit stk (pop lit1 , stk str ); push lit stk (pop lit2 , pop typ2 );

end else { bummer, both are recent strings }

⟨ Swap the two strings (they’re at the end of str pool ) 441 ⟩; end;

This code is used in section 343.

441. We have to swap both (a) the strings at the end of the string pool, and (b) their pointers on the literal stack. ⟨ Swap the two strings (they’re at the end of str pool ) 441 ⟩ ≡

begin ex buf length ← 0; add buf pool (pop lit2 ); { save the second string } sp ptr ← str start [pop lit1 ]; sp end ← str start [pop lit1 + 1]; while (sp ptr < sp end ) do { slide the first string down }

begin append char (str pool [sp ptr ]); incr (sp ptr );

end; push lit stk (make string , stk str ); { and push it onto the stack } add pool buf and push; { push second string onto the stack } end

This code is used in section 440.

442. The built in function $ pops the top (string) literal, and pushes the number of text characters it contains, where an accented character (more precisely, a “special character”, defined earlier) counts as a single text character, even if it’s missing its matching right brace, and where braces don’t count as text characters. If the literal isn’t a string, it complains and pushes the null string. ⟨ execute fn( $ ) 442 ⟩ ≡ procedure x text length;

begin pop lit stk (pop lit1 , pop typ1 ); if (pop typ1 ≠ stk str ) then

begin print wrong stk lit (pop lit1 , pop typ1 , stk str ); push lit stk (s null , stk str ); end

else begin num text chars ← 0; ⟨ Count the text characters 443 ⟩; push lit stk (num text chars , stk int ); { and push it onto the stack } end;

end;

This code is used in section 343.

443. Here we determine the number of text characters in the string, where an entire special character counts as a single text character (even if it’s missing its matching right brace), and where braces don’t count as text characters. ⟨ Count the text characters 443 ⟩ ≡

begin sp ptr ← str start [pop lit1 ]; sp end ← str start [pop lit1 + 1]; sp brace level ← 0; while (sp ptr < sp end ) do

begin incr (sp ptr );

if (str pool [sp ptr − 1] = left brace) then begin incr (sp brace level ); if ((sp brace level = 1) ∧ (sp ptr < sp end )) then

if (str pool [sp ptr ] = backslash) then begin incr (sp ptr ); { skip over the backslash } while ((sp ptr < sp end ) ∧ (sp brace level > 0)) do

begin if (str pool [sp ptr ] = right brace) then decr (sp brace level ) else if (str pool [sp ptr ] = left brace) then incr (sp brace level ); incr (sp ptr ); end;

incr (num text chars );

end; end

else if (str pool [sp ptr − 1] = right brace) then begin if (sp brace level > 0) then decr (sp brace level ); end

else incr (num text chars ); end;

end

This code is used in section 442.

444. The built in function $ pops the top two literals (the integer literal pop lit1 and a string literal, in that order). It pushes the substring of the (at most) pop lit1 consecutive text characters starting from the beginning of the string. This function is similar to $ , but this one considers an accented character (or more precisely, a “special character”, even if it’s missing its matching right brace) to be a single text character (rather than however many ASCII code characters it actually comprises), and this function doesn’t consider braces to be text characters; furthermore, this function appends any needed matching right braces. If any of the types is incorrect, it complains and pushes the null string. ⟨ execute fn( $ ) 444 ⟩ ≡ procedure x text prefix ;

label exit ;

begin pop lit stk (pop lit1 , pop typ1 ); pop lit stk (pop lit2 , pop typ2 );

if (pop typ1 ≠ stk int ) then begin print wrong stk lit (pop lit1 , pop typ1 , stk int ); push lit stk (s null , stk str ); end

else if (pop typ2 ≠ stk str ) then begin print wrong stk lit (pop lit2 , pop typ2 , stk str ); push lit stk (s null , stk str ); end

else if (pop lit1 ≤ 0) then begin push lit stk (s null , stk str ); return; end

else ⟨ Form the appropriate prefix 445 ⟩; exit : end;

This code is used in section 343.

445. This module finds the prefix as described in the last section, and appends any needed matching right braces. ⟨ Form the appropriate prefix 445 ⟩ ≡

begin sp ptr ← str start [pop lit2 ]; sp end ← str start [pop lit2 + 1]; { this may change } ⟨ Scan the appropriate number of characters 446 ⟩; if (pop lit2 ≥ cmd str ptr ) then { no shifting—merely change pointers }

pool ptr ← sp end else while (sp ptr < sp end ) do { shift the substring }

begin append char (str pool [sp ptr ]); incr (sp ptr ); end;

while (sp brace level > 0) do { add matching right braces } begin append char (right brace); decr (sp brace level ); end;

push lit stk (make string , stk str ); { and push it onto the stack } end

This code is used in section 444.

446. This section scans pop lit1 text characters, where an entire special character counts as a single text character (even if it’s missing its matching right brace), and where braces don’t count as text characters. ⟨ Scan the appropriate number of characters 446 ⟩ ≡

begin num text chars ← 0; sp brace level ← 0; sp xptr1 ← sp ptr ; while ((sp xptr1 < sp end ) ∧ (num text chars < pop lit1 )) do

begin incr (sp xptr1 );

if (str pool [sp xptr1 − 1] = left brace) then begin incr (sp brace level ); if ((sp brace level = 1) ∧ (sp xptr1 < sp end )) then

if (str pool [sp xptr1 ] = backslash) then begin incr (sp xptr1 ); { skip over the backslash } while ((sp xptr1 < sp end ) ∧ (sp brace level > 0)) do

begin if (str pool [sp xptr1 ] = right brace) then decr (sp brace level ) else if (str pool [sp xptr1 ] = left brace) then incr (sp brace level ); incr (sp xptr1 ); end;

incr (num text chars );

end; end

else if (str pool [sp xptr1 − 1] = right brace) then begin if (sp brace level > 0) then decr (sp brace level ); end

else incr (num text chars ); end;

sp end ← sp xptr1 ; end

This code is used in section 445.

447. The built in function $ pops and prints the top of the stack. ⟨ execute fn( $) 447 ⟩ ≡

begin pop top and print ; end

This code is used in section 342.

448. The built in function $ pushes the appropriate string from type list onto the stack (unless either it’s undefined or empty , in which case it pushes the null string). ⟨ execute fn( $) 448 ⟩ ≡ procedure x type;

begin if (¬mess with entries ) then bst cant mess with entries print

else if ((type list [cite ptr ] = undefined ) ∨ (type list [cite ptr ] = empty )) then push lit stk (s null , stk str )

else push lit stk (hash text [type list [cite ptr ]], stk str ); end;

This code is used in section 343.

449. The built in function $ pops the top (string) literal and prints it following a warning message. This is implemented as a special built in function rather than using the $ function so that it can mark warning . ⟨ execute fn( $) 449 ⟩ ≡ procedure x warning ;

begin pop lit stk (pop lit1 , pop typ1 );

if (pop typ1 ≠ stk str ) then print wrong stk lit (pop lit1 , pop typ1 , stk str )

else begin print (´ ´ ); print lit (pop lit1 , pop typ1 ); mark warning ;

end; end;

This code is used in section 343.

450. The built in function $ pops the top two (function) literals, and keeps executing the second as long as the (integer) value left on the stack by executing the first is greater than 0. If either type is incorrect, it complains but does nothing else. ⟨ execute fn( $) 450 ⟩ ≡

begin pop lit stk (r pop lt1 , r pop tp1 ); pop lit stk (r pop lt2 , r pop tp2 );

if (r pop tp1 ≠ stk fn) then print wrong stk lit (r pop lt1 , r pop tp1 , stk fn)

else if (r pop tp2 ≠ stk fn) then print wrong stk lit (r pop lt2 , r pop tp2 , stk fn)

else loop

begin execute fn(r pop lt2 ); { this is the $ test }

pop lit stk (pop lit1 , pop typ1 ); if (pop typ1 ≠ stk int ) then

begin print wrong stk lit (pop lit1 , pop typ1 , stk int ); goto end while; end

else if (pop lit1 > 0) then execute fn(r pop lt1 ) { this is the $ body }

else goto end while; end;

end while: { justifies this mean while }

end

This code is used in section 342.

451. The built in function $ pops the top (string) literal and pushes the integer that represents its width in units specified by the char width array. This function takes the literal literally; that is, it assumes each character in the string is to be printed as is, regardless of whether the character has a special meaning to TEX, except that special characters (even without their right braces) are handled specially. If the literal isn’t a string, it complains and pushes 0. ⟨ execute fn( $) 451 ⟩ ≡ procedure x width;

begin pop lit stk (pop lit1 , pop typ1 );

if (pop typ1 ≠ stk str ) then begin print wrong stk lit (pop lit1 , pop typ1 , stk str ); push lit stk (0, stk int ); end

else begin ex buf length ← 0; add buf pool (pop lit1 ); string width ← 0; ⟨ Add up the char widths in this string 452 ⟩; push lit stk (string width, stk int ); end

end;

This code is used in section 343.

452. We use the natural width for all but special characters, and we complain if the string isn’t bracebalanced. ⟨ Add up the char widths in this string 452 ⟩ ≡

begin brace level ← 0; { we’re at the top level }

ex buf ptr ← 0; { and the beginning of string }

while (ex buf ptr < ex buf length) do

begin if (ex buf [ex buf ptr ] = left brace) then begin incr (brace level ); if ((brace level = 1) ∧ (ex buf ptr + 1 < ex buf length)) then

if (ex buf [ex buf ptr + 1] = backslash) then ⟨ Determine the width of this special character 453 ⟩ else string width ← string width + char width[left brace] else string width ← string width + char width[left brace]; end

else if (ex buf [ex buf ptr ] = right brace) then begin decr brace level (pop lit1 ); string width ← string width + char width[right brace]; end

else string width ← string width + char width[ex buf [ex buf ptr ]]; incr (ex buf ptr ); end;

check brace level (pop lit1 );

end

This code is used in section 451.

453. We use the natural widths of all characters except that some characters have no width: braces, control sequences (except for the usual 13 accented and foreign characters, whose widths are given in the next module), and white space following control sequences (even a null control sequence). ⟨ Determine the width of this special character 453 ⟩ ≡

begin incr (ex buf ptr ); { skip over the left brace } while ((ex buf ptr < ex buf length) ∧ (brace level > 0)) do

begin incr (ex buf ptr ); { skip over the backslash }

ex buf xptr ← ex buf ptr ;

while ((ex buf ptr < ex buf length) ∧ (lex class [ex buf [ex buf ptr ]] = alpha)) do

incr (ex buf ptr ); { this scans the control sequence } if ((ex buf ptr < ex buf length) ∧ (ex buf ptr = ex buf xptr )) then incr (ex buf ptr )

{ this skips a nonalpha control seq } else begin control seq loc ← str lookup(ex buf , ex buf xptr , ex buf ptr − ex buf xptr , control seq ilk ,

dont insert ); if (hash found ) then ⟨ Determine the width of this accented or foreign character 454 ⟩; end;

while ((ex buf ptr < ex buf length) ∧ (lex class [ex buf [ex buf ptr ]] = white space)) do

incr (ex buf ptr ); { this skips following white space } while ((ex buf ptr < ex buf length) ∧ (brace level > 0) ∧ (ex buf [ex buf ptr ] ≠ backslash)) do

begin { this scans to the next control sequence }

if (ex buf [ex buf ptr ] = right brace) then decr (brace level ) else if (ex buf [ex buf ptr ] = left brace) then incr (brace level )

else string width ← string width + char width[ex buf [ex buf ptr ]]; incr (ex buf ptr ); end;

end; decr (ex buf ptr ); { unskip the right brace } end

This code is used in section 452.

454. Five of the 13 possibilities resort to special information not present in the char width array; the other eight simply use char width’s information for the first letter of the control sequence. ⟨ Determine the width of this accented or foreign character 454 ⟩ ≡

begin case (ilk info[control seq loc]) of n ss : string width ← string width + ss width; n ae: string width ← string width + ae width; n oe: string width ← string width + oe width; n ae upper : string width ← string width + upper ae width; n oe upper : string width ← string width + upper oe width; othercases string width ← string width + char width[ex buf [ex buf xptr ]] endcases; end

This code is used in section 453.

455. The built in function $ pops the top (string) literal and writes it onto the output buffer out buf (which will result in stuff being written onto the file if the buffer fills up). If the literal isn’t a string, it complains but does nothing else. ⟨ execute fn( $) 455 ⟩ ≡ procedure x write;

begin pop lit stk (pop lit1 , pop typ1 );

if (pop typ1 ≠ stk str ) then print wrong stk lit (pop lit1 , pop typ1 , stk str )

else add out pool (pop lit1 );

end;

This code is used in section 343.

160  CLEANING UP  BibTEX §456

456. Cleaning up. This section does any last-minute printing and ends the program. ⟨ Clean up and leave 456 ⟩ ≡

begin if ((read performed ) ∧ (¬reading completed )) then begin print (´ ␣ ␣ ␣´ , bib line num : 0, ´ ␣ ␣ ␣´ ); print bib name; end;

trace and stat printing ; ⟨ Print the job history 467 ⟩; a close(log file); { turn out the lights, the fat lady has sung; it’s over, Yogi } end

This code is used in section 10.

457. Here we print trace and/or stat information, if desired. ⟨ Procedures and functions for all file I/O, error messages, and such 3 ⟩ +≡ procedure trace and stat printing ;

begin trace ⟨ Print all - and -file information 458 ⟩; ⟨ Print all cite list and entry information 459 ⟩; ⟨ Print the wiz defined functions 464 ⟩; ⟨ Print the string pool 465 ⟩; ecart stat ⟨ Print usage statistics 466 ⟩; tats end;

458. This prints information obtained from the file about the other files. ⟨ Print all - and -file information 458 ⟩ ≡

begin if (num bib files = 1) then trace pr ln(´ ␣ ␣ ␣ ␣ ´ ) else trace pr ln(´ ␣´ , num bib files : 0, ´ ␣ ␣ ␣ ´ ); if (num bib files = 0) then trace pr ln(´ ␣␣␣ ´ ) else begin bib ptr ← 0;

while (bib ptr < num bib files ) do begin trace pr (´ ␣␣␣´ ); trace pr pool str (cur bib str ); trace pr pool str (s bib extension); trace pr newline; incr (bib ptr ); end;

end; trace pr (´ ␣ ␣ ␣ ␣´ ); if (bst str = 0) then trace pr ln(´ ´ ) else begin trace pr pool str (bst str ); trace pr pool str (s bst extension); trace pr newline;

end; end

This code is used in section 457.

§459 BibTEX CLEANING UP 161

459. In entry-sorted order, this prints an entry’s cite list string and, indirectly, its entry type and entry variables. ⟨ Print all cite list and entry information 459 ⟩ ≡

begin if (all entries ) then trace pr (´ ´ , all marker : 0, ´ ␣´ ); if (read performed ) then trace pr ln(´ ´ , old num cites : 0) else trace pr newline; trace pr (´ ␣´ , num cites : 0); if (num cites = 1) then trace pr ln(´ ␣ ´ ) else trace pr ln(´ ␣ ´ ); if (num cites = 0) then trace pr ln(´ ␣␣␣ ´ ) else begin sort cite ptr ← 0;

while (sort cite ptr < num cites ) do

begin if (¬read completed ) then { we didn’t finish the command }

cite ptr ← sort cite ptr else cite ptr ← sorted cites [sort cite ptr ]; trace pr pool str (cur cite str ); if (read performed ) then ⟨ Print entry information 460 ⟩ else trace pr newline; incr (sort cite ptr ); end;

end; end

This code is used in section 457.

460. This prints information gathered while reading the  and  files.

⟨ Print entry information 460 ⟩ ≡ begin trace pr (´ ␣ ␣´ ); if (type list [cite ptr ] = undefined ) then undefined : trace pr (´ ´ ) else if (type list [cite ptr ] = empty ) then trace pr (´ ␣ ␣ ␣ ´ )

else trace pr pool str (hash text [type list [cite ptr ]]); trace pr ln(´ ␣ ␣ ␣ ´ ); ⟨ Print entry strings 461 ⟩; trace pr (´ ␣␣ ␣ ␣ ´ ); ⟨ Print entry integers 462 ⟩; trace pr ln(´ ␣␣ ␣ ␣ ´ ); ⟨ Print fields 463 ⟩; end

This code is used in section 459.

461. This prints, for the current entry, the strings declared by the command. ⟨ Print entry strings 461 ⟩ ≡

begin if (num ent strs = 0) then trace pr ln(´ ␣␣␣␣ ´ ) else if (¬read completed ) then trace pr ln(´ ␣␣␣␣ ´ )

else begin str ent ptr ← cite ptr ∗ num ent strs ;

while (str ent ptr < (cite ptr + 1) ∗ num ent strs ) do begin ent chr ptr ← 0; trace pr (´ ␣␣␣␣ ´ ); while (entry strs [str ent ptr ][ent chr ptr ] ≠ end of string ) do

begin trace pr (xchr [entry strs [str ent ptr ][ent chr ptr ]]); incr (ent chr ptr ); end;

trace pr ln(´ ´ ); incr (str ent ptr );

end; end;

end

This code is used in section 460.

462. This prints, for the current entry, the integers declared by the command. ⟨ Print entry integers 462 ⟩ ≡

begin if (num ent ints = 0) then trace pr (´ ␣ ´ ) else if (¬read completed ) then trace pr (´ ␣ ´ )

else begin int ent ptr ← cite ptr ∗ num ent ints ;

while (int ent ptr < (cite ptr + 1) ∗ num ent ints ) do begin trace pr (´ ␣´ , entry ints [int ent ptr ] : 0); incr (int ent ptr ); end; end;

trace pr newline; end

This code is used in section 460.

463. This prints the fields stored for the current entry. ⟨ Print fields 463 ⟩ ≡

begin if (¬read performed ) then trace pr ln(´ ␣␣␣␣ ´ ) else begin field ptr ← cite ptr ∗ num fields ; field end ptr ← field ptr + num fields ; no fields ← true;

while (field ptr < field end ptr ) do

begin if (field info[field ptr ] ≠ missing ) then begin trace pr (´ ␣␣␣␣ ´ ); trace pr pool str (field info[field ptr ]); trace pr ln(´ ´ ); no fields ← false; end;

incr (field ptr );

end; if (no fields ) then trace pr ln(´ ␣␣␣␣ ´ ); end;

end

This code is used in section 460.

464. This gives all the wiz defined functions that appeared in the file. ⟨ Print the wiz defined functions 464 ⟩ ≡

begin trace pr ln(´ ␣ ␣ ␣ ´ ); if (wiz def ptr = 0) then trace pr ln(´ ␣␣␣ ´ ) else begin wiz fn ptr ← 0;

while (wiz fn ptr < wiz def ptr ) do

begin if (wiz functions [wiz fn ptr ] = end of def ) then trace pr ln(wiz fn ptr : 0, ´ ´ )

else if (wiz functions [wiz fn ptr ] = quote next fn) then

trace pr (wiz fn ptr : 0, ´ ␣␣ ␣␣␣␣´ ) else begin trace pr (wiz fn ptr : 0, ´ ␣␣` ´ ); trace pr pool str (hash text [wiz functions [wiz fn ptr ]]);

trace pr ln(´ ´ ´ ´ );

end; incr (wiz fn ptr ); end;

end; end

This code is used in section 457.

465. This includes all the ‘static’ strings (that is, those that are also in the hash table), but none of the dynamic strings (that is, those put on the stack while executing commands). ⟨ Print the string pool 465 ⟩ ≡

begin trace pr ln(´ ␣ ␣ ␣ ´ ); str num ← 1; while (str num < str ptr ) do

begin trace pr (str num : 4, str start [str num] : 6, ´ ␣ ´ ); trace pr pool str (str num); trace pr ln(´ ´ ); incr (str num); end;

end

This code is used in section 457.

466. These statistics can help determine how large some of the constants should be and can tell how useful certain built in functions are. They are written to the same files as tracing information.

define stat pr ≡ trace pr define stat pr ln ≡ trace pr ln define stat pr pool str ≡ trace pr pool str

⟨ Print usage statistics 466 ⟩ ≡ begin stat pr (´ ´ ´ ␣ ␣´ , num cites : 0); if (num cites = 1) then stat pr ln(´ ␣ ´ ) else stat pr ln(´ ␣ ´ ); stat pr ln(´ ␣␣␣␣␣␣␣␣␣␣␣␣´ , wiz def ptr : 0, ´ ␣ ␣ ´ ); stat pr ln(´ ␣␣␣␣␣␣␣␣␣␣␣␣´ , str ptr : 0, ´ ␣ ␣ ␣´ , str start [str ptr ] : 0, ´ ␣ ´ ); blt in ptr ← 0; total ex count ← 0; while (blt in ptr < num blt in fns ) do

begin total ex count ← total ex count + execution count [blt in ptr ]; incr (blt in ptr ); end;

stat pr ln(´ ␣ ␣ ␣ ␣ ␣´ , total ex count : 0, ´ ␣ ␣ ␣ ´ ); blt in ptr ← 0; while (blt in ptr < num blt in fns ) do

begin stat pr pool str (hash text [blt in loc[blt in ptr ]]);

stat pr ln(´ ␣ ␣´ , execution count [blt in ptr ] : 0); incr (blt in ptr );

end; end

This code is used in section 457.

467. Some implementations may wish to pass the history value to the operating system so that it can be used to govern whether or not other programs are started. Here we simply report the history to the user. ⟨ Print the job history 467 ⟩ ≡

case (history ) of spotless : do nothing ; warning message: begin if (err count = 1) then print ln(´ ␣ ␣ ␣ ´ )

else print ln(´ ␣ ␣´ , err count : 0, ´ ␣ ´ );

end; error message: begin if (err count = 1) then print ln(´ ␣ ␣ ␣ ␣ ´ )

else print ln(´ ␣ ␣´ , err count : 0, ´ ␣ ␣ ´ );

end; fatal message: print ln(´ ␣ ␣ ␣ ␣ ´ ); othercases begin print (´ ␣ ␣ ´ ); print confusion;

end endcases

This code is used in section 456.

§468 BibTEX SYSTEM-DEPENDENT CHANGES 165

468. System-dependent changes. This section should be replaced, if necessary, by changes to the program that are necessary to make BibTEX work at a particular installation. It is usually best to design your change file so that all changes to previous sections preserve the section numbering; then everybody’s version will be consistent with the printed program. More extensive changes, which introduce new sections, can be inserted here; then only the index itself will get a new section number.

166  INDEX  BibTEX §469

469* . Index. Here is where you can find all uses of each identifier in the program, with underlined entries pointing to where the identifier was defined. If the identifier is only one letter long, however, you get to see only the underlined entries. All references are to section numbers instead of page numbers.

This index also lists a few error messages and other aspects of the program that you might want to look up some day. For example, the entry for “system dependencies” lists all sections that should receive special attention from people who are installing TEX in a new operating environment. A list of various things that can’t happen appears under “this can’t happen”.

The following sections were changed by the change file: 1, 2, 4, 11, 13, 14, 15, 36, 37, 39, 40, 48, 78, 98, 101, 102, 103, 107, 124, 128, 142, 152, 199, 469.

a close: 143, 152* , 224, 456. a minus : 332. a open in: 107* , 124* , 128* , 142* . a open out : 107* . add a built-in function: 332, 334, 335, 342, 343. add area: \underline{62}. add buf pool : \underline{321}, 365, 383, 427, 430, 431,

441, 451. add database cite: 265, \underline{266}, 273. add extension: \underline{61}, 107* , 108, 124* , 128* . add out pool : \underline{323}, 455. add pool buf and push: \underline{319}, 330, 365, 383, 424,

430, 431, 441. ae width: \underline{35}, 454. all entries : \underline{130}, 132, 135, 146, 220, 228, 264, 265,

266, 268, 269, 270, 271, 273, 280, 284, 459. all lowers : 338, \underline{366}, 367, 373, 376, 377. all marker : \underline{130}, 135, 228, 269, 271, 273, 287, 459. all uppers : 338, \underline{366}, 367, 373, 376, 377. alpha: \underline{31}, 32, 89, 372, 399, 404, 412, 416,

432, 433, 453. alpha file: 48* , 52, 83, 105, 118, 125. alpha found : \underline{345}, 404, 406. already seen function print : \underline{170}. and found : \underline{345}, 385, 387. any value: \underline{9}, 228. append char : \underline{54}, 72, 319, 331, 352, 353, 354, 363,

380, 423, 435, 439, 441, 445. append ex buf char : \underline{320}, 321, 330, 415, 417,

418, 420. append ex buf char and check : \underline{320}, 403, 412,

416, 417, 418. append int char : \underline{198}, 199* . area: \underline{62}. argc: 101* . argv : 103* . arg1 : \underline{302}. arg2 : \underline{302}. ASCII code: 21. ASCII code: \underline{22}, 23, 24, 30, 31, 34, 41, 42, 43, 48* ,

49, 54, 84, 85, 86, 87, 88, 91, 162, 199* , 217, 220, 231, 302, 345, 378, 423, 444.

at bib command : \underline{220}, 222, 237, 240, 260, 262.

at sign: \underline{29}, 219, 238, 239.
aux bib data command : 117, \underline{121}.
aux bib style command : 117, \underline{127}.
aux citation command : 117, \underline{133}.
aux command ilk : \underline{65}, 80, 117.
aux done: \underline{110}, 111, 143.
aux end err : \underline{145}, 146.
aux end1 err print : \underline{145}.
aux end2 err print : \underline{145}.
aux err : \underline{112}, 123.
aux err illegal another : \underline{113}, 121, 127.
aux err illegal another print : \underline{113}.
aux err no right brace: \underline{114}, 121, 127, 133, 140.
aux err no right brace print : \underline{114}.
aux err print : \underline{112}.
aux err return: \underline{112}, 113, 114, 115, 116, 123, 128* ,

135, 136, 141, 142* . aux err stuff after right brace: \underline{115}, 121, 127,

133, 140. aux err stuff after right brace print : \underline{115}. aux err white space in argument : \underline{116}, 121, 127,

133, 140. aux err white space in argument print : \underline{116}. aux extension ok : \underline{140}, 141. aux file: \underline{105}. aux file ilk : \underline{65}, 108, 141. aux found : \underline{98*} , 101* , 104. aux input command : 117, \underline{140}. aux list : \underline{105}, 106, 108. aux ln stack : \underline{105}. aux name length: \underline{98*} , 99, 101* , 103* , 104, 107* , 108. aux not found : \underline{98*} , 99, 100, \underline{101*} . aux number : 105, \underline{106}. aux ptr : \underline{105}, 107* , 141, 142* , 143. aux stack size: \underline{14*} , 105, 106, 110, 141. auxiliary-file commands: 110, 117.

: 140. : 121. : 127. : 133.

b : 332.

§469 BibTEX INDEX 167

b add period : \underline{332}, 335. b call type: \underline{332}, 335. b change case: \underline{332}, 335. b chr to int : \underline{332}, 335. b cite: \underline{332}, 335. b concatenate: \underline{332}, 335. b default : 183, \underline{332}, 340, 364. b duplicate: \underline{332}, 335. b empty : \underline{332}, 335. b equals : \underline{332}, 335. b format name: \underline{332}, 335. b gat : 332. b gets : \underline{332}, 335. b greater than: \underline{332}, 335. b if : \underline{332}, 335. b int to chr : \underline{332}, 335. b int to str : \underline{332}, 335. b less than: \underline{332}, 335. b minus : \underline{332}, 335. b missing : \underline{332}, 335. b newline: \underline{332}, 335. b num names : \underline{332}, 335. b plus : \underline{332}, 335. b pop: \underline{332}, 335. b preamble: \underline{332}, 335. b purify : \underline{332}, 335. b quote: \underline{332}, 335. b skip: \underline{332}, 335, 340. b stack : \underline{332}, 335. b substring : \underline{332}, 335. b swap: \underline{332}, 335. b text length: \underline{332}, 335. b text prefix : \underline{332}, 335. b top stack : \underline{332}, 335. b type: \underline{332}, 335. b warning : \underline{332}, 335. b while: \underline{332}, 335. b width: \underline{332}, 335. b write: \underline{332}, 335. backslash: \underline{29}, 371, 372, 373, 375, 398, 399, 416,

417, 419, 432, 433, 443, 446, 452, 453. bad : 13* , \underline{16}, 17, 303. bad argument token: \underline{178}, 180, 205, 214. bad conversion: \underline{366}, 367, 373, 376, 377. bad cross reference print : \underline{281}, 282, 283. banner : \underline{1*} , 10. bbl file: \underline{105}, 107* , 152* , 322. bbl line num: \underline{148}, 152* , 322. begin: 4* . bf ptr : \underline{57}, \underline{63}, \underline{64}, \underline{96}. bib brace level : \underline{248}, 254, 255, 256, 257, 258. bib cmd confusion: 240, \underline{241}, 263. bib command ilk : \underline{65}, 80, 239. bib equals sign expected err : \underline{232}, 247, 276.

bib equals sign print : \underline{232}.
bib err : \underline{222}, 230, 231, 232, 233, 234, 236,

243, 247, 269. bib err print : \underline{222}. bib field too long err : \underline{234}, 252. bib field too long print : \underline{234}. bib file: \underline{118}. bib file ilk : \underline{65}, 124* . bib id print : \underline{236}. bib identifier scan check : \underline{236}, 239, 245, 260, 276. BIB INPUT PATH : 124* . BIB INPUT PATH BIT : 101* . bib line num: \underline{220}, 221, 224, 229, 238, 253, 456. bib list : \underline{118}, 119, 120, 124* . bib ln num print : \underline{221}, 222, 223. bib number : 118, \underline{119}, 220, 338. bib one of two expected err : \underline{231}, 243, 245, 267,

275. bib one of two print : \underline{231}. bib ptr : \underline{118}, 120, 124* , 146, 224, 458. bib seen: \underline{118}, 120, 121, 146. bib unbalanced braces err : \underline{233}, 255, 257. bib unbalanced braces print : \underline{233}. bib warn: \underline{223}. bib warn newline: \underline{223}, 235, 264, 274. bib warn print : \underline{223}. biblical procreation: 332. BibTEX : \underline{10}. : 45.

buffer size: 47, 48* , 198, 320, 321, 415, 417, 418. file name size: 59, 60, 61, 62. hash size: 72. literal-stack size: 308. number of files: 141. number of files: 124* . number of cite keys: 139. number of string global-variables: 217. number of strings: 55. output buffer size: 323. pool size: 54. single function space: 189. total number of fields: 227. total number of integer entry-variables: 288. total number of string entry-variables: 289. wizard-defined function space: 201.

BibTEX documentation: \underline{1*} .

BibTEX: \underline{1*} .

blt in loc: \underline{332}, 336, 466.

blt in num: \underline{336}. blt in ptr : \underline{332}, 466. blt in range: 332, \underline{333}, 336. boolean: 48* , 57, 58, 66, 69, 84, 85, 86, 87, 88,

89, 93, 94, 95, 118, 125, 130, 140, 153, 162, 164, 178, 220, 229, 250, 251, 253, 254, 279, 291, 302, 345, 366, 398, 419.

bottom up: 12. brace level : \underline{291}, 368, 370, 371, 372, 385, 386, 388,

391, 419, 432, 433, 452, 453. brace lvl one letters complaint : 406, \underline{407}. braces unbalanced complaint : 368, \underline{369}, 370, 403. break ptr : \underline{323}, 324, 325. bst cant mess with entries print : \underline{296}, 328, 329,

330, 355, 364, 379, 425, 448. bst command ilk : \underline{65}, 80, 155. bst done: \underline{147}, 150, 152* . bst entry command : 156, \underline{171}. bst err : \underline{150}, 154, 155, 167, 168, 169, 170, 171,

178, 179, 204, 206, 208, 209, 210, 212, 213, 215. bst err print and look for blank line: \underline{150}. bst err print and look for blank line return: \underline{150},

170, 178. bst ex warn: \underline{294}, 296, 310, 318, 346, 355, 367,

378, 381, 384, 392, 407, 423, 425. bst ex warn print : \underline{294}, 313, 389, 390. bst execute command : 156, \underline{179}. bst file: \underline{125}, 128* , 150, 152* , 153. bst file ilk : \underline{65}, 128* . bst fn ilk : \underline{65}, 157, 173, 175, 177, 178, 183, 193,

195, 200, 203, 217, 239, 276, 336, 341. bst function command : 156, \underline{181}. bst get and check left brace: \underline{168}, 172, 174, 176,

179, 181, 182, 202, 204, 207, 209, 213, 216. bst get and check right brace: \underline{169}, 179, 182, 204,

207, 209, 213. bst id print : \underline{167}. bst identifier scan: \underline{167}, 172, 174, 176, 179, 182,

202, 204, 207, 213, 216. bst integers command : 156, \underline{202}. bst iterate command : 156, \underline{204}. bst left brace print : \underline{168}. bst line num: \underline{148}, 149, 150, 152* , 153. bst ln num print : \underline{149}, 150, 151, 184, 294. bst macro command : 156, \underline{206}. bst mild ex warn: \underline{295}, 369. bst mild ex warn print : \underline{295}, 357. bst read command : 156, \underline{212}. bst reverse command : 156, \underline{213}. bst right brace print : \underline{169}. bst seen: \underline{125}, 126, 127, 146. bst sort command : 156, \underline{215}. bst str : \underline{125}, 126, 128* , 129, 146, 152* , 458. bst string size exceeded : \underline{357}, 358, 360. bst strings command : 156, \underline{216}.

bst warn: \underline{151}, 171, 295.
bst warn print : \underline{151}.
bst 1print string size exceeded : \underline{357}.
bst 2print string size exceeded : \underline{357}.
buf : \underline{57}, \underline{63}, \underline{64}, \underline{69}, 70, 71, 72.
buf pointer : 42, \underline{43}, 44, 57, 63, 64, 69, 81, 83, 96,

188, 199* , 291, 323, 345, 419. buf ptr1 : \underline{81}, 82, 83, 84, 85, 86, 87, 88, 89, 91,

93, 94, 117, 124* , 128* , 134, 135, 136, 137, 141, 155, 173, 175, 177, 178, 183, 191, 192, 193, 200, 203, 208, 210, 217, 239, 246, 259, 260, 268, 270, 273, 274, 276.

buf ptr2 : \underline{81}, 82, 83, 84, 85, 86, 87, 88, 89, 91, 93, 94, 95, 96, 117, 121, 127, 133, 134, 140, 141, 150, 152* , 153, 168, 169, 172, 174, 176, 188, 191, 192, 193, 195, 202, 210, 212, 216, 224, 229, 238, 239, 243, 245, 247, 250, 253, 254, 255, 256, 257, 258, 259, 267, 268, 275, 276.

buf size: \underline{14*} , 17, 43, 47, 48* , 198, 234, 252, 320,

321, 323, 415, 417, 418. buf type: 42, \underline{43}, 44, 57, 63, 64, 69, 199* , 291. buffer : \underline{42}, 43, 48* , 69, 78* , 81, 82, 83, 84, 96, 108, 117, 124* , 128* , 134, 135, 136, 137, 141, 155, 173, 175, 177, 178, 183, 191, 192, 193, 200, 203, 208, 210, 212, 217, 239, 246, 259, 260, 268, 270, 273, 274, 276.

buffer overflow : \underline{47}, 48* , 198, 320, 321, 415,

417, 418. build in: 335, \underline{336}. built in: 44, 51, \underline{157}, 159, 160, 178, 179, 180, 183, 204, 205, 213, 214, 326, 332, 333, 334, 335, 336, 338, 342, 343, 344, 346, 347, 348, 349, 350, 351, 355, 361, 364, 365, 378, 379, 380, 381, 383, 422, 423, 424, 425, 426, 427, 429, 430, 431, 435, 436, 437, 438, 440, 442, 444, 447, 448, 449, 450, 451, 455, 466.

bunk, history: 467. case mismatch: 133. case mismatch errors: 136, 274. case conversion confusion: 373, \underline{374}, 376, 377. case difference: \underline{63}, 64. Casey Stengel would be proud: 402. char : 23, 37* , 74, 98* . char ptr : \underline{302}. char value: \underline{92}, 93, 94. char width: \underline{34}, 35, 451, 452, 453, 454. character set dependencies: 23, 25, 26, 27, 32,

33, 35. char1 : \underline{84}, \underline{85}, \underline{86}, \underline{87}, \underline{88}, \underline{91}, \underline{231}, \underline{302}.

char2 : \underline{86}, \underline{87}, \underline{88}, \underline{91}, \underline{231}, \underline{302}.
char3 : \underline{88}, \underline{91}.
check brace level : \underline{370}, 371, 385, 452.

check cite overflow : 137, \underline{139}, 266. check cmnd line: 102* . check command execution: 297, 298, 299, \underline{318}. check field overflow : 226, \underline{227}, 266. check for already seen function: \underline{170}, 173, 175,

177, 183, 203, 217. check for and compress bib white space: \underline{253},

254, 257, 258. child entry: 278. chr : 23, 24, 27, 28, 59, 61, 62. citation seen: \underline{130}, 132, 133, 146. cite already set : \underline{237}, 273. cite found : \underline{130}. cite hash found : \underline{220}, 279, 280, 286. cite ilk : \underline{65}, 136, 137, 265, 270, 273, 274, 279. cite info: \underline{220}, 228, 265, 271, 280, 284, 287,

290, 291. cite key disappeared confusion: 271, \underline{272}, 286. cite list : 14* , 65, \underline{130}, 131, 132, 134, 136, 137, 139,

220, 225, 228, 264, 265, 266, 268, 269, 270, 273, 274, 279, 280, 282, 283, 284, 285, 286, 287, 298, 299, 303, 307, 379, 459.

cite loc: \underline{130}, 137, 139, 265, 266, 270, 273, 278,

279, 280, 286. cite number : 130, \underline{131}, 139, 162, 220, 266, 291,

301, 302, 304. cite parent ptr : \underline{162}, 278, 280, 283. cite ptr : \underline{130}, 132, 135, 137, 146, 228, 265, 273,

277, 278, 280, 284, 286, 287, 290, 298, 299, 328, 329, 330, 356, 358, 364, 448, 459, 460, 461, 462, 463.

cite str : \underline{279}. cite xptr : \underline{162}, 284, 286. cliché-à-trois: 456. close: 40* . close up shop: \underline{10}, 45, 46. cmd num: \underline{113}. cmd str ptr : \underline{291}, 309, 310, 317, 318, 352, 353,

354, 360, 363, 380, 439, 440, 445. colon: \underline{29}, 365, 366, 372, 377. comma: \underline{29}, 33, 121, 133, 219, 260, 267, 275,

388, 389, 390, 397, 402. command ilk : 65. command num: \underline{79}, 117, 155, 156, 239, 240,

260, 263. comma1 : \underline{345}, 390, 396. comma2 : \underline{345}, 390, 396. comment : \underline{29}, 33, 153, 167, 184, 191, 192,

193, 200, 325. commented-out code: 185, 246, 274. compare return: \underline{302}. compress bib white: \underline{253}.

concat char : \underline{29}, 219, 243, 244, 250, 260.
confusion: \underline{46}, 52, 108, 113, 117, 128* , 138, 156,

158, 166, 195, 239, 241, 259, 269, 272, 302, 310, 311, 318, 342, 374, 396, 400.

control sequence: 373.

control seq ilk : \underline{65}, 340, 372, 399, 433, 453. control seq loc: \underline{345}, 372, 373, 399, 400, 433,

434, 453, 454. conversion type: \underline{366}, 367, 371, 373, 376, 377. copy char : \underline{252}, 253, 257, 258, 259, 261. copy ptr : \underline{188}, 201. cross references: 278. : 341. crossref num: \underline{162}, 264, 278, 280, 341. cur aux file: \underline{105}, 107* , 111, 142* , 143. cur aux line: \underline{105}, 108, 111, 112, 142* . cur aux str : \underline{105}, 108, 109, 141, 142* . cur bib file: \underline{118}, 124* , 224, 229, 238, 253. cur bib str : \underline{118}, 122, 124* , 458. cur cite str : \underline{130}, 137, 281, 284, 294, 295, 298,

299, 379, 459. cur macro loc: \underline{220}, 246, 260, 263.

cur token: \underline{345}, 408, 409, 410, 411, 414, 415,

416, 418. database-file commands: 240.

: 242. : 243. : 244.

debug: \underline{4*} . debugging: 4* . decr : \underline{9}, 48* , 56, 62, 72, 103* , 141, 142* , 143, 199* , 254, 256, 258, 262, 299, 307, 310, 322, 324, 353, 362, 368, 372, 375, 386, 389, 391, 397, 399, 401, 402, 404, 405, 412, 417, 419, 420, 432, 433, 443, 445, 446, 453. decr brace level : \underline{368}, 371, 385, 452. : 340. do insert : \underline{69}, 78* , 108, 124* , 128* , 134, 137, 141,

173, 175, 177, 183, 191, 192, 195, 203, 208, 210, 217, 246, 262, 265, 268, 270, 273.

do nothing : \underline{9}, 69, 167, 184, 193, 200, 236, 267, 364, 373, 376, 377, 420, 434, 436, 467.

documentation: 1* .

dont insert : \underline{69}, 117, 136, 155, 178, 193, 200, 239, 260, 268, 271, 274, 276, 279, 372, 399, 433, 453.

double letter : \underline{345}, 404, 406, 408, 409, 410, 411,

413, 414, 418. double quote: \underline{29}, 33, 190, 192, 206, 209, 210,

219, 220, 251, 435. dum ptr : \underline{308}.

dummy loc: \underline{66}, 136, 274.
eat bib print : \underline{230}, 253.

eat bib white and eof check : \underline{230}, 237, 239, 243,

244, 245, 247, 250, 251, 255, 256, 267, 275, 276. eat bib white space: \underline{229}, 230, 253. eat bst print : \underline{154}. eat bst white and eof check : \underline{154}, 171, 172, 174,

176, 179, 181, 182, 188, 202, 204, 206, 207, 209, 213, 216.

eat bst white space: 152* , \underline{153}, 154. ecart: \underline{4*} . else: 5. empty : \underline{9}, 65, 68, 69, 162, 220, 228, 269, 280,

284, 364, 448, 460. end: 4* , 5. end of def : \underline{161}, 189, 201, 327, 464. end of group: \underline{345}, 404. end of num: \underline{188}, 195. end of string : \underline{217}, 289, 302, 330, 358, 461. end offset : \underline{303}, 306. end ptr : \underline{323}, 324, 325. end while: \underline{344}, 450. endcases: \underline{5}. endif : 4* . enough chars : \underline{419}. enough text chars : 418, \underline{419}, 420. ent chr ptr : \underline{291}, 330, 358, 461. ent str size: \underline{14*} , 17, 162, 291, 302, 341, 358. entire database inclusion: 133. : 358. $ : 341. entry cite ptr : \underline{130}, 264, 268, 269, 270, 271,

273, 274. entry exists : \underline{220}, 228, 269, 271, 273, 287. entry ints : \underline{162}, 288, 329, 356, 462. entry seen: \underline{164}, 165, 171, 212. entry strs : \underline{162}, 177, 289, 302, 330, 358, 461. entry type loc: \underline{220}, 239, 274. eof : 37* , 48* , 101* , 224. eoln: 48* , 101* . equals sign: \underline{29}, 33, 219, 232, 244, 245, 247, 276. err count : 18, \underline{19}, 20, 467. error message: \underline{18}, 19, 20, 294, 295, 467. ex buf : 134, 195, 248, 268, 271, 279, \underline{291}, 319,

320, 321, 345, 371, 372, 373, 375, 376, 377, 385, 386, 387, 388, 389, 391, 394, 395, 412, 419, 420, 424, 432, 433, 434, 452, 453, 454.

ex buf length: \underline{291}, 319, 321, 330, 365, 371, 372, 375, 383, 384, 385, 386, 387, 403, 415, 418, 424, 427, 428, 430, 431, 432, 433, 439, 441, 451, 452, 453.

ex buf ptr : 248, 271, 279, \underline{291}, 319, 320, 321, 330, 371, 372, 373, 375, 376, 377, 384, 385, 386, 387, 388, 389, 391, 403, 412, 417, 419, 420, 428, 432, 433, 452, 453.

ex buf xptr : 248, \underline{345}, 372, 373, 375, 376, 384, 388, 389, 390, 391, 392, 393, 394, 395, 412, 419, 432, 433, 434, 453, 454. ex buf yptr : \underline{345}, 419, 433, 434.

ex buf1 : \underline{134}.
ex buf2 : \underline{195}.
ex buf3 : \underline{268}.
ex buf4 : \underline{271}.
ex buf4 ptr : \underline{271}.
ex buf5 : \underline{279}.
ex buf5 ptr : \underline{279}.
ex fn loc: \underline{326}, 327, 328, 329, 330, 331, 342.
exclamation mark : \underline{29}, 361, 362.

execute fn: 297, 298, 299, \underline{326}, 327, 343, 345,

364, 422, 450. execution count : \underline{332}, 336, 342, 466. exit : \underline{6}, 9, 57, 58, 112, 117, 121, 127, \underline{133}, 140, 150, 153, 155, 170, 171, 178, 179, 181, \underline{188}, 202, 204, 206, 212, 213, 215, 216, 229, 230, 231, 232, 233, 234, \underline{237}, 250, 251, 253, \underline{254}, 302, \underline{322}, 381, 398, 402, 438, 444.

exit program: \underline{10}.

ext : \underline{61}.

extra buf : \underline{265}. f: \underline{48*} , \underline{52}, \underline{83}. false: 48* , 57, 58, 69, 84, 85, 86, 87, 88, 89, 93, 94, 95, 120, 126, 132, 141, 153, 165, 178, 228, 229, 237, 239, 250, 251, 253, 254, 260, 265, 268, 273, 276, 279, 297, 302, 371, 377, 385, 391, 392, 395, 398, 404, 406, 408, 409, 410, 411, 413, 419, 463.

fat lady: 456.

fatal message: \underline{18}, 19, 467.

fetish: 139, 227.

field : \underline{157}, 159, 160, 163, 171, 172, 173, 276,

326, 332, 341. field end : \underline{248}, 250, 252, 254, 261, 262, 265.

field end ptr : \underline{162}, 278, 286, 463.
field info: \underline{162}, 173, 225, 226, 264, 278, 280,

282, 286, 328, 463. field loc: \underline{161}, 162.

field name loc: \underline{220}, 264, 276.
field parent ptr : \underline{162}, 278, 280.
field ptr : \underline{162}, 226, 264, 278, 280, 282, 286,

328, 463. field start : \underline{248}, 262, 265.

field val loc: \underline{220}, 262, 263, 264.

field vl str : \underline{248}, 250, 252, 253, 254, 259, 260,

261, 262, 265. figure out the formatted name: 383, \underline{421}.

file area ilk : \underline{65}, 76.

file ext ilk : \underline{65}, 76. file name: \underline{59}. file name size: \underline{15*} , 37* , 59, 60, 61, 62, 101* , 104, 142* . file nm size overflow : 59, \underline{60}, 61, 62. FILENAMESIZE : 15* . find cite locs for this cite key : 271, 278, \underline{279},

280, 286. first end : \underline{345}, 396, 397, 408. first start : \underline{345}, 396, 408. first text char : \underline{23}, 28. first time entry : \underline{237}, 269. flush string : \underline{56}, 310. fn class : \underline{161}, 162, 191, 192, 210, 262. fn def loc: \underline{188}. fn hash loc: \underline{188}, 201, \underline{336}. fn info: \underline{162}, 173, 175, 177, 191, 192, 201, 203,

217, 264, 326, 327, 328, 329, 330, 331, 336, 341, 342, 356, 358, 359, 360.

fn loc: \underline{159}, \underline{160}, \underline{162}, 173, 175, 177, 178, 193, 194,

200, 203, 217, 297, 298, 299. fn type: 159, 160, \underline{162}, 173, 175, 177, 178, 183,

191, 192, 195, 203, 210, 217, 239, 262, 276, 326, 336, 340, 341, 355.

for a good time, try comment-out code: 185. for loops: 7, 70, 72. get : 37* . get aux command and process : 111, \underline{117}. get bib command or entry and process : 224, \underline{237}. get bst command and process : 152* , \underline{155}. get the top level aux file name: 13* , \underline{101*} . getc: 48* , 101* . glb str end : \underline{162}, 163, 331, 360. glb str ptr : \underline{162}, 163, 331, 360. glob chr ptr : \underline{291}, 331, 360. glob str size: \underline{14*} , 17, 162, 291, 341, 360. : 360. $ : 341. global strs : \underline{162}, 217, 331, 360. grade inflation: 332. gubed: \underline{4*} . gymnastics: 12, 144, 211, 218, 249, 343. h: \underline{69}. hack1 : 152* . hack2 : 152* . ham and eggs: 262. hash : 69. hash base: \underline{65}, 66, 68, 69, 161, 220. hash cite confusion: 137, \underline{138}, 265, 273, 280, 286. hash found : \underline{66}, 69, 71, 108, 117, 124* , 128* , 134,

136, 137, 141, 155, 170, 178, 191, 193, 195, 200, 208, 220, 239, 246, 260, 265, 268, 269, 270, 271, 273, 274, 276, 279, 372, 399, 433, 453.

hash ilk : 65, \underline{66}, 68, 71, 72.
hash is full : \underline{65}, 72.
hash loc: \underline{65}, 66, 67, 69, 77, 130, 159, 160, 161,

162, 170, 188, 220, 326, 332, 336, 345. hash max : \underline{65}, 66, 68, 161, 220.

hash next : 65, \underline{66}, 68, 69, 72.
hash pointer : \underline{65}, 66.
hash prime: \underline{15*} , 17, 69, 70.
hash ptr2 : \underline{161}, 162, 188, 220.
hash size: 14* , \underline{15*} , 17, 65, 70, 72.

hash text : 65, \underline{66}, 68, 71, 72, 76, 108, 124* , 128* , 137, 139, 141, 170, 183, 195, 208, 210, 246, 262, 263, 264, 266, 270, 278, 298, 299, 308, 312, 314, 326, 328, 340, 448, 460, 464, 466.

hash used : 65, \underline{66}, 68, 72. history : 18, \underline{19}, 20, 467. hyphen: \underline{29}, 32. i: \underline{52}, \underline{57}, \underline{63}, \underline{64}, \underline{78*} , \underline{83}. id class : \underline{30}, 33, 91. id null : \underline{90}, 91, 167, 236. id scanning confusion: \underline{166}, 167, 236. id type: 30, \underline{31}. ifdef : 4* . ilk : 65, 66, \underline{69}, 71, 72, \underline{78*} . ilk info: 65, \underline{66}, 68, 79, 80, 117, 136, 137, 155, 162, 208, 210, 239, 246, 261, 263, 265, 266, 268, 270, 273, 278, 280, 286, 340, 373, 400, 434, 454.

illegal : \underline{31}, 32.

illegal id char : \underline{31}, 33, 91.

illegl literal confusion: \underline{311}, 312, 313, 314.

impl fn loc: \underline{188}, 195.

impl fn num: 195, \underline{196}, 197.

important note: 76, 80, 335, 340, 341.

incr : \underline{9}, 18, 48* , 54, 55, 56, 57, 58, 59, 61, 62, 70, 72, 83, 84, 85, 86, 87, 88, 89, 91, 93, 94, 95, 96, 99, 100, 101* , 103* , 108, 111, 121, 124* , 127, 133, 134, 137, 140, 141, 142* , 150, 153, 163, 168, 169, 172, 173, 174, 175, 176, 177, 188, 189, 191, 192, 193, 195, 198, 199* , 201, 202, 210, 212, 216, 217, 224, 226, 228, 229, 238, 239, 243, 245, 247, 250, 252, 253, 254, 255, 256, 257, 258, 259, 261, 263, 265, 266, 267, 268, 271, 275, 276, 278, 279, 280, 284, 286, 287, 288, 289, 290, 298, 302, 307, 308, 309, 319, 320, 321, 322, 323, 324, 325, 327, 331, 341, 342, 352, 353, 354, 358, 360, 363, 371, 372, 375, 380, 382, 384, 385, 386, 389, 390, 391, 392, 393, 394, 395, 397, 398, 399, 401, 403, 404, 405, 406, 412, 413, 414, 415, 416, 417, 418, 419, 420, 428, 430, 432, 433, 434, 439, 441, 443, 445, 446, 452, 453, 458, 459, 461, 462, 463, 464, 465, 466.

init command execution: 297, 298, 299, \underline{317}.

initialize: 10, 12, \underline{13*} , 337.

innocent bystander : \underline{301}. input ln: 42, \underline{48*} , 81, 111, 150, 153, 229, 238, 253. insert fn loc: \underline{189}, 191, 192, 194, 195, 200, 201. insert it : \underline{69}. insert ptr : \underline{304}, 305. int begin: \underline{199*} . int buf : 198, \underline{199*} . int end : \underline{199*} . int ent loc: \underline{161}, 162. int ent ptr : \underline{162}, 288, 462. int entry var : 14* , \underline{157}, 159, 160, 161, 162, 163,

171, 174, 175, 288, 326, 329, 355. int global var : \underline{157}, 159, 160, 202, 203, 326,

332, 341, 355. int literal : 29, \underline{157}, 159, 160, 190, 191, 326. int ptr : 198, \underline{199*} . int tmp val : \underline{199*} . int to ASCII : 195, 198, \underline{199*} , 424. int xptr : \underline{199*} . integer : 16, 19, 34, 37* , 44, 66, 79, 92, 98* , 105, 113,

148, 162, 196, 199* , 220, 227, 248, 291, 308, 310, 312, 313, 314, 315, 332, 344, 345.

integer ilk : \underline{65}, 157, 191. invalid code: \underline{26}, 28, 32, 217. j: \underline{57}, \underline{69}. jr end : \underline{345}, 396, 411. k: \underline{67}, \underline{69}. kludge: 44, 52, 134, 195, 248, 265, 268, 271, 279. l: \underline{69}. last : \underline{42}, 48* , 81, 84, 85, 86, 87, 88, 89, 91, 93,

94, 95, 96, 121, 127, 133, 140, 150, 152* , 191, 192, 212, 224, 253.

last check for aux errors : 111, \underline{146}. last cite: \underline{139}. last end : \underline{345}, 396, 397, 402, 410, 411. last fn class : \underline{157}, 161. last ilk : \underline{65}. last lex : \underline{31}. last lit type: \underline{292}. last text char : \underline{23}, 28. last token: \underline{345}, 408, 409, 410, 411, 414, 418. LaTEX: 1* , 10, 133. lc cite ilk : \underline{65}, 134, 265, 268, 271, 279. lc cite loc: \underline{130}, 134, 136, 137, 265, 266, 268, 269,

270, 273, 278, 279, 280, 286. lc xcite loc: \underline{130}, 269, 271. left : \underline{304}, 306, 307. left brace: \underline{29}, 33, 117, 127, 140, 168, 172, 174,

176, 179, 182, 190, 195, 202, 204, 207, 209, 213, 216, 239, 243, 245, 251, 255, 256, 257, 258, 267, 371, 372, 385, 386, 388, 391, 398, 399, 401, 403, 404, 405, 412, 413, 416, 417, 419, 432, 433, 443, 446, 452, 453.

left end : 303, \underline{304}, 305, 306, 307.

left paren: \underline{29}, 33, 239, 243, 245, 267.
legal id char : \underline{31}, 33, 91.
len: \underline{57}, \underline{63}, \underline{64}, \underline{78*} , \underline{336}.

length: \underline{53}, 57, 58, 59, 61, 62, 104, 141, 271, 279, 352, 353, 354, 361, 363, 367, 378, 380, 438.

less than: \underline{302}, 305, 306, 307.

lex class : \underline{30}, 32, 48* , 85, 87, 89, 91, 93, 94, 95, 96, 121, 127, 133, 140, 191, 192, 253, 261, 322, 324, 371, 372, 375, 377, 382, 385, 387, 388, 389, 397, 399, 404, 412, 416, 418, 432, 433, 453.

lex type: 30, \underline{31}.

lit stack : \underline{291}, 292, 308, 309, 310, 353.
lit stk loc: 291, \underline{292}, 308.
lit stk ptr : \underline{291}, 308, 309, 310, 316, 317, 318,

352, 353, 354, 439. lit stk size: \underline{14*} , 292, 308. lit stk type: \underline{291}, 292, 308, 310. literal literal: 451. literal loc: \underline{162}, 191, 192. log file: 3, 10, 51, 52, 76, 80, 82, 83, \underline{105}, 107* ,

335, 340, 341, 456. long name: \underline{420}.

long token: \underline{418}.
longest pds : \underline{74}, 76, 78* , 80, 335, 336, 340, 341.
loop: 6, \underline{9}.

loop exit : \underline{6}, 48* , \underline{237}, 254, 258, 275, 322, 361,

362, 416, 417, 421. loop1 exit : \underline{6}, 383, 389.

loop2 exit : \underline{6}, \underline{383}, 397.

lower case: \underline{63}, 134, 155, 173, 175, 177, 178, 183, 193, 200, 203, 208, 217, 239, 246, 260, 265, 268, 271, 276, 279, 373, 376, 377.

macro def loc: \underline{162}, 210. macro ilk : \underline{65}, 208, 246, 260. macro loc: 220. macro name loc: \underline{162}, 208, 210, 260, 261. macro name warning : \underline{235}, 246, 260. macro warn print : \underline{235}. make string : \underline{55}, 72, 319, 331, 352, 353, 354, 363,

380, 423, 435, 439, 441, 445. mark error : \underline{18}, 96, 112, 123, 145, 150, 184,

222, 282, 294. mark fatal : \underline{18}, 45, 46. mark warning : \underline{18}, 151, 223, 283, 285, 295, 449.

max bib files : \underline{14*} , 118, 119, 124* , 243.
max cites : \underline{14*} , 17, 130, 131, 139, 220, 228.
max ent ints : \underline{14*} , 161, 288.
max ent strs : \underline{14*} , 161, 289.
max fields : \underline{14*} , 161, 226, 227.

max glb str minus 1 : \underline{15*} , 161. max glob strs : \underline{15*} , 162, 163, 217. max hash value: \underline{69}. max pop: \underline{51}, 52, 332. max print line: \underline{14*} , 17, 323, 324, 325. max strings : \underline{14*} , 15* , 17, 50, 52, 55, 220. mean while: 450. mess with entries : \underline{291}, 294, 295, 297, 298, 299,

328, 329, 330, 355, 364, 379, 425, 448. middle: \underline{304}, 306. min crossrefs : \underline{14*} , 228, 280, 284. min print line: \underline{14*} , 17, 324. minus sign: \underline{29}, 65, 94, 191, 199* . missing : \underline{162}, 226, 264, 278, 280, 283, 292,

328, 463. mooning: 12. n : 79, 334, 339. n aa: \underline{339}, 340, 373, 400. n aa upper : \underline{339}, 340, 373, 400. n add period : \underline{334}, 335, 342. n ae: \underline{339}, 340, 373, 400, 434, 454. n ae upper : \underline{339}, 340, 373, 400, 434, 454. n aux bibdata: \underline{79}, 80, 113, 117, 121. n aux bibstyle: \underline{79}, 80, 113, 117, 127. n aux citation: \underline{79}, 80, 117. n aux input : \underline{79}, 80, 117. n bib comment : \underline{79}, 80, 240. n bib preamble: \underline{79}, 80, 240, 263. n bib string : \underline{79}, 80, 240, 260, 263. n bst entry : \underline{79}, 80, 156. n bst execute: \underline{79}, 80, 156. n bst function: \underline{79}, 80, 156. n bst integers : \underline{79}, 80, 156. n bst iterate: \underline{79}, 80, 156. n bst macro: \underline{79}, 80, 156. n bst read : \underline{79}, 80, 156. n bst reverse: \underline{79}, 80, 156. n bst sort : \underline{79}, 80, 156. n bst strings : \underline{79}, 80, 156. n call type: \underline{334}, 335, 342. n change case: \underline{334}, 335, 342. n chr to int : \underline{334}, 335, 342. n cite: \underline{334}, 335, 342. n concatenate: \underline{334}, 335, 342. n duplicate: \underline{334}, 335, 342. n empty : \underline{334}, 335, 342. n equals : \underline{334}, 335, 342. n format name: \underline{334}, 335, 342. n gets : \underline{334}, 335, 342. n greater than: \underline{334}, 335, 342. n i : \underline{339}, 340, 373, 400. n if : \underline{334}, 335, 342.

n int to chr : \underline{334}, 335, 342.
n int to str : \underline{334}, 335, 342.
n j : \underline{339}, 340, 373, 400.
n l : \underline{339}, 340, 373, 400.
n l upper : \underline{339}, 340, 373, 400.
n less than: \underline{334}, 335, 342.
n minus : \underline{334}, 335, 342.
n missing : \underline{334}, 335, 342.
n newline: \underline{334}, 335, 342.
n num names : \underline{334}, 335, 342.
n o: \underline{339}, 340, 373, 400.
n o upper : \underline{339}, 340, 373, 400.
n oe: \underline{339}, 340, 373, 400, 434, 454.
n oe upper : \underline{339}, 340, 373, 400, 434, 454.
n plus : \underline{334}, 335, 342.
n pop: \underline{334}, 335, 342.
n preamble: \underline{334}, 335, 342.
n purify : \underline{334}, 335, 342.
n quote: \underline{334}, 335, 342.
n skip: \underline{334}, 335, 342.
n ss : \underline{339}, 340, 373, 400, 434, 454.
n stack : \underline{334}, 335, 342.
n substring : \underline{334}, 335, 342.
n swap: \underline{334}, 335, 342.
n text length: \underline{334}, 335, 342.
n text prefix : \underline{334}, 335, 342.
n top stack : \underline{334}, 335, 342.
n type: \underline{334}, 335, 342.
n warning : \underline{334}, 335, 342.
n while: \underline{334}, 335, 342.
n width: \underline{334}, 335, 342.
n write: \underline{334}, 335, 342.
name bf ptr : \underline{345}, 388, 391, 392, 395, 397, 398,

399, 401, 402, 415, 416, 417. name bf xptr : \underline{345}, 397, 398, 399, 401, 402,

415, 416, 417. name bf yptr : \underline{345}, 399. name buf : 44, \underline{345}, 388, 391, 395, 398, 399,

401, 415, 416, 417. name length: \underline{37*} , 59, 61, 62, 100, 107* , 108, 142* . name of file: \underline{37*} , 59, 61, 62, 98* , 99, 100, 101* ,

103* , 108, 142* . name ptr : \underline{37*} , 59, 61, 62, 99, 100, 108, 142* .

name scan for and : 384, \underline{385}, 428.

name sep char : \underline{345}, 388, 390, 393, 394, 397, 418. name tok : \underline{345}, 388, 391, 392, 395, 397, 402,

408, 415, 416. negative: \underline{94}. nested cross references: 278. new cite: \underline{266}. newline: 109, 122, 129. next cite: \underline{133}, 135. next insert : \underline{304}, 305. next token: \underline{184}, 185, 186, 187, 188. nil: 9. nm brace level : \underline{345}, 398, 399, 401, 417. no bst file: \underline{147}, 152* . no fields : \underline{162}, 463. no file path: \underline{39*} , 107* , 142* . nonexistent cross reference error : 280, \underline{282}. null code: \underline{26}. num bib files : \underline{118}, 146, 224, 458. num blt in fns : 333, \underline{334}, 336, 466. num cites : \underline{130}, 146, 226, 228, 277, 278, 280, 284,

288, 289, 290, 298, 299, 300, 459, 466. num commas : \underline{345}, 388, 390, 396. num ent ints : \underline{162}, 163, 175, 288, 329, 356, 462. num ent strs : \underline{162}, 163, 177, 289, 302, 330,

341, 358, 461. num fields : \underline{162}, 163, 171, 173, 226, 264, 266, 278,

280, 286, 328, 341, 463. num glb strs : \underline{162}, 163, 217. num names : \underline{345}, 384, 427, 428. num pre defined fields : \underline{162}, 171, 278, 341. num preamble strings : \underline{220}, 277, 430. num text chars : \underline{345}, 419, 442, 443, 446. num tokens : \underline{345}, 388, 390, 391, 392, 393, 394,

395, 396. number sign: \underline{29}, 33, 190, 191. numeric: \underline{31}, 32, 91, 93, 94, 191, 251, 432, 433. oe width: \underline{35}, 454. ok pascal i give up: \underline{365}, 371. old num cites : \underline{130}, 228, 265, 269, 270, 280,

284, 287, 459. old string : \underline{69}, 71, 72. open bibdata aux err : \underline{123}, 124* . ord : 24. other char adjacent : \underline{90}, 91, 167, 236. other lex : \underline{31}, 32. othercases: \underline{5}. others : 5. out buf : 265, \underline{291}, 322, 323, 324, 325, 426, 455. out buf length: \underline{291}, 293, 322, 323, 324, 325. out buf ptr : \underline{291}, 322, 323, 324, 325. out pool str : 51, \underline{52}. out token: 82, \underline{83}. output bbl line: \underline{322}, 324, 325, 426. overflow : \underline{45}, 47, 54, 55, 60, 72, 124* , 139, 141,

189, 201, 217, 227, 288, 289, 308, 323. overflow in arithmetic: 11* . p: \underline{69}. p ptr : \underline{59}, \underline{61}, \underline{62}. p ptr1 : \underline{49}, 58, 321, 323. p ptr2 : \underline{49}, 58, 321, 323. p str : \underline{321}, \underline{323}. parent entry: 278. partition: \underline{304}, 307.

PASCAL-H: 38.

pds : \underline{78*} , \underline{336}.

pds len: \underline{74}, 78* , 336.

pds loc: \underline{74}.

pds type: \underline{74}, 78* , 336.

period : \underline{29}, 361, 362, 363, 418.

pool file: 49, 73. pool overflow : \underline{54}. pool pointer : 49, \underline{50}, 52, 57, 59, 61, 62, 345. pool ptr : \underline{49}, 54, 55, 56, 73, 352, 353, 363, 445. pool size: \underline{14*} , 50, 54. pop lit : \underline{310}. pop lit stack : 313. pop lit stk : \underline{310}, 315, 346, 347, 348, 349, 350,

351, 355, 361, 365, 378, 380, 381, 383, 422, 423, 424, 425, 427, 429, 431, 438, 440, 442, 444, 449, 450, 451, 455. pop lit var : \underline{368}, \underline{369}, \underline{370}, \underline{385}. pop lit1 : \underline{345}, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 358, 359, 360, 361, 362, 363, 365, 367, 378, 380, 381, 382, 383, 385, 403, 407, 422, 423, 424, 425, 427, 428, 429, 431, 438, 439, 440, 441, 442, 443, 444, 446, 449, 450, 451, 452, 455.

pop lit2 : \underline{345}, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 358, 359, 360, 365, 371, 383, 384, 389, 390, 392, 422, 438, 439, 440, 441, 444, 445.

pop lit3 : \underline{345}, 383, 384, 385, 389, 390, 392,

422, 438, 439. pop the aux stack : 111, \underline{143}.

pop top and print : \underline{315}, 316, 447.
pop type: \underline{310}.
pop typ1 : \underline{345}, 346, 347, 348, 349, 350, 351,

355, 361, 365, 378, 380, 381, 383, 422, 423, 424, 425, 427, 429, 431, 438, 440, 442, 444, 449, 450, 451, 455.

pop typ2 : \underline{345}, 346, 347, 348, 349, 350, 351, 355,

356, 358, 359, 360, 365, 383, 422, 438, 440, 444. pop typ3 : \underline{345}, 383, 422, 438.

pop whole stack : \underline{316}, 318, 437.
pre def certain strings : 13* , \underline{337}.
pre def loc: 76, \underline{77}, 78* , 80, 336, 340, 341.
pre define: 76, \underline{78*} , 80, 336, 340, 341.
preamble ptr : \underline{220}, 243, 263, 277, 340, 430.
preceding white: \underline{345}, 385.
prev colon: \underline{366}, 371, 377.

print : \underline{3}, 45, 46, 59, 61, 62, 96, 97, 111, 112, 113, 114, 115, 116, 123, 128* , 136, 141, 142* , 145, 149, 150, 151, 154, 159, 167, 168, 169, 170, 178, 184, 185, 186, 187, 201, 221, 222, 223, 224, 235, 236, 264, 274, 281, 282, 283, 285, 288, 289, 294, 295, 312, 313, 346, 355, 357, 369, 378, 384, 389, 390, 392, 407, 449, 456, 467.

print : 3. print a newline: \underline{3}. print a pool str : 51, \underline{52}. print a token: 82, \underline{83}. print aux name: 108, \underline{109}, 111, 112, 141, 142* , 145. print bad input line: \underline{96}, 112, 150, 222. print bib name: \underline{122}, 123, 221, 224, 456. print bst name: 128* , \underline{129}, 149. print confusion: \underline{46}, 467. print fn class : \underline{159}, 170, 178, 355. print lit : \underline{314}, 315, 449. print ln: \underline{3}, 10, 45, 46, 59, 61, 96, 112, 135, 139,

170, 185, 222, 223, 227, 281, 282, 283, 285, 314, 315, 318, 357, 467.

print missing entry : 284, \underline{285}, 287. print newline: \underline{3}, 96, 109, 122, 129, 136, 294,

295, 314, 346. print overflow : \underline{45}. print pool str : \underline{51}, 59, 61, 62, 109, 122, 129, 136,

139, 170, 264, 274, 281, 285, 294, 295, 312, 314, 367, 369, 378, 384, 389, 390, 392, 407.

print recursion illegal : \underline{185}. print skipping whatever remains : \underline{97}, 112, 222. print stk lit : \underline{312}, 313, 314, 346, 381, 425. print token: \underline{82}, 136, 141, 155, 178, 185, 186,

208, 235, 274. print wrong stk lit : \underline{313}, 347, 348, 349, 350, 351,

355, 356, 358, 359, 360, 361, 365, 378, 383, 422, 423, 424, 427, 431, 438, 442, 444, 449, 450, 451, 455.

program conventions: 8. ptr1 : \underline{302}. ptr2 : \underline{302}. push the literal stack: 309, 352, 353, 354, 362,

380, 438, 439, 445. push lit stack : 309. push lit stk : \underline{308}, 319, 326, 327, 328, 329, 331,

346, 347, 348, 349, 350, 351, 352, 353, 354, 361, 363, 365, 378, 379, 380, 381, 382, 383, 423, 424, 425, 427, 431, 435, 438, 439, 440, 441, 442, 444, 445, 448, 451.

push lt : \underline{308}. push type: \underline{308}. put : 37* , 41. question mark : \underline{29}, 361, 362. quick sort : 300, 301, 303, \underline{304}, 307. quote next fn: \underline{161}, 189, 194, 195, 327, 464. r pop lt1 : \underline{344}, 450. r pop lt2 : \underline{344}, 450. r pop tp1 : \underline{344}, 450. r pop tp2 : \underline{344}, 450. raisin: 279. read completed : \underline{164}, 165, 224, 459, 461, 462. read performed : \underline{164}, 165, 224, 456, 459, 463. read seen: \underline{164}, 165, 179, 204, 206, 212, 213, 215. reading completed : \underline{164}, 165, 224, 456. readln: 101* . repush string : \underline{309}, 362, 380, 438. reset : 37* . return: 6, \underline{9}. return von found : \underline{398}, 399, 400. rewrite: 37* . right : \underline{304}, 305, 306, 307. right brace: \underline{29}, 33, 114, 115, 117, 121, 127, 133,

140, 167, 169, 172, 174, 176, 179, 182, 184, 188, 191, 192, 193, 200, 202, 204, 207, 209, 213, 216, 220, 243, 245, 251, 255, 256, 257, 258, 267, 361, 362, 368, 371, 372, 385, 386, 388, 391, 392, 399, 401, 403, 404, 405, 412, 417, 419, 432, 433, 442, 443, 444, 445, 446, 451, 452, 453.

right end : 303, \underline{304}, 305, 306, 307. right outer delim: \underline{220}, 243, 245, 247, 260, 267,

275. right paren: \underline{29}, 33, 220, 243, 245, 267. right str delim: \underline{220}, 251, 254, 255, 256, 257. s: \underline{52}, \underline{57}, \underline{281}, \underline{285}. s : 75, 338. s aux extension: \underline{75}, 76, 104, 107* , 108, 140, 141. s bbl extension: \underline{75}, 76, 104, 107* . s bib area: \underline{75}, 76. s bib extension: \underline{75}, 76, 122, 124* , 458. s bst area: \underline{75}, 76. s bst extension: \underline{75}, 76, 128* , 129, 458. s default : 183, \underline{338}, 340. s l : \underline{338}. s log extension: \underline{75}, 76, 104, 107* . s null : \underline{338}, 340, 351, 361, 365, 383, 423, 424,

431, 438, 442, 444, 448. s preamble: 220, 263, \underline{338}, 340, 430. s t : \underline{338}. s u: \underline{338}. sam too long file name print : \underline{99}. sam wrong file name print : \underline{100}. sam you made the file name too long : \underline{99}, 101* ,

104. sam you made the file name wrong : \underline{100}, 107* . save space: 43, 162. scan a field token and eat white: 250, \underline{251}. scan alpha: \underline{89}, 155. scan and store the field value and eat white: 243,

247, 248, 249, \underline{250}, 275. scan balanced braces : 251, \underline{254}. scan char : \underline{81}, 84, 85, 86, 87, 88, 89, 91, 92, 93,

94, 95, 121, 127, 133, 140, 153, 155, 167, 168, 169, 172, 174, 176, 187, 188, 190, 191, 192, 202, 209, 216, 236, 239, 243, 245, 247, 250, 251, 253, 255, 256, 257, 258, 267, 275, 276.

scan fn def : 181, \underline{188}, 190, 195. scan identifier : 90, \underline{91}, 167, 239, 245, 260, 276. scan integer : \underline{94}, 191. scan nonneg integer : \underline{93}, 259. scan result : \underline{90}, 91, 167, 236. scan white space: \underline{95}, 153, 229, 253. scan1 : \underline{84}, 86, 117, 192, 210, 238. scan1 white: \underline{85}, 127, 140, 267. scan2 : \underline{86}, 88, 256. scan2 white: \underline{87}, 121, 133, 184, 193, 200, 267. scan3 : \underline{88}, 255. secret agent man: 173. seen fn loc: \underline{170}. sep char : \underline{31}, 32, 388, 389, 394, 397, 402, 418,

431, 432, 433. set paths : 101* . short list : \underline{303}, 304, 305. sign length: \underline{94}. singl fn overflow : \underline{189}. singl function: \underline{188}, 189, 201. single fn space: \underline{14*} , 188, 189. single ptr : \underline{188}, 189, 201. single quote: \underline{29}, 33, 190, 193, 195. skip illegal stuff after token print : \underline{187}. skip recursive token: \underline{185}, 194, 200. skip stuff at sp brace level greater than one: 404,

\underline{405}, 413. skip token: \underline{184}, 191, 192. skip token illegal stuff after literal : \underline{187}, 191, 192. skip token print : \underline{184}, 185, 186, 187. skip token unknown function: \underline{186}, 193, 200. skp token unknown function print : \underline{186}. $ : 341. sort cite ptr : \underline{291}, 298, 299, 459. sort key num: \underline{291}, 302, 341. sorted cites : 220, \underline{290}, 291, 298, 299, 301, 303,

304, 305, 306, 307, 459. sp brace level : \underline{345}, 403, 404, 405, 406, 407, 412,

413, 443, 445, 446. sp end : \underline{345}, 352, 353, 354, 360, 362, 363, 380,

382, 403, 404, 405, 439, 441, 443, 445, 446. sp length: \underline{345}, 353, 438, 439. sp ptr : \underline{345}, 352, 353, 354, 358, 360, 362, 363, 380,

382, 403, 404, 405, 406, 408, 409, 410, 411, 412,

413, 418, 439, 441, 443, 445, 446. sp xptr1 : \underline{345}, 353, 358, 404, 412, 413, 418, 446.

sp xptr2 : \underline{345}, 413, 418.

space: \underline{26}, 31, 32, 33, 35, 96, 250, 253, 254, 257,

261, 262, 323, 324, 393, 394, 418, 420, 431, 432. space savings: 1* , 14* , 15* , 43, 162. special character: 372, 398, 399, 402, 416, 417,

419, 431, 432, 433, 442, 443, 444, 446, 451, 453. specified char adjacent : \underline{90}, 91, 167, 236. spotless : \underline{18}, 19, 20, 467. sp2 length: 345, 353. ss width: \underline{35}, 454. standard input : 2* . standard output : 2* . star : \underline{29}, 135. start name: \underline{59}, 124* , 128* , 142* . stat: \underline{4*} . stat pr : \underline{466}. stat pr ln: \underline{466}. stat pr pool str : \underline{466}. statistics: 4* , 466. stk empty : \underline{292}, 308, 310, 312, 313, 314, 315,

346, 381, 425. stk field missing : \underline{292}, 308, 312, 313, 314, 328,

381, 425. stk fn: \underline{292}, 308, 312, 313, 314, 327, 355, 422, 450. stk int : \underline{292}, 308, 312, 313, 314, 326, 329, 346,

347, 348, 349, 350, 356, 359, 378, 381, 382, 383, 422, 423, 424, 425, 427, 438, 442, 444, 450, 451.

stk lt : \underline{312}, \underline{313}, \underline{314}, \underline{315}.

stk str : \underline{292}, 308, \underline{310}, 312, 313, 314, 319, 326, 328, 331, 346, 351, 352, 353, 354, 358, 360, 361, 363, 365, 378, 379, 380, 381, 383, 423, 424, 425, 427, 431, 435, 438, 439, 440, 441, 442, 444, 445, 448, 449, 451, 455.

stk tp: \underline{312}, \underline{314}, \underline{315}.

stk tp1 : \underline{313}.
stk tp2 : \underline{313}.
stk type: 291, \underline{292}, 308, 310, 312, 313, 314,

315, 344, 345. store entry : \underline{220}, 268, 276. store field : \underline{220}, 243, 247, 250, 254, 259, 260, 276. store token: \underline{220}, 260. str delim: 248. str ent loc: \underline{161}, 162, 291, 302. str ent ptr : \underline{162}, 289, 330, 358, 461. str entry var : 14* , \underline{157}, 159, 160, 161, 162, 163, 171, 176, 177, 289, 291, 303, 326, 330, 332, 341, 355.

str eq buf : \underline{57}, 71, 141.

str eq str : \underline{58}, 346.
str found : \underline{69}, 71.
str glb ptr : \underline{162}, 163, 331, 360.

str glob loc: \underline{161}, 162. str global var : 14* , 15* , \underline{157}, 159, 160, 161, 162, 163,

216, 217, 291, 326, 331, 355. str ilk : \underline{65}, 66, 69, 71, 78* . str literal : \underline{157}, 159, 160, 181, 190, 192, 206,

210, 262, 326, 340. str lookup: 66, \underline{69}, 77, 78* , 108, 117, 124* , 128* , 134,

136, 137, 141, 155, 173, 175, 177, 178, 183, 191, 192, 193, 195, 200, 203, 208, 210, 217, 239, 246, 260, 262, 265, 268, 270, 271, 273, 274, 276, 279, 372, 399, 433, 453.

str not found : \underline{69}. str num: \underline{49}, \underline{69}, 71, 72, 465. str number : 49, \underline{50}, 52, 55, 57, 58, 59, 61, 62, 66,

69, 75, 105, 118, 125, 130, 162, 220, 279, 281, 285, 291, 321, 323, 338, 368, 369, 370, 385.

str pool : \underline{49}, 50, 51, 52, 54, 55, 57, 58, 59, 61, 62, 65, 69, 72, 73, 74, 75, 76, 105, 118, 130, 261, 271, 279, 292, 310, 317, 318, 319, 321, 323, 330, 331, 335, 338, 345, 352, 353, 354, 358, 360, 362, 363, 367, 378, 380, 382, 403, 404, 405, 406, 408, 409, 410, 411, 412, 413, 418, 439, 441, 443, 445, 446.

str ptr : \underline{49}, 52, 55, 56, 73, 291, 310, 317, 318,

465, 466. str room: \underline{54}, 72, 319, 331, 352, 353, 354, 363,

380, 423, 435. str start : \underline{49}, 50, 52, 53, 55, 56, 57, 58, 59, 61, 62,

65, 68, 73, 261, 271, 279, 321, 323, 352, 353, 354, 358, 360, 362, 363, 367, 378, 380, 382, 403, 439, 441, 443, 445, 465, 466.

string pool: 73. : 357.

entry string size: 358. global string size: 360.

string width: \underline{34}, 451, 452, 453, 454. style-file commands: 156, 164.

: 171. : 179. : 181. : 202. : 204. : 206. : 212. : 213. : 215. : 216.

sv buffer : \underline{44}, 212, 345. sv ptr1 : \underline{44}, 212. sv ptr2 : \underline{44}, 212. swap: \underline{301}, 305, 306, 307. swap1 : \underline{301}. swap2 : \underline{301}. system dependencies: 1* , 2* , 3, 5, 10, 11* , 14* , 15* , 23,

25, 26, 27, 32, 33, 35, 37* , 38, 40* , 43, 52, 76, 83, 98* , 99, 100, 101* , 102* , 103* , 107* , 162, 467, 468.

s1 : \underline{58}. s2 : \underline{58}. tab: \underline{26}, 27, 32, 33. tats: \underline{4*} . term in: \underline{2*} , 101* . term out : \underline{2*} , 3, 13* , 52, 83, 99, 100, 101* . TEX INPUT PATH : 128* . TEX INPUT PATH BIT : 101* . The TEXbook: 27. text char : \underline{23}, 24. text ilk : \underline{65}, 76, 108, 157, 192, 210, 262, 340. the int : \underline{199*} . : 46, 469* .

A cite key disappeared: 271, 272, 286. A digit disappeared: 259. Already encountered auxiliary file: 108. Already encountered implicit function: 195. Already encountered style file: 128* . An at-sign disappeared: 239. Cite hash error: 137, 138, 265, 273, 280, 286. Control-sequence hash error: 400. Duplicate sort key: 302. History is bunk: 467. Identifier scanning error: 166, 167, 236. Illegal auxiliary-file command: 113. Illegal literal type: 311, 312, 313, 314. Illegal number of comma,s: 396. Illegal string number: 52. Nonempty empty string stack: 318. Nontop top of string stack: 310. The cite list is messed up: 269. Unknown auxiliary-file command: 117. Unknown built-in function: 342. Unknown database-file command: 240, 241, 263. Unknown function class: 158, 159, 160, 326. Unknown literal type: 308, 311, 312, 313, 314. Unknown style-file command: 156. Unknown type of case conversion: 373, 374,

376, 377. tie: \underline{29}, 32, 397, 402, 412, 418, 420. title lowers : 338, \underline{366}, 367, 371, 373, 376, 377. tmp end ptr : \underline{44}, 261, 271, 279. tmp ptr : \underline{44}, 134, 212, 259, 261, 265, 268, 271,

279, 286, 324, 325, 375. to be written: \underline{345}, 404, 406, 408, 409, 410, 411. token len: \underline{81}, 89, 91, 93, 94, 117, 124* , 128* , 134,

135, 136, 137, 141, 155, 173, 175, 177, 178, 183, 191, 192, 193, 200, 203, 208, 210, 217, 239, 246, 260, 268, 270, 273, 274, 276.

token starting : \underline{345}, 388, 390, 391, 392, 393,

394, 395. token value: \underline{92}, 93, 94, 191. top lev str : \underline{105}, 108. total ex count : \underline{332}, 466. total fields : \underline{227}. tr print : 162. trace: 3, \underline{4*} . trace and stat printing : 456, \underline{457}. trace pr : \underline{3}, 134, 160, 191, 192, 193, 194, 200,

210, 262, 298, 299, 308, 326, 458, 459, 460, 461, 462, 463, 464, 465, 466.

trace pr : 3. trace pr fn class : \underline{160}, 194, 200. trace pr ln: \underline{3}, 111, 124* , 135, 136, 173, 175, 177,

180, 183, 191, 192, 195, 203, 205, 208, 210, 214, 217, 224, 239, 246, 262, 268, 276, 300, 304, 308, 326, 458, 459, 460, 461, 463, 464, 465, 466.

trace pr newline: \underline{3}, 137, 185, 194, 200, 298,

299, 458, 459, 462. trace pr pool str : \underline{51}, 124* , 195, 262, 298, 299, 308,

326, 458, 459, 460, 463, 464, 465, 466. trace pr token: \underline{82}, 134, 173, 175, 177, 180, 183,

191, 192, 193, 200, 203, 205, 208, 210, 214, 217, 239, 246, 268, 276.

true: 9, 48* , 57, 58, 66, 69, 71, 84, 85, 86, 87, 88, 89, 93, 94, 95, 118, 121, 125, 127, 130, 133, 135, 141, 153, 164, 171, 178, 212, 220, 224, 229, 239, 240, 243, 247, 250, 251, 253, 254, 260, 266, 268, 269, 270, 273, 276, 279, 291, 298, 299, 302, 366, 377, 385, 387, 388, 390, 393, 394, 398, 404, 406, 408, 409, 410, 411, 413, 419, 463.

Tuesdays: 326, 402. turn out lights: 456. type exists : \underline{220}, 239, 274. type list : \underline{220}, 228, 269, 274, 280, 284, 286,

364, 448, 460. uexit : 13* , 101* . undefined : \underline{220}, 274, 364, 448, 460. unflush string : \underline{56}, 309, 352, 353, 439, 440. unknwn function class confusion: \underline{158}, 159, 160,

326. unknwn literal confusion: 308, \underline{311}, 312, 313, 314. upper ae width: \underline{35}, 454. upper case: \underline{64}, 373, 375, 376, 377. upper oe width: \underline{35}, 454. use default : \underline{345}, 413, 418. user abuse: 99, 100, 394, 417. vgetc: 48* . von end : \underline{345}, 397, 402, 409, 410. von found : \underline{383}, 397. von name ends and last name starts stuff : 396,

397, \underline{402}. von start : \underline{345}, 396, 397, 402, 409. von token found : 397, \underline{398}, 402. warning message: \underline{18}, 19, 20, 151, 294, 295, 467. : 53, 70. white adjacent : \underline{90}, 91, 167, 236. white space: 26, 29, \underline{31}, 32, 35, 48* , 85, 87, 91, 95,

96, 116, 121, 127, 133, 140, 153, 171, 181, 184, 188, 191, 192, 193, 200, 202, 206, 216, 219, 229, 244, 247, 250, 253, 254, 255, 257, 258, 261, 322, 323, 324, 325, 365, 371, 375, 377, 381, 382, 385, 387, 388, 389, 394, 427, 428, 431, 432, 433, 453.

whole database inclusion: 133. windows: 326. wiz def ptr : \underline{162}, 163, 201, 464, 466. wiz defined : 14* , \underline{157}, 159, 160, 161, 162, 163, 178,

179, 180, 181, 182, 183, 185, 188, 195, 204, 205, 213, 214, 239, 326, 327, 464.

wiz fn loc: \underline{161}, 162, 326. wiz fn ptr : \underline{162}, 464. wiz fn space: \underline{14*} , 161, 201. wiz functions : 161, \underline{162}, 189, 191, 192, 194, 195,

200, 201, 326, 327, 464. wiz loc: \underline{162}, 181, 183, 190, 194, 200. wiz ptr : \underline{326}, 327. wizard: 1* . write: 3, 52, 83, 99, 100, 101* , 322. write ln: 3, 13* , 99, 100, 322. writeln: 101* . x add period : 342, \underline{361}. x change case: 342, \underline{365}. x chr to int : 342, \underline{378}. x cite: 342, \underline{379}. x concatenate: 342, \underline{351}. x duplicate: 342, \underline{380}. x empty : 342, \underline{381}. x equals : 342, \underline{346}. x format name: 342, \underline{383}, 421. x gets : 342, \underline{355}. x greater than: 342, \underline{347}. x int to chr : 342, \underline{423}. x int to str : 342, \underline{424}. x less than: 342, \underline{348}. x minus : 342, \underline{350}. x missing : 342, \underline{425}. x num names : 342, \underline{427}. x plus : 342, \underline{349}. x preamble: 342, \underline{430}. x purify : 342, \underline{431}. x quote: 342, \underline{435}. x substring : 342, \underline{438}. x swap: 342, \underline{440}. x text length: 342, \underline{442}. x text prefix : 342, \underline{444}. x type: 342, \underline{448}. x warning : 342, \underline{449}. x width: 342, \underline{451}. x write: 342, \underline{455}. xchr : \underline{24}, 25, 27, 28, 49, 52, 83, 96, 114, 115, 155,

167, 168, 169, 187, 192, 209, 210, 231, 232, 236, 239, 243, 247, 322, 461.

xclause: 9. xord : \underline{24}, 28, 48* , 78* , 108. Yogi: 456.

180  NAMES OF THE SECTIONS  BibTEX §469

⟨ Add cross-reference information 278 ⟩ Used in section 277. ⟨ Add extensions and open files 107* ⟩ Used in section 104. ⟨ Add or update a cross reference on cite list if necessary 265 ⟩ Used in section 264. ⟨ Add the period (it’s necessary) and push 363 ⟩ Used in section 362. ⟨ Add the period , if necessary, and push 362 ⟩ Used in section 361. ⟨ Add up the char widths in this string 452 ⟩ Used in section 451.

⟨ Assign to a str entry var 358 ⟩ Used in section 355. ⟨ Assign to a str global var 360 ⟩ Used in section 355. ⟨ Assign to an int entry var 356 ⟩ Used in section 355. ⟨ Assign to an int global var 359 ⟩ Used in section 355. ⟨ Break that line 324 ⟩ Used in section 323.

⟨ Break that unbreakable line 325 ⟩ Used in section 324. ⟨ Check and insert the quoted function 194 ⟩ Used in section 193. ⟨ Check for a database key of interest 268 ⟩ Used in section 267. ⟨ Check for a duplicate or -matching database key 269 ⟩ Used in section 268. ⟨ Check for entire database inclusion (and thus skip this cite key) 135 ⟩ Used in section 134. ⟨ Check the -command argument token 180 ⟩ Used in section 179. ⟨ Check the -command argument token 205 ⟩ Used in section 204. ⟨ Check the -command argument token 214 ⟩ Used in section 213. ⟨ Check the “constant” values for consistency 17, 303 ⟩ Used in section 13*.

⟨ Check the cite key 134 ⟩ Used in section 133. ⟨ Check the macro name 208 ⟩ Used in section 207.

⟨ Check the special character (and return) 399 ⟩ Used in section 398. ⟨ Check the wiz defined function name 183 ⟩ Used in section 182. ⟨ Cite seen, don’t add a cite key 136 ⟩ Used in section 134. ⟨ Cite unseen, add a cite key 137 ⟩ Used in section 134.

⟨ Clean up and leave 456 ⟩ Used in section 10.

⟨ Compiler directives 11* ⟩ Used in section 10. ⟨ Complain about a nested cross reference 283 ⟩ Used in section 280. ⟨ Complain about missing entries whose cite keys got overwritten 287 ⟩ Used in section 284. ⟨ Complete this function’s definition 201 ⟩ Used in section 188. ⟨ Compute the hash code h 70 ⟩ Used in section 69. ⟨ Concatenate the two strings and push 352 ⟩ Used in section 351. ⟨ Concatenate them and push when pop lit1 , pop lit2 < cmd str ptr 354 ⟩ Used in section 353. ⟨ Concatenate them and push when pop lit2 < cmd str ptr 353 ⟩ Used in section 352. ⟨ Constants in the outer block 14*, 334 ⟩ Used in section 10. ⟨ Convert a noncontrol sequence 376 ⟩ Used in section 372. ⟨ Convert a special character 372 ⟩ Used in section 371. ⟨ Convert a brace level = 0 character 377 ⟩ Used in section 371. ⟨ Convert the accented or foreign character, if necessary 373 ⟩ Used in section 372. ⟨ Convert, then remove the control sequence 375 ⟩ Used in section 373. ⟨ Copy name and count commas to determine syntax 388 ⟩ Used in section 383. ⟨ Copy the macro string to field vl str 261 ⟩ Used in section 260. ⟨ Count the text characters 443 ⟩ Used in section 442. ⟨ Declarations for executing built in functions 344 ⟩ Used in section 326. ⟨ Determine the case-conversion type 367 ⟩ Used in section 365. ⟨ Determine the number of names 428 ⟩ Used in section 427. ⟨ Determine the width of this accented or foreign character 454 ⟩ Used in section 453. ⟨ Determine the width of this special character 453 ⟩ Used in section 452. ⟨ Determine where the first name ends and von name starts and ends 397 ⟩ Used in section 396. ⟨ Do a full brace-balanced scan 257 ⟩ Used in section 254.

⟨ Do a full scan with bib brace level > 0 258 ⟩ Used in section 257.

§469 BibTEX NAMES OF THE SECTIONS 181

⟨ Do a quick brace-balanced scan 255 ⟩ Used in section 254. ⟨ Do a quick scan with bib brace level > 0 256 ⟩ Used in section 255. ⟨ Do a straight insertion sort 305 ⟩ Used in section 304. ⟨ Do the partitioning and the recursive calls 307 ⟩ Used in section 304. ⟨ Draw out the median-of-three partition element 306 ⟩ Used in section 304.

⟨ Execute a field 328 ⟩ Used in section 326. ⟨ Execute a built in function 342 ⟩ Used in section 326. ⟨ Execute a str entry var 330 ⟩ Used in section 326. ⟨ Execute a str global var 331 ⟩ Used in section 326. ⟨ Execute a wiz defined function 327 ⟩ Used in section 326. ⟨ Execute an int entry var 329 ⟩ Used in section 326.

⟨ Figure out how to output the name tokens, and do it 413 ⟩ Used in section 412. ⟨ Figure out the formatted name 403 ⟩ Used in section 421. ⟨ Figure out what this letter means 406 ⟩ Used in section 404. ⟨ Figure out what tokens we’ll output for the ‘first’ name 408 ⟩ Used in section 406. ⟨ Figure out what tokens we’ll output for the ‘jr’ name 411 ⟩ Used in section 406. ⟨ Figure out what tokens we’ll output for the ‘last’ name 410 ⟩ Used in section 406. ⟨ Figure out what tokens we’ll output for the ‘von’ name 409 ⟩ Used in section 406. ⟨ Final initialization for processing 225 ⟩ Used in section 224. ⟨ Final initialization for processing the entries 277 ⟩ Used in section 224. ⟨ Finally format this part of the name 412 ⟩ Used in section 404. ⟨ Finally output a full token 415 ⟩ Used in section 414. ⟨ Finally output a special character and exit loop 417 ⟩ Used in section 416. ⟨ Finally output an abbreviated token 416 ⟩ Used in section 414. ⟨ Finally output the inter-token string 418 ⟩ Used in section 414. ⟨ Finally output the name tokens 414 ⟩ Used in section 413. ⟨ Find the lower-case equivalent of the cite info key 271 ⟩ Used in section 269. ⟨ Find the parts of the name 396 ⟩ Used in section 383. ⟨ Form the appropriate prefix 445 ⟩ Used in section 444. ⟨ Form the appropriate substring 439 ⟩ Used in section 438. ⟨ Format this part of the name 404 ⟩ Used in section 403. ⟨ Get the next field name 276 ⟩ Used in section 275. ⟨ Get the next function of the definition 190 ⟩ Used in section 188.

⟨ Globals in the outer block 16, 19, 24, 30, 34, 37*, 42, 44, 49, 66, 75, 77, 79, 81, 90, 92, 98*, 105, 118, 125, 130, 148, 162,

164, 196, 220, 248, 291, 332, 338, 345, 366 ⟩ Used in section 10.

⟨ Handle a discretionary tie 420 ⟩ Used in section 412.

⟨ Handle this name 104 ⟩ Used in section 101*.

⟨ Handle this accented or foreign character (and return) 400 ⟩ Used in section 399.

⟨ Initialize the field info 226 ⟩ Used in section 225. ⟨ Initialize the int entry var s 288 ⟩ Used in section 277. ⟨ Initialize the sorted cites 290 ⟩ Used in section 277. ⟨ Initialize the str entry var s 289 ⟩ Used in section 277.

⟨ Initialize things for the cite list 228 ⟩ Used in section 225. ⟨ Insert a field into the hash table 173 ⟩ Used in section 172. ⟨ Insert a str entry var into the hash table 177 ⟩ Used in section 176. ⟨ Insert a str global var into the hash table 217 ⟩ Used in section 216. ⟨ Insert an int entry var into the hash table 175 ⟩ Used in section 174. ⟨ Insert an int global var into the hash table 203 ⟩ Used in section 202. ⟨ Insert pair into hash table and make p point to it 72 ⟩ Used in section 69. ⟨ Isolate the desired name 384 ⟩ Used in section 383. ⟨ Labels in the outer block 110, 147 ⟩ Used in section 10. ⟨ Local variables for initialization 23, 67 ⟩ Used in section 13*.

⟨ Make sure this entry is ok before proceeding 274 ⟩ Used in section 268. ⟨ Make sure this entry’s database key is on cite list 270 ⟩ Used in section 269.

⟨ Name-process a comma 390 ⟩ Used in section 388. ⟨ Name-process a left brace 391 ⟩ Used in section 388. ⟨ Name-process a right brace 392 ⟩ Used in section 388. ⟨ Name-process a sep char 394 ⟩ Used in section 388. ⟨ Name-process a white space 393 ⟩ Used in section 388.

⟨ Name-process some other character 395 ⟩ Used in section 388.

⟨ Open a file 124* ⟩ Used in section 121. ⟨ Open the file 128* ⟩ Used in section 127. ⟨ Open this file 142* ⟩ Used in section 141. ⟨ Perform a command 299 ⟩ Used in section 213. ⟨ Perform a command 300 ⟩ Used in section 215. ⟨ Perform an command 297 ⟩ Used in section 179. ⟨ Perform an command 298 ⟩ Used in section 204.

⟨ Perform the case conversion 371 ⟩ Used in section 365. ⟨ Perform the purification 432 ⟩ Used in section 431.

⟨ Pre-define certain strings 76, 80, 335, 340, 341 ⟩ Used in section 337.

⟨ Print all  - and  -file information 458 ⟩ Used in section 457.

⟨ Print all cite list and entry information 459 ⟩ Used in section 457. ⟨ Print entry information 460 ⟩ Used in section 459. ⟨ Print entry integers 462 ⟩ Used in section 460.

⟨ Print entry strings 461 ⟩ Used in section 460. ⟨ Print fields 463 ⟩ Used in section 460. ⟨ Print the job history 467 ⟩ Used in section 456.

⟨ Print the string pool 465 ⟩ Used in section 457.

⟨ Print the wiz defined functions 464 ⟩ Used in section 457.

⟨ Print usage statistics 466 ⟩ Used in section 457. ⟨ Procedures and functions for about everything 12 ⟩ Used in section 10. ⟨ Procedures and functions for all file I/O, error messages, and such 3, 18, 45, 46, 47, 48*, 52, 54, 60, 83, 96, 97,

99, 100, 109, 112, 113, 114, 115, 116, 122, 129, 138, 139, 145, 149, 150, 151, 154, 158, 159, 160, 166, 167, 168, 169, 170, 189, 221, 222, 223, 227, 230, 231, 232, 233, 234, 235, 236, 241, 272, 281, 282, 285, 294, 295, 296, 311, 312, 314, 322, 357, 369, 374, 457 ⟩ Used in section 12.

⟨ Procedures and functions for file-system interacting 59, 61, 62 ⟩ Used in section 12. ⟨ Procedures and functions for handling numbers, characters, and strings 55, 57, 58, 63, 64, 69, 78*, 199*, 266,

279, 301, 302, 304, 336, 337 ⟩ Used in section 12. ⟨ Procedures and functions for input scanning 84, 85, 86, 87, 88, 89, 91, 93, 94, 95, 153, 184, 185, 186, 187, 188, 229,

249, 250 ⟩ Used in section 12.

⟨ Procedures and functions for name-string processing 368, 370, 385, 398, 402, 405, 407, 419, 421 ⟩

Used in section 12.

⟨ Procedures and functions for style-file function execution 308, 310, 313, 315, 316, 317, 318, 319, 321, 323, 343 ⟩

Used in section 12.

⟨ Procedures and functions for the reading and processing of input files 101*, 121, 127, 133, 140, 143, 144, 146,

171, 178, 179, 181, 202, 204, 206, 211, 212, 213, 215, 216, 218 ⟩ Used in section 12. ⟨ Process a command 240 ⟩ Used in section 239. ⟨ Process a command 242 ⟩ Used in section 240. ⟨ Process a command 243 ⟩ Used in section 240. ⟨ Process a command 244 ⟩ Used in section 240.

⟨ Process a possible command line 103* ⟩ Used in section 101*. ⟨ Process the appropriate command 156 ⟩ Used in section 155. ⟨ Process the string if we’ve already encountered it 71 ⟩ Used in section 69. ⟨ Purify a special character 433 ⟩ Used in section 432.

⟨ Purify this accented or foreign character 434 ⟩ Used in section 433. ⟨ Push 0 if the string has a nonwhite space char, else 1 382 ⟩ Used in section 381.

⟨ Push the stack 141 ⟩ Used in section 140.

⟨ Put this cite key in its place 273 ⟩ Used in section 268. ⟨ Put this name into the hash table 108 ⟩ Used in section 104. ⟨ Read and execute the file 152* ⟩ Used in section 10.

⟨ Read the file 111 ⟩ Used in section 10. ⟨ Read the file(s) 224 ⟩ Used in section 212.

⟨ Remove leading and trailing junk, complaining if necessary 389 ⟩ Used in section 388. ⟨ Remove missing entries or those cross referenced too few times 284 ⟩ Used in section 277.

⟨ Scan a macro name 260 ⟩ Used in section 251. ⟨ Scan a number 259 ⟩ Used in section 251.

⟨ Scan a quoted function 193 ⟩ Used in section 190.

⟨ Scan a str literal 192 ⟩ Used in section 190.

⟨ Scan an already-defined function 200 ⟩ Used in section 190.

⟨ Scan an int literal 191 ⟩ Used in section 190.

⟨ Scan for and process a command or database entry 237 ⟩ Used in section 211. ⟨ Scan for and process a command 155 ⟩ Used in section 218. ⟨ Scan for and process an command 117 ⟩ Used in section 144. ⟨ Scan the appropriate number of characters 446 ⟩ Used in section 445. ⟨ Scan the entry type or scan and process the command 239 ⟩ Used in section 237. ⟨ Scan the entry’s database key 267 ⟩ Used in section 237. ⟨ Scan the entry’s list of fields 275 ⟩ Used in section 237.

⟨ Scan the list of field s 172 ⟩ Used in section 171. ⟨ Scan the list of int entry var s 174 ⟩ Used in section 171. ⟨ Scan the list of str entry var s 176 ⟩ Used in section 171.

⟨ Scan the macro definition-string 210 ⟩ Used in section 209.

⟨ Scan the macro name 207 ⟩ Used in section 206.

⟨ Scan the macro’s definition 209 ⟩ Used in section 206. ⟨ Scan the string’s definition field 247 ⟩ Used in section 244. ⟨ Scan the string’s name 245 ⟩ Used in section 244. ⟨ Scan the wiz defined function name 182 ⟩ Used in section 181. ⟨ See if we have an “and” 387 ⟩ Used in section 385.

⟨ Set initial values of key variables 20, 25, 27, 28, 32, 33, 35, 68, 73, 120, 126, 132, 163, 165, 197, 293 ⟩

Used in section 13*. ⟨ Skip over ex buf stuff at brace level > 0 386 ⟩ Used in section 385. ⟨ Skip over name buf stuff at nm brace level > 0 401 ⟩ Used in section 398.

⟨ Skip to the next database entry or command 238 ⟩ Used in section 237. ⟨ Slide this cite key down to its permanent spot 286 ⟩ Used in section 284. ⟨ Start a new function definition 195 ⟩ Used in section 190. ⟨ Store the field value for a command 263 ⟩ Used in section 262. ⟨ Store the field value for a database entry 264 ⟩ Used in section 262. ⟨ Store the field value string 262 ⟩ Used in section 250. ⟨ Store the string’s name 246 ⟩ Used in section 245. ⟨ Subtract cross-reference information 280 ⟩ Used in section 277. ⟨ Swap the two strings (they’re at the end of str pool ) 441 ⟩ Used in section 440.

⟨ The procedure initialize 13* ⟩ Used in section 10.

⟨ The scanning function compress bib white 253 ⟩ Used in section 249. ⟨ The scanning function scan a field token and eat white 251 ⟩ Used in section 249. ⟨ The scanning function scan balanced braces 254 ⟩ Used in section 249.

⟨ Types in the outer block 22, 31, 36*, 43, 50, 65, 74, 106, 119, 131, 161, 292, 333 ⟩ Used in section 10. ⟨ execute fn itself 326 ⟩ Used in section 343.

⟨ execute fn( ) 351 ⟩ Used in section 343. ⟨ execute fn( ) 349 ⟩ Used in section 343. ⟨ execute fn( ) 350 ⟩ Used in section 343. ⟨ execute fn( ) 355 ⟩ Used in section 343. ⟨ execute fn( ) 348 ⟩ Used in section 343. ⟨ execute fn( ) 346 ⟩ Used in section 343. ⟨ execute fn( ) 347 ⟩ Used in section 343. ⟨ execute fn( $ ) 361 ⟩ Used in section 343. ⟨ execute fn( $ ) 364 ⟩ Used in section 342. ⟨ execute fn( $ ) 365 ⟩ Used in section 343. ⟨ execute fn( $ ) 378 ⟩ Used in section 343. ⟨ execute fn( $) 379 ⟩ Used in section 343. ⟨ execute fn( $ ) 380 ⟩ Used in section 343. ⟨ execute fn( $) 381 ⟩ Used in section 343. ⟨ execute fn( $ ) 383 ⟩ Used in section 343. ⟨ execute fn( $) 422 ⟩ Used in section 342. ⟨ execute fn( $ ) 423 ⟩ Used in section 343. ⟨ execute fn( $ ) 424 ⟩ Used in section 343. ⟨ execute fn( $) 425 ⟩ Used in section 343. ⟨ execute fn( $) 426 ⟩ Used in section 342. ⟨ execute fn( $ ) 427 ⟩ Used in section 343. ⟨ execute fn( $) 429 ⟩ Used in section 342. ⟨ execute fn( $) 430 ⟩ Used in section 343. ⟨ execute fn( $) 431 ⟩ Used in section 343. ⟨ execute fn( $) 435 ⟩ Used in section 343. ⟨ execute fn( $) 436 ⟩ Used in section 342. ⟨ execute fn( $) 437 ⟩ Used in section 342. ⟨ execute fn( $ ) 438 ⟩ Used in section 343. ⟨ execute fn( $) 440 ⟩ Used in section 343. ⟨ execute fn( $ ) 442 ⟩ Used in section 343. ⟨ execute fn( $ ) 444 ⟩ Used in section 343. ⟨ execute fn( $) 447 ⟩ Used in section 342. ⟨ execute fn( $) 448 ⟩ Used in section 343. ⟨ execute fn( $) 449 ⟩ Used in section 343. ⟨ execute fn( $) 450 ⟩ Used in section 342. ⟨ execute fn( $) 451 ⟩ Used in section 343. ⟨ execute fn( $) 455 ⟩ Used in section 343.

The BibT_{E}X preprocessor

(Version 0.99c—February 23, 1992)

Section Page

Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1 The main program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 4 The character set . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 8 Input and output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 14 String handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 17 The hash table . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 22 Scanning an input line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 28 Getting the top-level auxiliary file name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 33 Reading the auxiliary file(s) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 37 Reading the style file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 47 Style-file commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 54 Reading the database file(s) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219 71 Executing the style file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291 97 The built-in functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332 111 Cleaning up . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 456 160 System-dependent changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 468 165 Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 469 166