TEX.CMS-CHAN - WEB change file for TeX 2.0 for VM/CMS and Pascal/VS. Copyright (C) 1984 by David Fuchs. All rights are reserved. External references: TERMATTN, ATTN202, USESTACK. Assembled text decks of these routines must be linked into module. Changes to this file since 1.0 version (at SLAC): Added increased mem size params etc from VMS-CHAN, XEDIT hook, change ".log" to ".texlog". 11 Feb 84 Fixed filemode specifier so you can "\input fn.ft.fm". 9 Mar 84 Update line number references from TeX 1.0 to TeX 1.1. 20 Mar 84 Increase |buf_size| parameter from 500 to 1024. 24 Apr 84 Add CMS hook to send string to CMS using "\write15". 24 Apr 84 Various small changes in comments in TeX. 12 Jul 84 Change |pool_name| from "TEX.POOL" to "TEX.POOL.*". 21 Aug 84 File mode "*" added to |prompt_file_name| on input. 23 Aug 84 Allow tab and formfeed characters in input. 23 Aug 84 Increase |pool_size| to 40000. 23 Aug 84 ONERROR message deleted. 23 Aug 84 DVI block size changed to 1024. 24 Aug 84 SLAC character translates (hex): 4F->4A, 6A->4F, A1->5F. 27 Sep 84 Add SLAC routines for logging use data. 27 Sep 84 Update for TeX 1.4. 24 Feb 86 Remove |ready_already| as per Klaus Thull's recommendation. 24 Feb 86 Increase |hash_size| to 3000. 26 Feb 86 Update for TeX 2.0. 10 Mar 86 Add Chris Thompson's changes for large arrays, |use_stack|, and do simple array asignments for |do_all_six|. 25 Mar 86 Add code in |close_files_and_terminate| to explicitly close all input files. Avoids Pascal/VS loop in AMPXIO. 6 May 86 Allow |mem| array to start at negative index. 8 May 86 Increase |pool_size| to 50000. 9 May 86 Move |ret_code| from |end_of_TEX:| to |final_end:| and make |history|:=|fatal_error_stop| if |bad_fmt|. 15 May 86 Remove SLAC-specific routines and character translates to conform to TeX Project (hex): 5F->A1, 4A->5F. 4 Jun 86 Change |tfm_file| reading routine to read multiple 1024-byte records. All TeX/MF data files are now RECFM F LRECL 1024. 2 Jul 86 TeX 2.0 WEB source line 34 @x limbo \def\ph{\hbox{Pascal-H}} @y \def\ph{\hbox{Pascal-H}} \def\pvs{\hbox{Pascal/VS}} @z TeX 2.0 WEB source line 60 @x limbo \pageno=3 @y \pageno=3 \let\maybe=\iffalse % to TeX only the changed sections after WEAV'ing \def\title{\TeX\ changes for VM/CMS} @z TeX 2.0 WEB source line 148 @x @d banner=='This is TeX, Version 2.0' {printed when \TeX\ starts} @y The VM/CMS port of \TeX\ is a combination of efforts of many people. \.{WEB} change files for preliminary versions of \TeX\ were brought to the \TeX\ Users Group meeting in August 1983 and given to David Fuchs, of Stanford University Computer Science Department, who combined them into a definitive version on the VM system at Stanford Linear Accelerator Center. The original change files were supplied by Roger Chaffee of SLAC (now at Metaphor), Craig Platt of the University of Manitoba, and Peter M.#Sih of IBM Palo Alto Scientific Center. Bernd Schulze of the University of Bonn contributed his experience from bringing up a preliminary \TeX\ under CMS and has since sent many further improvements including the Metafont change file used in this implementation and other CMS change files. Other CMS change files and suggestions were made by Klaus Thull. All of this work was based on preliminary work adapting \TeX\ to MVS by Eagle Berns and Susan Plass of Stanford University. Peter Sih has donated countless hours of his expertise and contributed the device support for the IBM 4250 and APA6670 (and 3800 model 3) printers. Many valuable revisions and additions to this work were made by Robert J.#Creasy. Alan Spragens at SLAC coordinated communication among the CMS sites and made some enhancements to the implementation while revising the CMS change file for \TeX\ versions 1.1 and 2.0. Significant improvements were contributed for version 2.0 by Chris Thompson of the University of Cambridge; they are described in the ``System-dependent Changes'' section. @d banner=='This is TeX, VM/CMS Version 2.0' {printed when \TeX\ starts} @d term_in==tty_in @d term_out==tty_out @d string_length==len @& gth {IBM length function} @d string_index ==ind @& ex {IBM index function} @z TeX 2.0 WEB source line 218 @x procedure initialize; {this procedure gets things started properly} @y @@/ @@/ @# procedure initialize; {this procedure gets things started properly} @z TeX 2.0 WEB source line 261 @x @d debug==@{ {change this to `$\\{debug}\equiv\null$' when debugging} @d gubed==@t@>@} {change this to `$\\{gubed}\equiv\null$' when debugging} @y @d debug==@{ {change this to `$\\{debug}\equiv\null$' when debugging} @d gubed==@t@>@} {change this to `$\\{gubed}\equiv\null$' when debugging} @z TeX 2.0 WEB source line 266 @x @d stat==@{ {change this to `$\\{stat}\equiv\null$' when gathering usage statistics} @d tats==@t@>@} {change this to `$\\{tats}\equiv\null$' when gathering usage statistics} @y @d stat== @d tats== @z TeX 2.0 WEB source line 281 @x @d init== {change this to `$\\{init}\equiv\.{@@\{}$' in the production version} @d tini== {change this to `$\\{tini}\equiv\.{@@\}}$' in the production version} @y virtex: init==@{ tini==@} initex: init== tini== @d init==@{ @d tini==@} @z TeX 2.0 WEB source line 333 @x @d othercases == others: {default for cases not listed explicitly} @y @d othercases == otherwise {default for cases not listed explicitly} @z TeX 2.0 WEB source line 345 @x @!mem_max=30000; {greatest index in \TeX's internal |mem| array; must be strictly less than |max_halfword|; must be equal to |mem_top| in \.{INITEX}, otherwise |>=mem_top|} @!mem_min=0; {smallest index in \TeX's internal |mem| array; must be |min_halfword| or more; must be equal to |mem_bot| in \.{INITEX}, otherwise |<=mem_bot|} @!buf_size=500; {maximum number of characters simultaneously present in current lines of open files and in control sequences between \.{\\csname} and \.{\\endcsname}; must not exceed |max_halfword|} @!error_line=72; {width of context lines on terminal error messages} @!half_error_line=42; {width of first lines of contexts in terminal error messages; should be between 30 and |error_line-15|} @!max_print_line=79; {width of longest text lines output; should be at least 60} @!stack_size=200; {maximum number of simultaneous input sources} @!max_in_open=6; {maximum number of input files and error insertions that can be going on simultaneously} @!font_max=75; {maximum internal font number; must not exceed |max_quarterword| and must be at most |font_base+256|} @!font_mem_size=20000; {number of words of |font_info| for all fonts} @!param_size=60; {maximum number of simultaneous macro parameters} @!nest_size=40; {maximum number of semantic levels simultaneously active} @!max_strings=3000; {maximum number of strings; must not exceed |max_halfword|} @!string_vacancies=8000; {the minimum number of characters that should be available for the user's control sequences and font names, after \TeX's own error messages are stored} @!pool_size=32000; {maximum number of characters in strings, including all error messages and help texts, and the names of all fonts and control sequences; must exceed |string_vacancies| by the total length of \TeX's own strings, which is currently about 23000} @!save_size=600; {space for saving values outside of current group; must be at most |max_halfword|} @!trie_size=8000; {space for hyphenation patterns; should be larger for \.{INITEX} than it is in production versions of \TeX} @!dvi_buf_size=800; {size of the output buffer; must be a multiple of 8} @!file_name_size=40; {file names shouldn't be longer than this} @!pool_name='TeXformats:TEX.POOL '; {string of length |file_name_size|; tells where the string pool appears} @.TeXformats@> @y @!mem_max=32766; {greatest index in \TeX's internal |mem| array; must be strictly less than |max_halfword|; must be equal to |mem_top| in \.{INITEX}, otherwise |>=mem_top|} @!mem_min=-32768; {smallest index in \TeX's internal |mem| array; must be |min_halfword| or more; must be equal to |mem_bot| in \.{INITEX}, otherwise |<=mem_bot|} @!buf_size=1024; {maximum number of characters simultaneously present in current lines of open files and in control sequences between \.{\\csname} and \.{\\endcsname}; must not exceed |max_halfword|} @!error_line=79; {width of context lines on terminal error messages} @!half_error_line=50; {width of first lines of contexts in terminal error messages; should be between 30 and |error_line-15|} @!max_print_line=79; {width of longest text lines output; should be at least 60} @!stack_size=200; {maximum number of simultaneous input sources} @!max_in_open=6; {maximum number of input files and error insertions that can be going on simultaneously} @!font_max=100; {maximum internal font number; must not exceed |max_quarterword| and must be at most |font_base+256|} @!font_mem_size=30000; {number of words of |font_info| for all fonts} @!param_size=60; {maximum number of simultaneous macro parameters} @!nest_size=40; {maximum number of semantic levels simultaneously active} @!max_strings=5000; {maximum number of strings; must not exceed |max_halfword|} @!string_vacancies=26000; {the minimum number of characters that should be available for the user's control sequences and font names, after \TeX's own error messages are stored} @!pool_size=50000; {maximum number of characters in strings, including all error messages and help texts, and the names of all fonts and control sequences; must exceed |string_vacancies| by the total length of \TeX's own strings, which is currently about 23000} @!save_size=600; {space for saving values outside of current group; must be at most |max_halfword|} @!trie_size=8000; {space for hyphenation patterns; should be larger for \.{INITEX} than it is in production versions of \TeX} @!dvi_buf_size=2048; {size of the output buffer; must be a multiple of 8} @!len_byte_block=1024; {must be half of |dvi_buf_size|} @!len_word_block=256; {format file buffer length} @!file_name_size=40; {file names shouldn't be longer than this} @!pool_name='TEX.POOl.* '; {string of length |file_name_size|; tells where the string pool appears} @.TeXformats@> @z TeX 2.0 WEB source line 395 @x @d mem_bot=0 {smallest index in the |mem| array dumped by \.{INITEX}; must not be less than |mem_min|} @d mem_top==30000 {largest index in the |mem| array dumped by \.{INITEX}; must be substantially larger than |mem_bot| and not greater than |mem_max|} @d font_base=0 {smallest internal font number; must not be less than |min_quarterword|} @d hash_size=2100 {maximum number of control sequences; it should be at most about |(mem_max-mem_min)/10|, but 2100 is already quite generous} @d hash_prime=1777 {a prime number equal to about 85\% of |hash_size|} @d hyph_size=307 {another prime; the number of \.{\\hyphenation} exceptions} @^system dependencies@> @y @d mem_bot==-32768 {smallest index in the |mem| array dumped by \.{INITEX}; must not be less than |mem_min|} @d mem_top==32766 {largest index in the |mem| array dumped by \.{INITEX}; must be substantially larger than |mem_bot| and not greater than |mem_max|} @d font_base=0 {smallest internal font number; must not be less than |min_quarterword|} @d hash_size=3000 {maximum number of control sequences; it should be at most about |(mem_max-mem_min)/10|, but 2100 is already quite generous} @d hash_prime=2549 {a prime number equal to about 85\% of |hash_size|} @d hyph_size=307 {another prime; the number of \.{\\hyphenation} exceptions} @^system dependencies@> @z TeX 2.0 WEB source line 503 @x @!ASCII_code=0..127; {seven-bit numbers} @y @!ASCII_code=packed 0..127; {seven-bit numbers} @z TeX 2.0 WEB source line 533 @x @d last_text_char=127 {ordinal number of the largest element of |text_char|} @y @d last_text_char=255 {ordinal number of the largest element of |text_char|} @z TeX 2.0 WEB source line 689 @x [2] System-dependent character set changes: @^character set dependencies@> @^system dependencies@> @= for i:=1 to @'37 do xchr[i]:=' '; @y For \pvs\ we allow |form_feed| and |tab| characters in input. @^character set dependencies@> @^system dependencies@> @d form_feed=@'14 @d tab=@'05 @= for i:=1 to @'37 do xchr[i]:=' '; xchr[form_feed]:=chr(form_feed); xchr[tab]:=chr(tab); @z TeX 2.0 WEB source line 737 @x for us to specify simple operations on word files before they are defined. @= @!eight_bits=0..255; {unsigned one-byte quantity} @!alpha_file=packed file of text_char; {files that contain textual data} @!byte_file=packed file of eight_bits; {files that contain binary data} @y for us to specify simple operations on word files before they are defined. @d alpha_file==@= TEXT@> @d ccat==@=||@> @= @!eight_bits=packed 0..255; {unsigned one-byte quantity} @z TeX 2.0 WEB source line 790 @x begin reset(f,name_of_file,'/O'); a_open_in:=reset_OK(f); @y begin okstatus; reset(f,'NAME='ccat@, trim(str(name_of_file))); a_open_in:=status; @z TeX 2.0 WEB source line 795 @x begin rewrite(f,name_of_file,'/O'); a_open_out:=rewrite_OK(f); @y begin okstatus; rewrite(f,'NAME='ccat@, trim(str(name_of_file))); a_open_out:=status; @z TeX 2.0 WEB source line 800 @x begin reset(f,name_of_file,'/O'); b_open_in:=reset_OK(f); @y begin okstatus; reset(f,'NAME='ccat@, trim(str(name_of_file) ccat'.*')); b_open_in:=status; @z TeX 2.0 WEB source line 805 @x begin rewrite(f,name_of_file,'/O'); b_open_out:=rewrite_OK(f); @y begin okstatus; rewrite(f,'NAME='ccat@, trim(str(name_of_file))); b_open_out:=status; @z TeX 2.0 WEB source line 810 @x begin reset(f,name_of_file,'/O'); w_open_in:=reset_OK(f); @y begin okstatus; reset(f,'NAME='ccat@, trim(str(name_of_file) ccat'.*')); w_open_in:=status; @z TeX 2.0 WEB source line 815 @x begin rewrite(f,name_of_file,'/O'); w_open_out:=rewrite_OK(f); @y begin okstatus; rewrite(f,'NAME='ccat@, trim(str(name_of_file))); w_open_out:=status; @z TeX 2.0 WEB source line 855 @x @= @!buffer:array[0..buf_size] of ASCII_code; {lines of characters being read} @y @d LA_buffer== @!buffer:array[0..buf_size] of ASCII_code; {lines of characters being read} @= @z TeX 2.0 WEB source line 901 @x @p function input_ln(var f:alpha_file;@!bypass_eoln:boolean):boolean; {inputs the next line or returns |false|} var last_nonblank:0..buf_size; {|last| with trailing blanks removed} begin if bypass_eoln then if not eof(f) then get(f); {input the first character of the line into |f^|} last:=first; {cf.\ Matthew 19\thinspace:\thinspace30} if eof(f) then input_ln:=false else begin last_nonblank:=first; while not eoln(f) do begin if last>=max_buf_stack then begin max_buf_stack:=last+1; if max_buf_stack=buf_size then overflow("buffer size",buf_size); @:TeX capacity exceeded buffer size}{\quad buffer size@> end; buffer[last]:=xord[f^]; get(f); incr(last); if buffer[last-1]<>" " then last_nonblank:=last; end; last:=last_nonblank; input_ln:=true; end; end; @y @p function input_ln(var f:alpha_file;@!bypass_eoln:boolean):boolean; {inputs the next line or returns |false|} var last_nonblank:0..buf_size; {|last| with trailing blanks removed} begin if bypass_eoln then if not eof(f) then get(f); {input the first character of the line into |f^|} last:=first; {cf.\ Matthew 19\thinspace:\thinspace30} if eof(f) then input_ln:=false else begin last_nonblank:=first; while not eoln(f) do begin if last>=max_buf_stack then begin max_buf_stack:=last+1; if max_buf_stack=buf_size then overflow("buffer size",buf_size); @:TeX capacity exceeded buffer size}{\quad buffer size@> end; buffer[last]:=xord[f@@]; get(f); incr(last); {@@ is \pvs\ pointer notation} if buffer[last-1]<>" " then last_nonblank:=last; end; last:=last_nonblank; input_ln:=true; end; end; @z TeX 2.0 WEB source line 933 @x @ Here is how to open the terminal files in \ph. The `\.{/I}' switch suppresses the first |get|. @^system dependencies@> @d t_open_in==reset(term_in,'TTY:','/O/I') {open the terminal for text input} @d t_open_out==rewrite(term_out,'TTY:','/O') {open the terminal for text output} @y @ Here is how to open the terminal files in \pvs. There is no need to do a |reset| or |rewrite| or suppress the first |get| as with \ph. @d t_open_in==@= TERMIN@>(term_in) {open the terminal for text input} @d t_open_out==@= TERMOUT@>(term_out); {open the terminal for text output} @z TeX 2.0 WEB source line 949 @x some instruction to the operating system. The following macros show how these operations can be specified in \ph: @^system dependencies@> @d update_terminal == break(term_out) {empty the terminal output buffer} @d clear_terminal == break_in(term_in,true) {clear the terminal input buffer} @d wake_up_terminal == do_nothing {cancel the user's cancellation of output} @y some instructions to the operating system. The following macros were used to specify these operations in \ph\ but have been made into ``no-ops'' for \pvs. @d update_terminal == do_nothing @d clear_terminal == do_nothing @d wake_up_terminal == do_nothing @z TeX 2.0 WEB source line 1011 @x @p function init_terminal:boolean; {gets the terminal input started} label exit; begin t_open_in; loop@+begin wake_up_terminal; write(term_out,'**'); update_terminal; @y @p function init_terminal:boolean; {gets the terminal input started} label exit; var i,j,k: integer; l: string(256); begin t_open_in; l:=parms; if l<>'' then begin i:=@=LENGTH@>(l); j:=min(i,buf_size-first); {this much will fit} if j>0 then for k:=0 to j-1 do buffer[first+k]:=xord[l[k+1]]; last:=first+j; max_buf_stack:=max(max_buf_stack,last); loc:=first; init_terminal:=true; return end; loop@+begin wake_up_terminal; write_ln(term_out,'**'); update_terminal; @z TeX 2.0 WEB source line 1072 @x @ @= @!str_pool:packed array[pool_pointer] of ASCII_code; {the characters} @!str_start : array[str_number] of pool_pointer; {the starting pointers} @y @ @d LA_string== @!str_pool:packed array[pool_pointer] of ASCII_code; {the characters} @!str_start : array[str_number] of pool_pointer; {the starting pointers} @= @z The following change is to use \write15 to send stuff to CMS TeX 2.0 WEB source line 1373 @x @ To end a line of text output, we call |print_ln|. @= procedure print_ln; {prints an end-of-line} begin case selector of term_and_log: begin wterm_cr; wlog_cr; term_offset:=0; file_offset:=0; end; log_only: begin wlog_cr; file_offset:=0; end; term_only: begin wterm_cr; term_offset:=0; end; no_print,pseudo,new_string: do_nothing; othercases write_ln(write_file[selector]) endcases;@/ end; {|tally| is not affected} @y @ To end a line of text output, we call |print_ln|. In CMS \TeX\ we also use |print_ln| to send a message to the operating system using the \.{\\write15} stream. @= procedure print_ln; {prints an end-of-line} var i:integer; begin case selector of term_and_log: begin wterm_cr; wlog_cr; term_offset:=0; file_offset:=0; end; log_only: begin wlog_cr; file_offset:=0; end; term_only: begin wterm_cr; term_offset:=0; end; no_print,pseudo,new_string: do_nothing; 15: begin cms(trim(str(cms_buf)), irc); {send \.{\\write15} to CMS} for i:=1 to cms_ptr do cms_buf[i]:=' '; cms_ptr:=1; end; othercases write_ln(write_file[selector]) endcases;@/ end; {|tally| is not affected} @z The following change is to use \write15 to send stuff to CMS TeX 2.0 WEB source line 1394 @x @= procedure print_char(@!s:ASCII_code); {prints a single character} label exit; begin if @ then if selector= procedure print_char(@!s:ASCII_code); {prints a single character} label exit; begin if @ then if selector There is a secret `\.D' option available when the debugging routines have not been commented out. @^debugging@> @= case c of "0","1","2","3","4","5","6","7","8","9": if deletions_allowed then @; @t\4\4@>@;@+@!debug "D": begin debug_help; goto continue;@+end;@+gubed@/ "E": if base_ptr>0 then begin print_nl("You want to edit file "); @.You want to edit file x@> print(input_stack[base_ptr].name_field); print(" at line "); print_int(line); interaction:=scroll_mode; jump_out; end; "H": @; "I":@; "Q","R","S":@; "X":begin interaction:=scroll_mode; jump_out; end; othercases do_nothing endcases;@/ @ @y wizardry, so the standard implementation simply types out what file should be edited and the relevant line number. The CMS implementation uses an external assembly routine |attn202| to invoke XEDIT with ``:|line|'' in the program stack. @^system dependencies@> There is a secret `\.D' option available when the debugging routines have not been commented out. @^debugging@> @= case c of "0","1","2","3","4","5","6","7","8","9": if deletions_allowed then @; @t\4\4@>@;@+@!debug "D": begin debug_help; goto continue;@+end;@+gubed@/ "E": if base_ptr>0 then begin print_nl("You want to edit file "); @.You want to edit file x@> print(input_stack[base_ptr].name_field); print(" at line "); print_int(line); inp_line:='XEDIT '; s1:=selector; tally:=0; selector:=pseudo; print(input_stack[base_ptr].name_field); for s2:=0 to tally-1 do inp_line[s2+7]:=xchr[trick_buf[s2]]; s2:=string_index(inp_line,'.'); if s2>0 then inp_line[s2]:=' '; s2:=string_index(inp_line,'.'); if s2>0 then inp_line[s2]:=' '; attn202('FIFO ',inp_line); tally:=0; inp_line:=' '; print_int(line); inp_line[1]:=':'; for s2:=0 to tally-1 do inp_line[s2+2]:=xchr[trick_buf[s2]]; attn202('FIFO ',inp_line); ret_code(12); selector:=s1; interaction:=scroll_mode; jump_out; end; "H": @; "I":@; "Q","R","S":@; "X":begin interaction:=scroll_mode; jump_out; end; othercases do_nothing endcases;@/ @ @z TeX 2.0 WEB source line 2030 @x interrupt:=0; OK_to_interrupt:=true; @y interrupt:=0; OK_to_interrupt:=true; term_attn(interrupt); @z TeX 2.0 WEB source line 2277 @x @!glue_ratio=real; {one-word representation of a glue expansion factor} @y @!glue_ratio=shortreal; {are there any other reals in the program?} @z TeX 2.0 WEB source line 2330 @x @d min_quarterword=0 {smallest allowable value in a |quarterword|} @d max_quarterword=255 {largest allowable value in a |quarterword|} @d min_halfword==0 {smallest allowable value in a |halfword|} @d max_halfword==65535 {largest allowable value in a |halfword|} @y @d min_quarterword=0 {smallest allowable value in a |quarterword|} @d max_quarterword=255 {largest allowable value in a |quarterword|} @d min_halfword==-32768 {smallest allowable value in a |halfword|} @d max_halfword==32767 {largest allowable value in a |halfword|} @z TeX 2.0 WEB source line 2363 @x @d qi(#)==#+min_quarterword {to put an |eight_bits| item into a quarterword} @d qo(#)==#-min_quarterword {to take an |eight_bits| item out of a quarterword} @d hi(#)==#+min_halfword {to put a sixteen-bit item into a halfword} @d ho(#)==#-min_halfword {to take a sixteen-bit item from a halfword} @y @d qi(#)==# {to put an |eight_bits| item into a quarterword} @d qo(#)==# {to take an |eight_bits| item out of a quarterword} @d hi(#)==#+min_halfword {to put a sixteen-bit item into a halfword} @d ho(#)==#-min_halfword {to take a sixteen-bit item from a halfword} @z TeX 2.0 WEB source line 2378 @x @!quarterword = min_quarterword..max_quarterword; {1/4 of a word} @!halfword=min_halfword..max_halfword; {1/2 of a word} @!two_choices = 1..2; {used when there are two variants in a record} @!four_choices = 1..4; {used when there are four variants in a record} @y @!quarterword = packed min_quarterword..max_quarterword; {1/4 of a word} @!halfword=packed min_halfword..max_halfword; {1/2 of a word} @!two_choices=packed 1..2; {used when there are two variants in a record} @!four_choices=packed 1..4; {when there are four variants in a record} @z TeX 2.0 WEB source line 2401 @x @!word_file = file of memory_word; @y @!word_block = packed array [0..len_word_block-1] of memory_word; @!word_file = packed file of word_block; @!byte_block = packed array [0..len_byte_block-1] of quarterword; @!byte_file = packed file of byte_block; @z TeX 2.0 WEB source line 2466 @x deallocating them after their use. @= @!mem : array[mem_min..mem_max] of memory_word; {the big dynamic storage area} @y deallocating them after their use. For \pvs\ we have declared the big |mem| array in the ``large array variables'' module. It is defined here in terms of a macro expanded near the end of the program. All such ``large array'' macros begin with ``|LA_|.'' @d LA_mem== @!mem : array[mem_min..mem_max] of memory_word; {the big dynamic storage area} @= @z TeX 2.0 WEB source line 3268 @x been included. (You may want to decrease the size of |mem| while you @^debugging@> are debugging.) @= @!debug @!free: packed array [mem_min..mem_max] of boolean; {free cells} @t\hskip1em@>@!was_free: packed array [mem_min..mem_max] of boolean; {previously free cells} @t\hskip1em@>@!was_mem_end,@!was_lo_max,@!was_hi_min: pointer; @y been included. (You may want to decrease the size of |mem| while you @^debugging@> are debugging.) @d LA_mem_debug== @!free: packed array [mem_min..mem_max] of boolean; {free cells} @!was_free: packed array [mem_min..mem_max] of boolean; {previously free cells} @= @!debug @!was_mem_end,@!was_lo_max,@!was_hi_min: pointer; @z TeX 2.0 WEB source line 3653 @x if abs(mem[p+glue_offset].int)<@'4000000 then print("?.?") @y if false then print("?.?") {no need to check value in 370 architecture} @z TeX 2.0 WEB source line 4218 @x @= @!nest:array[0..nest_size] of list_state_record; @y @d LA_nest== @!nest:array[0..nest_size] of list_state_record; @= @z TeX 2.0 WEB source line 5085 @x is needed. The program here simply specifies July 4, 1776, at noon; but users probably want a better approximation to the truth. @p procedure fix_date_and_time; begin time:=12*60; {minutes since midnight} day:=4; {fourth day of the month} month:=7; {seventh month of the year} year:=1776; {Anno Domini} end; @y is needed. The standard program here simply specified July 4, 1776, at noon; but we want a better approximation to the truth. @p procedure fix_date_and_time; var date,tod:alfa; hour, minute:integer; begin datetime(date,tod); readstr(str(date),month:3,day:3,year); year:=year+1900;{Bug next century} readstr(str(tod),hour:3,minute); time:=hour*60+minute; end; @z TeX 2.0 WEB source line 5289 @x called |xeq_level|. @= @!eqtb:array[active_base..eqtb_size] of memory_word; @!xeq_level:array[int_base..eqtb_size] of quarterword; @y called |xeq_level|. @d LA_eqtb== @!eqtb:array[active_base..eqtb_size] of memory_word; @!xeq_level:array[int_base..eqtb_size] of quarterword; @z TeX 2.0 WEB source line 5336 @x @d hash_is_full == (hash_used=hash_base) {test if all positions are occupied} @d font_id_text(#) == text(font_id_base+#) {a frozen font identifier's name} @= @!hash: array[hash_base..undefined_control_sequence-1] of two_halves; {the hash table} @y @d hash_is_full == (hash_used=hash_base) {test if all positions are occupied} @d font_id_text(#) == text(font_id_base+#) {a frozen font identifier's name} @# @d LA_hash== @!hash: array[hash_base..undefined_control_sequence-1] of two_halves; {the hash table} @= @z TeX 2.0 WEB source line 5721 @x @ @= @!save_stack : array[0..save_size] of memory_word; @y @ @d LA_save_stack== @!save_stack : array[0..save_size] of memory_word; @= @z TeX 2.0 WEB source line 6277 @x @ @= @!input_stack : array[0..stack_size] of in_state_record; @y @ @d LA_input_stack== @!input_stack : array[0..stack_size] of in_state_record; @= @z TeX 2.0 WEB source line 6543 @x rate from the others. @= @!param_stack:array [0..param_size] of pointer; {token list pointers for parameters} @y rate from the others. @d LA_param_stack== @!param_stack:array [0..param_size] of pointer; {token list pointers for parameters} @= @z TeX 2.0 WEB source line 9736 @x @d TEX_area=="TeXinputs:" @.TeXinputs@> @d TEX_font_area=="TeXfonts:" @.TeXfonts@> @y @d TEX_area==".*" @.TeXinputs@> @d TEX_font_area=="" @.TeXfonts@> @z TeX 2.0 WEB source line 9751 @x @p function more_name(@!c:ASCII_code):boolean; begin if c=" " then more_name:=false else begin if (c=">")or(c=":") then begin area_delimiter:=pool_ptr; ext_delimiter:=0; end else if (c=".")and(ext_delimiter=0) then ext_delimiter:=pool_ptr; str_room(1); append_char(c); {contribute |c| to the current string} more_name:=true; end; end; @y @p function more_name(@!c:ASCII_code):boolean; var ret:boolean; begin if c=" " then ret:=false else begin ret:=true; if (c=".")then if ext_delimiter=0 then ext_delimiter:=pool_ptr else if area_delimiter=0 then area_delimiter:=pool_ptr else ret:=false; if ret then begin {contribute |c| to the current string} str_room(1); append_char(c); end; end; more_name:=ret; end; @z TeX 2.0 WEB source line 9769 @x if area_delimiter=0 then cur_area:="" else begin cur_area:=str_ptr; incr(str_ptr); str_start[str_ptr]:=area_delimiter+1; end; if ext_delimiter=0 then begin cur_ext:=""; cur_name:=make_string; end else begin cur_name:=str_ptr; incr(str_ptr); str_start[str_ptr]:=ext_delimiter; cur_ext:=make_string; end; end; @y if ext_delimiter=0 then begin cur_area:=""; cur_ext:=""; cur_name:=make_string; end else begin cur_name:=str_ptr; incr(str_ptr); str_start[str_ptr]:=ext_delimiter; if area_delimiter=0 then begin cur_area:=""; cur_ext:=make_string; end else begin cur_ext:=str_ptr; incr(str_ptr); str_start[str_ptr]:=area_delimiter; cur_area:=make_string; end; end; end; @z TeX 2.0 WEB source line 9788 @x begin print(a); print(n); print(e); @y begin print(n); print(e); print(a); @z TeX 2.0 WEB source line 9800 @x @p procedure pack_file_name(@!n,@!a,@!e:str_number); @y @p procedure pack_file_name(@!a,@!e,@!n:str_number); @z TeX 2.0 WEB source line 9818 @x @d format_default_length=20 {length of the |TEX_format_default| string} @d format_area_length=11 {length of its area part} @y @d format_default_length=9 {length of the |TEX_format_default| string} @d format_area_length=0 {length of its area part} @z TeX 2.0 WEB source line 9826 @x TEX_format_default:='TeXformats:plain.fmt'; @y TEX_format_default:='plain.fmt'; @z TeX 2.0 WEB source line 9998 @x clear_terminal; prompt_input(": "); @; if cur_ext="" then cur_ext:=e; pack_cur_name; @y clear_terminal; prompt_input(": "); @; if cur_ext="" then cur_ext:=e; if (s="input file name") and (cur_area="") then cur_area:=TEX_area; pack_cur_name; @z TeX 2.0 WEB source line 10034 @x @p procedure open_log_file; var old_setting:0..max_selector; {previous |selector| setting} @!k:0..buf_size; {index into |months| and |buffer|} @!l:0..buf_size; {end of first input line} @!months:packed array [1..36] of char; {abbreviations of month names} begin old_setting:=selector; if job_name=0 then job_name:="texput"; @.texput@> pack_job_name(".log"); while not a_open_out(log_file) do @; log_name:=a_make_name_string(log_file); selector:=log_only; @y @p procedure open_log_file; var old_setting:0..max_selector; {previous |selector| setting} @!k:0..buf_size; {index into |months| and |buffer|} @!l:0..buf_size; {end of first input line} @!months:packed array [1..36] of char; {abbreviations of month names} begin old_setting:=selector; if job_name=0 then job_name:="texput"; @.texput@> pack_job_name(".texlog"); while not a_open_out(log_file) do @; log_name:=a_make_name_string(log_file); selector:=log_only; @z TeX 2.0 WEB source line 10089 @x @p procedure start_input; {\TeX\ will \.{\\input} something} label done; begin scan_file_name; {set |cur_name| to desired file name} if cur_ext="" then cur_ext:=".tex"; pack_cur_name; loop@+ begin begin_file_reading; {set up |cur_file| and new level of input} if a_open_in(cur_file) then goto done; if cur_area="" then begin pack_file_name(cur_name,TEX_area,cur_ext); if a_open_in(cur_file) then goto done; end; end_file_reading; {remove the level that didn't work} prompt_file_name("input file name",".tex"); end; done: name:=a_make_name_string(cur_file); if job_name=0 then begin job_name:=cur_name; open_log_file; @y @p procedure start_input; {\TeX\ will \.{\\input} something} label done; begin scan_file_name; {set |cur_name| to desired file name} if cur_ext="" then cur_ext:=".tex"; if cur_area="" then cur_area:=TEX_area; pack_cur_name; loop@+ begin begin_file_reading; {set up |cur_file| and new level of input} if a_open_in(cur_file) then goto done; end_file_reading; {remove the level that didn't work} prompt_file_name("input file name",".tex"); end; done: name:=a_make_name_string(cur_file); if job_name=0 then begin job_name:=cur_name; open_log_file; @z |flush_string| removed--spoils XEDIT invocation TeX 2.0 WEB source line 10110 @x print_char("("); print(name); update_terminal; state:=new_line; if name=str_ptr-1 then {we can conserve string pool space now} begin flush_string; name:=cur_name; end; @; end; @y print_char("("); print(name); update_terminal; state:=new_line; @; end; @z TeX 2.0 WEB source line 10399 @x @ Here now is the (rather formidable) array of font arrays. @= @!font_info:array[0..font_mem_size] of memory_word; {the big collection of font data} @!fmem_ptr:0..font_mem_size; {first unused word of |font_info|} @!font_ptr:internal_font_number; {largest internal font number in use} @!font_check:array[internal_font_number] of four_quarters; {check sum} @!font_size:array[internal_font_number] of scaled; {``at'' size} @!font_dsize:array[internal_font_number] of scaled; {``design'' size} @!font_params:array[internal_font_number] of halfword; {how many font parameters are present} @!font_name:array[internal_font_number] of str_number; {name of the font} @!font_area:array[internal_font_number] of str_number; {area of the font} @!font_bc:array[internal_font_number] of eight_bits; {beginning (smallest) character code} @!font_ec:array[internal_font_number] of eight_bits; {ending (largest) character code} @!font_glue:array[internal_font_number] of pointer; {glue specification for interword space, |null| if not allocated} @!font_used:array[internal_font_number] of boolean; {has a character from this font actually appeared in the output?} @!hyphen_char:array[internal_font_number] of integer; {current \.{\\hyphenchar} values} @!skew_char:array[internal_font_number] of integer; {current \.{\\skewchar} values} @y @ Here now is the (rather formidable) array of font arrays. @d LA_font1== @!font_info:array[0..font_mem_size] of memory_word; {the big collection of font data} @!font_check:array[internal_font_number] of four_quarters; {check sum} @!font_size:array[internal_font_number] of scaled; {``at'' size} @!font_dsize:array[internal_font_number] of scaled; {``design'' size} @!font_params:array[internal_font_number] of halfword; {how many font parameters are present} @!font_name:array[internal_font_number] of str_number; {name of the font} @!font_area:array[internal_font_number] of str_number; {area of the font} @!font_bc:array[internal_font_number] of eight_bits; {beginning (smallest) character code} @!font_ec:array[internal_font_number] of eight_bits; {ending (largest) character code} @!font_glue:array[internal_font_number] of pointer; {glue specification for interword space, |null| if not allocated} @!font_used:array[internal_font_number] of boolean; {has a character from this font actually appeared in the output?} @!hyphen_char:array[internal_font_number] of integer; {current \.{\\hyphenchar} values} @!skew_char:array[internal_font_number] of integer; {current \.{\\skewchar} values} @= @!fmem_ptr:0..font_mem_size; {first unused word of |font_info|} @!font_ptr:internal_font_number; {largest internal font number in use} @z TeX 2.0 WEB source line 10435 @x @= @y @d LA_font2== @z TeX 2.0 WEB source line 10639 @x @ @= @y @ @= tfm_count:=0; @z TeX 2.0 WEB source line 10654 @x @d fget==get(tfm_file) @d fbyte==tfm_file^ @y @ In CMS we know that \.{TFM} files have a logical record length of 1024 bytes, so we do one |get(tfm_file)| per CMS record. Then, since |tfm_file| is a |byte_file| which is a |file of byte_block| which are arrays of 1024 bytes, we refer to each byte in the record while it is in the file buffer, avoiding the need to |get(tfm_file)| for each byte. Note that |fget| procedure is defined at the end of the program. @d fbyte==tfm_file@@[tfm_count] {@@ is \pvs\ pointer notation} @z TeX 2.0 WEB source line 11527 @x @ Some systems may find it more efficient to make |dvi_buf| a |packed| array, since output of four bytes at once may be facilitated. @^system dependencies@> @y @ We play a trick with variant records so that we can fill up the |dvi_buf| array byte by byte, but write it out in one swell foop. @^system dependencies@> @d dvi_buf==d_buffer.b {buffer for \.{DVI} output} @z TeX 2.0 WEB source line 11531 @x @!dvi_buf:array[dvi_index] of eight_bits; {buffer for \.{DVI} output} @y @!d_buffer: packed record case boolean of false:(b:packed array [dvi_index] of eight_bits); true: (l:byte_block; r:byte_block); end; @z TeX 2.0 WEB source line 11547 @x @ The actual output of |dvi_buf[a..b]| to |dvi_file| is performed by calling |write_dvi(a,b)|. For best results, this procedure should be optimized to run as fast as possible on each particular system, since it is part of \TeX's inner loop. It is safe to assume that |a| and |b+1| will both be multiples of 4 when |write_dvi(a,b)| is called; therefore it is possible on many machines to use efficient methods to pack four bytes per word and to output an array of words with one system call. @^system dependencies@> @^inner loop@> @^defecation@> @p procedure write_dvi(@!a,@!b:dvi_index); var k:dvi_index; begin for k:=a to b do write(dvi_file,dvi_buf[k]); end; @y @ The actual output of |dvi_buf[a..b]| to |dvi_file| is performed by calling |write| on the other variant of the |dvi_buf| record. Thus, we had better be sure things line up properly. many machines to use efficient methods to pack four bytes per word and to output an array of words with one system call. @^system dependencies@> @^inner loop@> @^defecation@> @= if dvi_buf_size<>2*len_byte_block then bad:=223; @z TeX 2.0 WEB source line 11572 @x begin write_dvi(0,half_buf-1); dvi_limit:=half_buf; @y begin write(dvi_file,d_buffer.l); dvi_limit:=half_buf; @z TeX 2.0 WEB source line 11575 @x else begin write_dvi(half_buf,dvi_buf_size-1); dvi_limit:=dvi_buf_size; @y else begin write(dvi_file,d_buffer.r); dvi_limit:=dvi_buf_size; @z TeX 2.0 WEB source line 11584 @x if dvi_limit=half_buf then write_dvi(half_buf,dvi_buf_size-1); if dvi_ptr>0 then write_dvi(0,dvi_ptr-1) @y if dvi_limit=half_buf then write(dvi_file,d_buffer.r); for k:=dvi_ptr to dvi_buf_size do dvi_buf[k]:=223; {bug is |k| ok?} if dvi_ptr>0 then write(dvi_file,d_buffer.l); if dvi_ptr>half_buf then write(dvi_file,d_buffer.r); @z TeX 2.0 WEB source line 15720 @x @d delta_node=2 {|type| field in a delta node} @y @d delta_node=2 {|type| field in a delta node} @= @!delta_array=array[1..6] of scaled; @z TeX 2.0 WEB source line 15735 @x @d do_all_six(#)==#(1);#(2);#(3);#(4);#(5);#(6) @= @!active_width:array[1..6] of scaled; {distance from first active node to#|cur_p|} @!cur_active_width:array[1..6] of scaled; {distance from current active node} @!background:array[1..6] of scaled; {length of an ``empty'' line} @!break_width:array[1..6] of scaled; {length being computed after current break} @y In standard \TeX\ the |do_all_six| macro is sometimes used just to copy one of these arrays to another. In this version, that uses \pvs, these have been converted to simple array assignments. This not only produces faster code, it decreases the size of the generated procedure: which is important, for |try_break| is very nearly too large for \pvs. @d do_all_six(#)==#(1);#(2);#(3);#(4);#(5);#(6) @= @!active_width:delta_array; {distance from first active node to#|cur_p|} @!cur_active_width:delta_array; {distance from current active node} @!background:delta_array; {length of an ``empty'' line} @!break_width:delta_array; {length being computed after current break} @z TeX 2.0 WEB source line 15874 @x @@; @y @@; procedure print_new_break; begin @ end; procedure print_feasible_break; begin @; end; @z TeX 2.0 WEB source line 15877 @x do_all_six(copy_to_cur_active); @y cur_active_width:=active_width; {\pvs\ for |do_all_six(copy_to_cur_active)|} @z TeX 2.0 WEB source line 16020 @x begin no_break_yet:=false; do_all_six(set_break_width_to_background); @y begin no_break_yet:=false; break_width:=background; {\pvs\ for |do_all_six(set_break_width_to_background)|} @z TeX 2.0 WEB source line 16122 @x begin do_all_six(store_break_width); @y begin active_width:=break_width; {\pvs\ for |do_all_six(store_break_width)|} @z TeX 2.0 WEB source line 16158 @x @; @y print_new_break; @z TeX 2.0 WEB source line 16343 @x @; @y print_feasible_break; @z TeX 2.0 WEB source line 16448 @x do_all_six(copy_to_cur_active); @y cur_active_width:=active_width; {\pvs\ for |do_all_six(copy_to_cur_active)|} @z TeX 2.0 WEB source line 16523 @x do_all_six(store_background);@/ @y active_width:=background; {\pvs\ for |do_all_six(store_background)|} @z TeX 2.0 WEB source line 17394 @x @!trie_pointer=0..trie_size; {an index into |trie|} @y @!trie_pointer=packed 0..trie_size; {an index into |trie|} @z TeX 2.0 WEB source line 17398 @x @d trie_op(#)==trie[#].b0 {program for hyphenation at this trie location} @= @y @d trie_op(#)==trie[#].b0 {program for hyphenation at this trie location} @# @d LA_trie== @z TeX 2.0 WEB source line 17457 @x @!hyph_pointer=0..hyph_size; {an index into the ordered hash table} @ @= @!hyph_word:array[hyph_pointer] of str_number; {exception words} @!hyph_list:array[hyph_pointer] of pointer; {list of hyphen positions} @y @!hyph_pointer=packed 0..hyph_size; {an index into the ordered hash table} @ @d LA_hyph== @!hyph_word:array[hyph_pointer] of str_number; {exception words} @!hyph_list:array[hyph_pointer] of pointer; {list of hyphen positions} @= @z TeX 2.0 WEB source line 17665 @x @d trie_op_hash_size=quarterword_diff+quarterword_diff {double} @= @!init@! trie_op_hash:array[0..trie_op_hash_size] of quarterword; {trie op codes for triples} tini@;@/ @t\hskip1em@>@!trie_op_ptr:quarterword; {highest |trie_op| assigned} @y @d trie_op_hash_size=quarterword_diff+quarterword_diff {double} @# @d LA_trie_init1== @! trie_op_hash:array[0..trie_op_hash_size] of quarterword; {trie op codes for triples} @= @!trie_op_ptr:quarterword; {highest |trie_op| assigned} @z TeX 2.0 WEB source line 17717 @x @d trie_root==trie_l[0] {root of the linked trie} @= @!init @!trie_c:packed array[trie_pointer] of ASCII_code; {characters to match} @t\hskip1em@>@!trie_o:packed array[trie_pointer] of quarterword; {operations to perform} @t\hskip1em@>@!trie_l:packed array[trie_pointer] of trie_pointer; {left subtrie links} @t\hskip1em@>@!trie_r:packed array[trie_pointer] of trie_pointer; {right subtrie links} @t\hskip1em@>@!trie_ptr:trie_pointer; {the number of nodes in the trie} @y @d trie_root==trie_l[0] {root of the linked trie} @# @d LA_trie_init2== @!trie_c:packed array[trie_pointer] of ASCII_code; {characters to match} @t\hskip1em@>@!trie_o:packed array[trie_pointer] of quarterword; {operations to perform} @t\hskip1em@>@!trie_l:packed array[trie_pointer] of trie_pointer; {left subtrie links} @t\hskip1em@>@!trie_r:packed array[trie_pointer] of trie_pointer; {right subtrie links} @= @!init @!trie_ptr:trie_pointer; {the number of nodes in the trie} @z TeX 2.0 WEB source line 17734 @x initialized to zero. @= @!init @!trie_hash:packed array[trie_pointer] of trie_pointer; tini {to identify equivalent subtries} @y initialized to zero. @d LA_trie_init3== @!trie_hash:packed array[trie_pointer] of trie_pointer; {to identify equivalent subtries} @z TeX 2.0 WEB source line 17809 @x @d trie_back(#)==trie[#].lh {backward links in |trie| holes} @= @!init@!trie_taken:packed array[trie_pointer] of boolean; {does a family start here?} @t\hskip1em@>@!trie_min:trie_pointer; @y @d trie_back(#)==trie[#].lh {backward links in |trie| holes} @# @d LA_trie_init4== @!trie_taken:packed array[trie_pointer] of boolean; {does a family start here?} @= @!init @!trie_min:trie_pointer; @z TeX 2.0 WEB source line 22573 @x if cur_ext="" then cur_ext:=".tex"; @y if cur_ext="" then cur_ext:=".tex"; if cur_area="" then cur_area:=TEX_area; @z TeX 2.0 WEB source line 22865 @x bad_fmt: wake_up_terminal; wterm_ln('(Fatal format file error; I''m stymied)'); @.Fatal format file error@> load_fmt_file:=false; exit:end; @y bad_fmt: wake_up_terminal; wterm_ln('(Fatal format file error; I''m stymied)'); @.Fatal format file error@> history:=fatal_error_stop; load_fmt_file:=false; exit:end; @z TeX 2.0 WEB source line 22885 @x @d dump_wd(#)==begin fmt_file^:=#; put(fmt_file);@+end @d dump_int(#)==begin fmt_file^.int:=#; put(fmt_file);@+end @d dump_hh(#)==begin fmt_file^.hh:=#; put(fmt_file);@+end @d dump_qqqq(#)==begin fmt_file^.qqqq:=#; put(fmt_file);@+end @= @y @d fmt_word==fmt_file@@[fmt_count] @d dump_wd(#)==begin fmt_word:=#; put_fmt;@+end @d dump_int(#)==begin fmt_word.int:=#; put_fmt;@+end @d dump_hh(#)==begin fmt_word.hh:=#; put_fmt;@+end @d dump_qqqq(#)==begin fmt_word.qqqq:=#; put_fmt;@+end @= @!fmt_count:integer; @z TeX 2.0 WEB source line 22897 @x @d undump_wd(#)==begin get(fmt_file); #:=fmt_file^;@+end @d undump_int(#)==begin get(fmt_file); #:=fmt_file^.int;@+end @d undump_hh(#)==begin get(fmt_file); #:=fmt_file^.hh;@+end @d undump_qqqq(#)==begin get(fmt_file); #:=fmt_file^.qqqq;@+end @y @d undump_wd(#)==begin get_fmt; #:=fmt_word;@+end @d undump_int(#)==begin get_fmt; #:=fmt_word.int;@+end @d undump_hh(#)==begin get_fmt; #:=fmt_word.hh;@+end @d undump_qqqq(#)==begin get_fmt; #:=fmt_word.qqqq;@+end @z TeX 2.0 WEB source line 22912 @x @= @y @= fmt_count:=0; @z; TeX 2.0 WEB source line 22927 @x x:=fmt_file^.int; @y fmt_count:=0; x:=fmt_word.int; @z TeX 2.0 WEB source line 23224 @x dump_int(interaction); dump_int(format_ident); dump_int(69069); @y dump_int(interaction); dump_int(format_ident); dump_int(69069); while fmt_count<>0 do dump_int(0); {flush out the buffer} @z TeX 2.0 WEB source line 23309 @x The initial test involving |ready_already| should be deleted if the \PASCAL\ runtime system is smart enough to detect such a ``mistake.'' @^system dependencies@> @p begin @!{|start_here|} history:=fatal_error_stop; {in case we quit during initialization} t_open_out; {open the terminal for output} if ready_already=314159 then goto start_of_TEX; @y The initial test involving |ready_already| has been deleted here since the CMS storage management is not smart enough to clean up properly. We also declare the procedure |use_stack| which is explained in its definition. @^system dependencies@> @p @ @; @# begin @!{|start_here|} use_stack; history:=fatal_error_stop; {in case we quit during initialization} t_open_out; {open the terminal for output} @z TeX 2.0 WEB source line 23319 @x begin wterm_ln('Ouch---my internal constants have been clobbered!', '---case ',bad:1); @y begin wterm_ln('Ouch---my internal constants have been clobbered!', '---case ',bad:1); ret_code(100+bad); @z TeX 2.0 WEB source line 23328 @x ready_already:=314159; start_of_TEX: @; @; init_str_ptr:=str_ptr; init_pool_ptr:=pool_ptr;@/ history:=spotless; {ready to go!} main_control; {come to life} final_cleanup; {prepare for death} end_of_TEX: close_files_and_terminate; final_end: ready_already:=0; @y do_nothing; {remove |ready_already:=314159;|} start_of_TEX: @; @; init_str_ptr:=str_ptr; init_pool_ptr:=pool_ptr;@/ history:=spotless; {ready to go!} main_control; {come to life} final_cleanup; {prepare for death} end_of_TEX: close_files_and_terminate; final_end: ret_code(history*4); interrupt:=-1; term_attn(interrupt); @z TeX 2.0 WEB source line 23348 @x but that can't cause infinite recursion. @= procedure close_files_and_terminate; var k:integer; {all-purpose index} begin @; @!stat if tracing_stats>0 then @;@;@+tats@/ wake_up_terminal; @; if job_name>0 then begin wlog_cr; a_close(log_file); selector:=selector-2; @y but that can't cause infinite recursion. For \pvs\ we explicitly close all text input files, which standard \TeX\ leaves open, because \pvs\ sometimes(!) cannot manage to close them after a |jump_out| from an inner-level input file containing a \TeX\ error. It is (currently) okay to close files that are not open in \pvs. @= procedure close_files_and_terminate; var k:integer; {all-purpose index} begin @; @!stat if tracing_stats>0 then @;@;@+tats@/ wake_up_terminal; @; if job_name>0 then begin wlog_cr; a_close(log_file); for k:=1 to max_in_open do a_close(input_file[k]); {close input files} selector:=selector-2; @z The following change is to use \write15 to send stuff to CMS TeX 2.0 WEB source line 23619 @x @ @= for k:=0 to 17 do write_open[k]:=false; @y @ @= for k:=0 to 17 do write_open[k]:=false; write_open[15]:=true; {hack open \.{\\write15} stream for sending messages to CMS} cms_ptr:=1; {initialize |cms_buf| pointer and array} for k:=1 to buf_size do cms_buf[k]:=' '; @z TeX 2.0 WEB source line 23949 @x This section should be replaced, if necessary, by changes to the program that are necessary to make \TeX\ 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 published program. More extensive changes, which introduce new sections, can be inserted here; then only the index itself will get a new section number. @^system dependencies@> @y The following sections, as recommended, contain the changes necessary to make \TeX\ work under \pvs\ and CMS. @ The following two sections of code and comment are from Chris Thompson of Cambridge University Computing Service: One of the unfortunate features of the \pvs\ compiler (and, indeed, of all known \PASCAL\ compilers for the IBM/370 architecture) is that variables in a stack frame are allocated strictly in the order they were declared. If the stack frame is more than 4096 bytes long, access to the later variables is less efficient, as \pvs\ must generate code to add a suitable multiple of 4096 to the base register for the stack frame. If many different multiples of 4096 are involved, the situation is correspondingly worse. Unfortunately, this effect is particularly acute for programs like \TeX. The order of the global variable declarations in the program generated by \.{TANGLE} is the order they actually occur in the source of \TeX. This order is oriented towards a structured exposition of the program. In particular, arrays (some of them rather large) and simple variables are mixed up; thus some of the most heavily used global variables in \TeX\ not only are not assigned addresses in the first 4096 bytes of the global stack frame, but even occur in many different 4096-byte sections of that frame, causing \pvs\ to have to assign many registers to point at them. There are many possible ways in which this situation could be improved. In this version of \TeX\ the declarations of the largest arrays have been removed from the module ``Global variables'' and added to a new one called ``Large array variables'' which is inserted at the end of the declarations. The object is to make the space allocated to the variables left in the first module no more than 4096 bytes. Many of the smaller arrays have been left in the first module; after all, they too can gain from being directly addressable. As the individual sections of ``Global variables'' often contain declarations of both simple and array variables, the latter have been converted to \.{TANGLE} macros which are expanded here, rather than building up ``Large array variables'' on the way. This would also enable us to change the order of these arrays on the global stack frame if desired. @= LA_buffer @; LA_string @; LA_mem @; debug LA_mem_debug gubed @; LA_nest @; LA_eqtb @; LA_hash @; LA_save_stack @; LA_input_stack @; LA_param_stack @; LA_font1 @; LA_font2 @; LA_trie @; LA_hyph @; init LA_trie_init1 @; LA_trie_init2 @; LA_trie_init3 @; LA_trie_init4 tini @ Another unfortunate feature of the \pvs\ compiler (this time unique to it) is the way it manages the \PASCAL\ stack. Rather than allocating the whole stack area at once, it uses \.{GETMAIN} system calls to obtain chunks of store for it on demand. If stack overflow is detected on a routine call (i.e., the current chunk is not big enough; which, in particular, always happens when the main program is called from the runtime system) then a new chunk is made current. This is taken from a chain of spare chunks if any of them is big enough; if not, a new chunk is obtained, of size $$\lceil\max(\hbox{new stack frame}, d)\rceil\quad\hbox{Kbytes}$$ where $d$ is specified by a runtime option, defaulting to 12\thinspace Kbytes. A special dummy procedure is placed between the caller and callee. When the callee returns, this procedure switches back to the old chunk, placing the new one on the spare list. Now, consider the case of \TeX. Most of the stack frames are not much larger than the \pvs\ minimum of 144 bytes, because they do not contain arrays; on the other hand, the global stack frame is enormous. The chunk obtained by \pvs\ for the main program will have between 0#and 1\thinspace Kbytes left after the global stack frame itself---and exactly how much will be quite impossible to keep control of as \TeX\ is altered. This is not enough for very many nested routine calls, and \TeX\ will soon use it up and obtain a new chunk of 12\thinspace Kbytes; this will suffice for nearly all \TeX\ applications (and if it didn't, we could change the runtime option). Some routines will have their stack frames very near the end of the first chunk. On every routine call they make, a switch will have to be made to the second chunk, and on each return to them a switch back again. Although this part of the \pvs\ runtime system is written in assembler, this is still a heavy overhead. If the routine involved is one that calls many other routines (the worst case may be |main_control|) then this will observably degrade the whole performance of \TeX. Experiments have shown variations due to this cause in the CPU time used by \TeX\ of 10\% in normal applications, and more than that in special cases. The possible solutions here range from altering the algorithm in \pvs\ to use a chunk size of $$\lceil\hbox{new stack frame} + d\rceil\quad\hbox{Kbytes}$$ (which would work quite well for \TeX) to arranging to always specify a runtime system \.{STACK=d} option comfortably larger than the global stack frame (but then one could hardly hope ever to get another chunk if the first one {\sl did} run out). The solution adopted in this version of \TeX\ is to use an assembler routine |use_stack| which arranges that its caller's stack frame will subsequently be judged by \pvs\ to be as high as possible in the current chunk---to do this it has to know more than is good for it about the internals of \pvs, of course! Ideally, this routine would be used as follows. The main program would consist of a call of |use_stack|, followed by a call of \\{do\_everything\_else}; then only one call-return pair gets the overhead. This is awkward for \TeX, though, because of the labels in the main program, especially |end_of_TEX|. Almost as good is to insert a call of |use_stack| near the beginning of the existing main program, and this is what we do here. It works because the main program doesn't actually call many other routines, and has no loops---we can hope it will stay that way! @= procedure use_stack; external; @ Extra type needed for CMS message @= @!cms_buf_type=packed array[1..buf_size] of char; @ Here are extra global variables for VM/CMS routines @= @!inp_line:string(255); @!cms_buf:cms_buf_type; @!cms_ptr:1..buf_size; @!irc:integer; @!tfm_count:integer; @!status: boolean; {did the last |reset| or |rewrite| succeed?} @ @= procedure term_attn(var interrupt: integer); fortran; procedure cms(const s:string; var rc:integer); external; procedure attn202(const lifofifo:alfa; const cmd:string); external; procedure okstatus; begin status:=true; end; @/@\@=%INCLUDE ONERROR;@>@\ @# procedure onerror; begin if @= FERROR @> in [41,48] then begin status:=false; @= FACTION@>:=[@=XDECERR@>]; end; if @= FERROR@>=30 then interrupt:=1; end; procedure fget; begin {no check done for eof} incr(tfm_count); if tfm_count=len_byte_block then begin get(tfm_file); tfm_count:=0; end; end; procedure put_fmt; begin incr(fmt_count); if fmt_count=len_word_block then begin put(fmt_file); fmt_count:=0; end; end; procedure get_fmt; begin incr(fmt_count); if fmt_count=len_word_block then begin get(fmt_file); fmt_count:=0; end; end; @z