@x \def\title{WEAVE} \def\contentspagenumber{15} % should be odd @y \def\title{MWEAVE} \def\contentspagenumber{1} % should be odd @z @x \pageno=\contentspagenumber \advance\pageno by 1 @y \pageno=\contentspagenumber \advance\pageno by 1 \let\maybe=\iffalse \def\title{WEAVE changes for Vax/VMS} @z @x @d banner=='This is WEAVE, Version 2.8' @y For the VAX/VMS version of \.{MWEAVE}, we add a second decimal point and number to the main version number, so we can differentiate between changes to the standard \.{WEAVE}\ and changes local to the VAX/VMS version of \.{MWEAVE}. @d banner=='This is MWEAVE, VAX/VMS Version 2.8.0' @z @x and |change_file|, and the \TeX\ output goes to file |tex_file|. @y and |change_file|, and the \TeX\ output goes to file |tex_file|. VMS requires us to mention |input| and |output| in the program header, too. They are used for terminal input and output. @z @x program WEAVE(@!web_file,@!change_file,@!tex_file); @y program WEAVE(@!input,@!output,@!web_file,@!change_file,@!tex_file); @z @x begin @@/ @y begin @@/ @@/ @z @x @= @{@&$C-,A+,D-@} {no range check, catch arithmetic overflow, no debug overhead} @!debug @{@&$C+,D+@}@+ gubed {but turn everything on when debugging} @y On Vax/VMS, things are a bit different. @= @=[check(none)]@> {no debug overhead, but...} debug @=[check(all)]@> gubed {turn everything on when debugging} @z @x @d othercases == others: {default for cases not listed explicitly} @y @d othercases == otherwise {Vax/VMS default for cases not listed explicitly} @z @x @!max_refs=20000; {number of cross references; must be less than 65536} @!max_toks=20000; {number of symbols in \PASCAL\ texts being parsed; @y @!max_refs=30000; {number of cross references; must be less than 65536} @!max_toks=30000; {number of symbols in \PASCAL\ texts being parsed; @z @x @!text_file=packed file of text_char; @y @!text_file=text; @z @x @d print_ln(#)==write_ln(term_out,#) {`|print|' and then start new line} @d new_line==write_ln(term_out) {start new line} @y @d print_ln(#)==write_ln(term_out,#,chr(13),chr(10)) {`|print|' and then start new line} @d new_line==write_ln(term_out,chr(13),chr(10)) {start new line} @z @x rewrite(term_out,'TTY:'); {send |term_out| output to the terminal} @y @= open@>(term_out,'SYS$OUTPUT',@=carriage_control:=none@>); rewrite(term_out); @z @x @d update_terminal == break(term_out) {empty the terminal output buffer} @y @d update_terminal == write_ln(term_out) {empty the terminal output buffer} @z @x @ The following code opens |tex_file|. Since this file was listed in the program header, we assume that the \PASCAL\ runtime system has checked that a suitable external file name has been given. @^system dependencies@> @= rewrite(tex_file); @y @ The following code opens |tex_file|. Actually, on Vax/VMS this task is put off until later. @^system dependencies@> @z @x @ Input goes into an array called |buffer|. @=@!buffer: array[0..long_buf_size] of ASCII_code; @y @ Input goes into an array called |buffer|. Actually, it is first read into |temp_buffer|. @=@!buffer: array[0..long_buf_size] of ASCII_code; @!temp_buffer: varying [buf_size] of char; @z @x @p function input_ln(var f:text_file):boolean; {inputs a line or returns |false|} var final_limit:0..buf_size; {|limit| without trailing blanks} begin limit:=0; final_limit:=0; if eof(f) then input_ln:=false else begin while not eoln(f) do begin buffer[limit]:=xord[f^]; get(f); incr(limit); if buffer[limit-1]<>" " then final_limit:=limit; if limit=buf_size then begin while not eoln(f) do get(f); decr(limit); {keep |buffer[buf_size]| empty} print_nl('! Input line too long'); loc:=0; error; @.Input line too long@> end; end; read_ln(f); limit:=final_limit; input_ln:=true; end; end; @y On Vax/VMS we first read a line into |temp_buffer|, since that's faster. @p function input_ln(var f:text_file):boolean; {inputs a line or returns |false|} var i,@!l:0..buf_size; begin limit:=0; if eof(f) then input_ln:=false else begin read(f,temp_buffer); l:=temp_buffer.@=length@>; for i:=1 to l do begin buffer[i-1]:=xord[temp_buffer[i]]; if buffer[i-1]<>" " then limit:=i; end; if not eoln(f) then begin print_nl('! Input line too long'); error; @.Input line too long@> end else read_ln(f); input_ln:=true; end; end; @z @x @d do_like=9 {\&{do}, \&{of}, \&{then}} @y @d do_like=9 {\&{do}, \&{then}} @z @x @d for_like=12 {\&{for}, \&{while}, \&{with}} @y @d for_like=12 {\&{for}, \&{if}, \&{while}, \&{with}} @z @x @d goto_like=13 {\&{goto}, \&{packed}} @y @d goto_like=13 {\&{implementation}, \&{definition}, \&{packed}} @z @x @d if_like=14 {\&{if}} @y @d if_like=14 {not used for \.{MWEB} --- see |for_like| } @z @x @d proc_like=17 {\&{function}, \&{procedure}, \&{program}} @y @d proc_like=17 {\&{procedure}, \&{module}} @z @x @d to_like=20 {\&{downto}, \&{to}} @d until_like=21 {\&{until}} @y @d to_like=20 {\&{to}} @d until_like=21 {\&{until}, \&{end}} @z @x @d loop_like=23 {\&{loop}, \&{xclause}} @y @d loop_like=23 {\&{loop} } @z @x @d char_like=24 {\&{and}, \&{or}, \&{not}, \&{in}} @y @d elsif_like=24 {\&{elsif} } @d of_like=25 {\&{of} } @d char_like=26 {\&{and}, \&{or}, \&{not}, \&{in}} @z @x We have to get \PASCAL's reserved words into the hash table, and the @y We have to get Modula-2's reserved words into the hash table, and the @z @x @d sid9(#)==buffer[9]:=#;cur_name:=id_lookup @d sid8(#)==buffer[8]:=#;sid9 @d sid7(#)==buffer[7]:=#;sid8 @d sid6(#)==buffer[6]:=#;sid7 @d sid5(#)==buffer[5]:=#;sid6 @d sid4(#)==buffer[4]:=#;sid5 @d sid3(#)==buffer[3]:=#;sid4 @d sid2(#)==buffer[2]:=#;sid3 @d sid1(#)==buffer[1]:=#;sid2 @d id2==id_first:=8; sid8 @d id3==id_first:=7; sid7 @d id4==id_first:=6; sid6 @d id5==id_first:=5; sid5 @d id6==id_first:=4; sid4 @d id7==id_first:=3; sid3 @d id8==id_first:=2; sid2 @d id9==id_first:=1; sid1 @y @d sid14(#)==buffer[14]:=#;cur_name:=id_lookup @d sid13(#)==buffer[13]:=#;sid14 @d sid12(#)==buffer[12]:=#;sid13 @d sid11(#)==buffer[11]:=#;sid12 @d sid10(#)==buffer[10]:=#;sid11 @d sid9(#)==buffer[9]:=#;sid10 @d sid8(#)==buffer[8]:=#;sid9 @d sid7(#)==buffer[7]:=#;sid8 @d sid6(#)==buffer[6]:=#;sid7 @d sid5(#)==buffer[5]:=#;sid6 @d sid4(#)==buffer[4]:=#;sid5 @d sid3(#)==buffer[3]:=#;sid4 @d sid2(#)==buffer[2]:=#;sid3 @d sid1(#)==buffer[1]:=#;sid2 @d id2==id_first:=13; sid13 @d id3==id_first:=12; sid12 @d id4==id_first:=11; sid11 @d id5==id_first:=10; sid10 @d id6==id_first:=9; sid9 @d id7==id_first:=8; sid8 @d id8==id_first:=7; sid7 @d id9==id_first:=6; sid6 @d id10==id_first:=5; sid5 @d id11==id_first:=4; sid4 @d id12==id_first:=3; sid3 @d id13==id_first:=2; sid2 @d id14==id_first:=1; sid1 @z @x id_loc:=10;@/ @y id_loc:=15;@/ @z @x id5("b")("e")("g")("i")("n")(begin_like);@/ @y id5("b")("e")("g")("i")("n")(begin_like);@/ id2("b")("y")(to_like);@/ @z @x id6("d")("o")("w")("n")("t")("o")(to_like);@/ @y id10("d")("e")("f")("i")("n")("i")("t")("i")("o")("n")(goto_like);@/ @z @x id3("e")("n")("d")(end_like);@/ id4("f")("i")("l")("e")(array_like);@/ id3("f")("o")("r")(for_like);@/ id8("f")("u")("n")("c")("t")("i")("o")("n")(proc_like);@/ id4("g")("o")("t")("o")(goto_like);@/ @y id5("e")("l")("s")("i")("f")(elsif_like);@/ id3("e")("n")("d")(end_like);@/ id4("e")("x")("i")("t")(goto_like);@/ id6("e")("x")("p")("o")("r")("t")(goto_like);@/ id3("f")("o")("r")(for_like);@/ id4("f")("r")("o")("m")(goto_like);@/ @z @x id2("i")("f")(if_like);@/ id2("i")("n")(char_like+set_element_sign);@/ id5("l")("a")("b")("e")("l")(const_like);@/ @y id2("i")("f")(for_like);@/ id14("i")("m")("p")("l")("e")("m")("e")("n")("t")("a")("t")("i")("o")("n")(goto_like);@/ id6("i")("m")("p")("o")("r")("t")(goto_like);@/ id2("i")("n")(char_like+set_element_sign);@/ id5("l")("a")("b")("e")("l")(const_like);@/ id4("l")("o")("o")("p")(loop_like);@/ id6("m")("o")("d")("u")("l")("e")(proc_like);@/ @z @x id2("o")("f")(do_like);@/ @y id2("o")("f")(of_like);@/ @z @x id6("p")("a")("c")("k")("e")("d")(goto_like);@/ @y id7("p")("o")("i")("n")("t")("e")("r")(goto_like);@/ @z @x id7("p")("r")("o")("g")("r")("a")("m")(proc_like);@/ @y id9("q")("u")("a")("l")("i")("f")("i")("e")("d")(goto_like);@/ @z @x id6("r")("e")("p")("e")("a")("t")(repeat_like);@/ @y id6("r")("e")("p")("e")("a")("t")(repeat_like);@/ id6("r")("e")("t")("u")("r")("n")(goto_like);@/ @z @x id7("x")("c")("l")("a")("u")("s")("e")(loop_like);@/ @y @z @x @d force_line=@'3 {extended ASCII beta will not appear} @y @d force_line=@'3 {extended ASCII beta will not appear} @d vertical_bar=15 {control code for vertical bar character} @d begin_regular_comment=16 {control code for beginning of comments} @d end_regular_comment=17 {control code for ending of comments} @z @x else if c="{" then incr(bal) else if c="}" then begin decr(bal); if bal=0 then goto done; end @y else if c=begin_regular_comment then incr(bal) else if c=end_regular_comment then begin decr(bal); if bal=0 then goto done; end else if (c="(") and (buffer[loc]="*") then begin incr(bal); incr(loc); end else if (c="*") and (buffer[loc]=")") then begin decr(bal); incr(loc); c:=end_regular_comment; if bal=0 then goto done; end @z @x @ Note that the following code substitutes \.{@@\{} and \.{@@\}} for the respective combinations `\.{(*}' and `\.{*)}'. Explicit braces should be used for \TeX\ comments in \PASCAL\ text. @y @ Note that the following code converts `\.{(*}' and `\.{*)}' to internal characters which are converted back to ASCII when output. Adjacent vertical bar characters (|'||'|), which represent the Modula-2 usage of that character rather than that of WEB, are handled the same way. @z @x "(": if buffer[loc]="*" then compress(begin_comment) else if buffer[loc]="." then compress("["); "*": if buffer[loc]=")" then compress(end_comment); @y "(": if buffer[loc]="*" then compress(begin_regular_comment) else if buffer[loc]="." then compress("["); "*": if buffer[loc]=")" then compress(end_regular_comment); "|": if buffer[loc]="|" then compress(vertical_bar); @z @x if (next_control="|")or(next_control="{") then return; @y if (next_control="|")or(next_control=begin_regular_comment) then return; @z @x if next_control<>"{" then Pascal_xref @y if next_control<>begin_regular_comment then Pascal_xref @z @x done: for k:=1 to j do write(tex_file,xchr[out_buf[k]]); if per_cent then write(tex_file,xchr["%"]); write_ln(tex_file); incr(out_line); @y done: for k:=1 to j do out_temp_buffer[k]:=xchr[out_buf[k]]; k:=j; if per_cent then begin incr(k); out_temp_buffer[k]:=xchr["%"]; end; write_ln(tex_file,substr(out_temp_buffer,1,k)); incr(out_line); @z @x `\.{\\input webmac}'. @y `\.{\\input mwebmac}'. @z @x out_ptr:=1; out_line:=1; out_buf[1]:="c"; write(tex_file,'\input webma'); @y out_ptr:=1; out_line:=1; out_buf[1]:="c"; write(tex_file,'\input mwebma'); @z @x if c="|" then goto done; app_tok(c); @y if c="|" then goto done; if (c="*") and (buffer[loc]=")") then begin incr(loc); c:=end_regular_comment; app_tok("}"); end else begin app_tok(c); end; @z @x else if c="{" then incr(bal) else if c="}" then begin decr(bal); if bal=0 then goto done; end @y else if c=begin_regular_comment then incr(bal) else if c=end_regular_comment then begin decr(bal); if bal=0 then goto done; end else if (c="(") and (buffer[loc]="*") then begin incr(bal); incr(loc); end @z @x repeat app_tok("}"); decr(bal); @y repeat app_tok(end_regular_comment); decr(bal); @z @x if (next_control="|")or(next_control="{") then return; @y if (next_control="|")or(next_control=begin_regular_comment) then return; @z @x "#","$","%","^","_": sc2("\")(next_control)(math); @y "$","%","^","_": sc2("\")(next_control)(math); "#": if in_def_part then begin pound_found := true; sc2("\")("#")(math); end else sc2("\")("I")(math); "~": sc2("\")("R")(math); "&": sc2("\")("W")(math); @z @x ignore,"|",xref_roman,xref_wildcard,xref_typewriter: do_nothing; @y ignore,xref_roman,xref_wildcard,xref_typewriter: do_nothing; @z @x ";": sc1(";")(semi); @y ";": sc1(";")(semi); "{": sc2("\")("{")(open); "}": sc2("\")("}")(close); "|",vertical_bar: sc4("\")("V")("B")(force)(semi); @z @x equivalence_sign: sc2("\")("S")(math); @y equivalence_sign: begin sc2("\")("S")(math); if not pound_found then in_def_part := false; end; @z @x do_like,for_like,goto_like,nil_like,to_like: sub_cases(p); @y of_like,for_like,goto_like,nil_like,to_like: sub_cases(p); @z @x do_like: sc1(res_flag+p)(omega); {\&{do}, \&{of}, \&{then}} @y @z @x for_like: sc2(force)(res_flag+p)(alpha); {\&{for}, \&{while}, \&{with}} @y for_like: sc2(force)(res_flag+p)(alpha); {\&{for}, \&{if}, \&{while}, \&{with}} @z @x goto_like: sc1(res_flag+p)(intro); {\&{goto}, \&{packed}} @y goto_like: sc1(res_flag+p)(intro); {\&{packed}} @z @x to_like: sc3(math_rel)(res_flag+p)("}")(math); {\&{downto}, \&{to}} @y of_like: sc1(res_flag+p)(omega); {\&{of} } to_like: sc3(math_rel)(res_flag+p)("}")(math); {\&{to}} @z @x begin_like: begin sc3(force)(res_flag+p)(cancel)(beginning); sc0(intro); end; {\&{begin}} @y begin_like: begin sc4(force)(backup)(res_flag+p)(force)(beginning); sc0(intro); end; {\&{begin}} @z @x else_like: begin @; sc3(force)(backup)(res_flag+p)(elsie); @y do_like: begin sc2(res_flag+p)(force)(omega); sc0(beginning); sc0(intro); end; {\&{do}, \&{then}} elsif_like: begin @; sc0(close); sc0(terminator); sc1(res_flag+p)(alpha); end; else_like: begin sc4(force)(backup)(res_flag+p)(force)(terminator); @z @x end_like: begin @; sc2(force)(res_flag+p)(close); @y end_like: begin @; sc4(force)(backup)(res_flag+p)(break_space)(close); @z @x if_like: begin sc0(cond); sc2(force)(res_flag+p)(alpha); end; {\&{if}} @y @z @x loop_like: begin sc3(force)("\")("~")(alpha); @y loop_like: begin sc1(force)(alpha); @z @x sc1(res_flag+p)(omega); @y sc2(res_flag+p)(force)(omega); sc0(beginning); sc0(intro); @z @x end; {\&{xclause}} @y end; {\&{loop}} @z @x record_like: begin sc1(res_flag+p)(record_head); sc0(intro); end; {\&{record}} @y record_like: begin sc1(res_flag+p)(alpha); sc0(omega); sc0(beginning); end; {\&{record}} @z @x repeat_like: begin sc4(force)(indent)(res_flag+p)(cancel)(beginning); sc0(intro); @y repeat_like: begin sc4(force)(indent)(res_flag+p)(force)(beginning); sc0(intro); @z @x if next_control<>"{" then Pascal_parse @y if next_control<>begin_regular_comment then Pascal_parse @z @x bal:=copy_comment(1); next_control:="|"; @y bal:=copy_comment(1); next_control:=ignore; @z @x if next_control="|" then bal:=copy_comment(bal) @y if next_control="|" then begin next_control := ignore; bal:=copy_comment(bal); end @z @x save_next_control:=next_control; next_control:="|"; p:=Pascal_translate; @y save_next_control:=next_control; next_control:=ignore; p:=Pascal_translate; @z @x repeat next_control:=copy_TeX; @y in_def_part := false; repeat next_control:=copy_TeX; @z @x "|": begin init_stack; output_Pascal; @y "|": begin next_control := ignore; init_stack; output_Pascal; @z @x begin sc2("\")("D")(intro); {this will produce `\&{define }'} @y begin sc2("\")("D")(intro); {this will produce `\&{define }'} in_def_part := true; pound_found := false; @z @x @=@!this_module:name_pointer; {the current module name, or zero} @y @=@!this_module:name_pointer; {the current module name, or zero} in_def_part, pound_found : boolean; {flags to determine context of use of pound sign and vertical bar} @z @x this_module:=0; @y this_module:=0; in_def_part := false; @z @x @!term_in:text_file; {the user's terminal as an input file} @y @z @x @= @y @d term_in==input @= @z @x reset(term_in,'TTY:','/I'); {open |term_in| as the terminal, don't do a |get|} @y @z @x @t\4\4@>{here files should be closed if the operating system requires it} @y if history(tex_file,@=disposition:=save@>,@=error:=continue@>); @z @x This module should be replaced, if necessary, by changes to the program that are necessary to make \.{WEAVE} work at a particular installation. It is usually best to design your change file so that all changes to previous modules preserve the module numbering; then everybody's version will be consistent with the printed program. More extensive changes, which introduce new modules, can be inserted here; then only the index itself will get a new module number. @y Here are the remaining changes to the program that are necessary to make \.{WEAVE} work on Vax/VMS. @ This variable is for speeding up the output routine. @= @!out_temp_buffer: packed array [1..line_length+1] of char; @ On Vax/VMS we need the following special definitions, types, variables and procedures to be able to get the file name from the command line, or to prompt for them. @d VAX_volatile==@=volatile@> @d VAX_immed==@=%immed @> @d VAX_external==@=external@> @d VAX_stdescr==@=%stdescr @> @d VAX_lib_get_foreign==@= lib$get_foreign@> @d VAX_length==@=length @> @ @= @!command_line:packed array[1..300] of char; @!cmd_len:sixteen_bits; @!cmd_i:integer; @!file_name,@!default_file_name:varying [300] of char; @!ask,@!got_file_name: boolean; @ Here is the library procedure that gets the user's command line. @= [VAX_external] function VAX_lib_get_foreign( VAX_stdescr cmdlin:[VAX_volatile] packed array [$l1..$u1:integer] of char := VAX_immed 0; VAX_stdescr prompt:[VAX_volatile] packed array [$l2..$u2:integer] of char := VAX_immed 0; var len : [VAX_volatile] sixteen_bits := VAX_immed 0; var flag : [VAX_volatile] integer := VAX_immed 0) :integer; extern; @ We get the external file names, and then call |open| to associate an external file with each file variable. @d VAX_open == @= open@> @= cmd_i:=0; VAX_lib_get_foreign(command_line,,cmd_len,cmd_i); cmd_i:=1; while (cmd_i<=cmd_len) and (command_line[cmd_i]=' ') do incr(cmd_i); got_file_name:=cmd_i<=cmd_len; if got_file_name then default_file_name:=substr(command_line,cmd_i,cmd_len-cmd_i+1); if got_file_name then begin file_name:=default_file_name+'.WEB'; VAX_open(web_file,file_name,@=readonly@>,@=error:=continue@>); ask:=status(web_file)<>0; if ask then write_ln('Couldn''t open ',file_name); end else ask:=true; while ask do begin got_file_name:=false; write('Web file: '); if eof then begin mark_fatal; jump_out; end; read_ln(file_name); VAX_open(web_file,file_name,@=readonly@>,@=error:=continue@>); ask:=status(web_file)<>0; if ask then write_ln('Couldn''t open ',file_name); end; if got_file_name then begin file_name:=default_file_name+'.CH'; VAX_open(change_file,file_name,@=readonly@>,@=error:=continue@>); ask:=status(change_file)>0; {can be empty} if ask then write_ln('Couldn''t open ',file_name); end else ask:=true; while ask do begin write('Change file: '); if eof then begin mark_fatal; jump_out; end; read_ln(file_name); if file_name.VAX_length=0 then file_name:='NL:'; VAX_open(change_file,file_name,@=readonly@>,@=error:=continue@>); ask:=status(change_file)>0; if ask then write_ln('Couldn''t open ',file_name); end; if got_file_name then begin cmd_i:=1; for cmd_len:=1 to default_file_name.VAX_length do if (default_file_name[cmd_len]=']') or (default_file_name[cmd_len]=':') then cmd_i:=cmd_len+1; if cmd_i<=default_file_name.VAX_length then default_file_name:=substr(default_file_name,cmd_i, default_file_name.VAX_length-cmd_i+1); file_name:=default_file_name+'.TEX'; VAX_open(tex_file,file_name,@=new,disposition:=delete@>, @=error:=continue@>); ask:=status(tex_file)>0; if ask then write_ln('Couldn''t open ',file_name); end else ask:=true; while ask do begin write('TeX file: '); if eof then begin mark_fatal; jump_out; end; read_ln(file_name); VAX_open(tex_file,file_name,@=new,disposition:=delete@>, @=error:=continue@>); ask:=status(tex_file)>0; if ask then write_ln('Couldn''t open ',file_name); end; rewrite(tex_file); @z