begin comment A0006,A0013; comment A0012; procedure findprog(dv,a); value dv; integer dv; integer array a; begin comment A̲L̲G̲O̲L̲; end findprog; integer procedure readprog; begin comment A̲L̲G̲O̲L̲; end readprog; procedure printtitle(od); value od; integer od; begin comment A̲L̲G̲O̲L̲; end printtitle; procedure print(s, n); value n; string s; integer n; begin writetext(out, s); write(out, format( “ ssndd ” ), n); end print; procedure algoledit(linelimit, id, od, failure); value linelimit, id, od; integer linelimit, id, od; label failure; comment This procedure edits one Algol 60 program when it is called. The meaning of the parameters is:- ‘line limit’ - the maximum number of basic symbols to be output on one line ‘id’ - the input device number ‘od’ - the output device number ‘failure’ - the procedure jumps to this label is a failure occurs while editing is in progress; begin comment ‘algol edit’ uses arrays for the following purposes:- ‘n tabs’ - the elements of this array are used to remember the number of tabs which must precede the start of each statement and declaration of every block ‘disk buffer’ - this array is used as a buffer if the Algol program is read from the disc ‘buffer’ - this array is used as a buffer to hold the symbols which will be output on the next line ‘s’ - this array is used as a temporary store when a line must be split because it is too long ‘spa’, ‘spb’ - these arrays are used to specify the number of spaces which are to be output before and after each different basic symbol; integer array ntabs[1 : 25], buffer, s[0 : 150], discbuffer[0 : if id = 120 then 640 else 1], spa, spb[0 : 255]; comment At any point in the Algol program being edited, these integer variables have the following values:- ‘b ctr’, ‘e ctr’ - the number of b̲e̲g̲i̲n̲s and e̲n̲d̲s that have occurred so far ‘bs’ - the current basic symbol ‘depth’ - the currentnested block depth, ie. ‘b ctr’ - ‘e ctr’ ‘i’ - this is used as the controlled variable in a f̲o̲r̲ statement ‘lc’ - the next symbol to be output will be put in ‘buffer[lc]’ ‘line number’ - the value of this variable is the number of lines which are to be utput before the next gap ‘start of string’ - this variable is used in the procedures ‘read string’ and ‘copy string’. Its value indicates the start of the current string in the output buffer and is needed if the string is too long to be put on one line ‘tabs’ - the number of tab symbols which must start the next line to be output ‘tabspace’ - the number of spae symbols equivalent to oe tab symbol; integer bctr, bs, depth, ectr, l, lc, linenumber, startofstring, tabs, tabspace; comment Each one of these variables represents an Algol basic symbol and has an appropriate constant value; integer capital A, and, array, becomes, begin, boolean, colon, comma, comment, divide, do, else, end, equals, eqv, false, for, goto, greaterthan, gtequal, if, imp, intdiv, integer, label, lrbracket, lsqbracket, lstrbracket, lessthan, ltequal, minus, multiply, newline, nine, not, notequal, or, own, plus, procedure, real, rrbracket, rsqbracket, rstrbracket, semicolon, space, step, string, subscript ten, switch, tab, then, true, until, value, while, zero, small z; comment Each one of these variables represents a KDF9 pseudo basic symbol and has the appropriate constant value; integer algol, endmessage, exit, kdf9, library, segment, tabdummy; comment A list of the procedures in algol edit. read symbol out line ( i̲n̲t̲e̲g̲e̲r̲ v̲a̲l̲u̲e̲ od, i̲n̲t̲e̲g̲e̲r̲ a̲r̲r̲a̲y̲ buffer, i̲n̲t̲e̲g̲e̲r̲ v̲a̲l̲u̲e̲ lc ) nbs b̲o̲o̲l̲e̲a̲n̲ letter or digit identifier or label scan ( i̲n̲t̲e̲g̲e̲r̲ v̲a̲l̲u̲e̲ symbol 1, i̲n̲t̲e̲g̲e̲r̲ v̲a̲l̲u̲e̲ symbol 2 ) next line out 1 ( i̲n̲t̲e̲g̲e̲r̲ v̲a̲l̲u̲e̲ char ) out ( i̲n̲t̲e̲g̲e̲r̲ v̲a̲l̲u̲e̲ char ) clear full line ( i̲n̲t̲e̲g̲e̲r̲ v̲a̲l̲u̲e̲ symbol ) specifications or declarations ( b̲o̲o̲l̲e̲a̲n̲ v̲a̲l̲u̲e̲ declarations ) proc declaration fail ( i̲n̲t̲e̲g̲e̲r̲ v̲a̲l̲u̲e̲ n ) expression ( i̲n̲t̲e̲g̲e̲r̲ v̲a̲l̲u̲e̲ symbol ) for variable and list if clause statement possible label(b̲o̲o̲l̲e̲a̲n̲ v̲a̲l̲u̲e̲ inserting a dummy statement is possible) copy string read string copy square brackets copy round brackets block ( b̲o̲o̲l̲e̲a̲n̲ v̲a̲l̲u̲e̲ inner ) call library code body ; comment label numbers 1 statement 2 scan 3 specifications or declarations 4 clear full line 5 copy square brackets 6 fail 7 nbs 8 read string 9 comment statement 10 block 11 block 12 copy round brackets 13 call library 14 specifications or declarations 15 code body 16 code body 17 out 18 identifier or label 19 expression 20 expression 21 for variable and list 22 statement ; procedure readsymbol; comment This procedure assigns the next basic symbol of the Algol program being edited to the global variable ‘be’. It is a machine-dependent procedure; begin if bs = endmessage then fail(114); bs ≔ if id = 120 then readprog else inbasicsymbol(id); end readsymbol; procedure outline(od, buffer, lc); value od, lc; integer od, lc; integer array buffer; begin comment This is the basic output routine which prints the next line of the program on device od. The symbols of the output line are stored in elements 1 to lc of the array buffer . outline is a machine dependent procedure; comment A̲L̲G̲O̲L̲; end outline; procedure nbs; comment ‘nbs’ assigns the next non-printing symbol of the Algol program being edited to the variabe ‘bs’; begin label7 :; readsymbol; if bs = space ∨ bs = newline ∨ bs = tab then goto label7; end nbs; boolean procedure letter or digit; letter or digit ≔ (bs ⩾ capital A ∧ bs ⩽ small z) ∨ (bs ⩾ zero ∧ bs ⩽ nine); procedure identifier or label; comment This procedure copies successive symbols of the Algol program which form either an identifier or label; begin if ¬ letter or digit then fail(105); label18 :; out(bs); nbs; if letter or digit then goto label18; end identifier or label; procedure scan(symbol1, symbol2); value symbol1, symbol2; integer symbol1, symbol2; comment ‘scan’ copies successive non-printing symbols and bracketed elements of the Algol program. It inserts spaces where appropriate and stops when the current basic symbol is either ‘symbol1’ or ‘symbol2’; begin label2 :; if bs = lrbracket then begin copy round brackets; goto label2 end; if bs = lsqbracket then begin copy square brackets; goto label2 end; out(bs); if bs ≠ symbol1 ∧ bs ≠ symbol2 then begin nbs; goto label2; end end scan; procedure next line; comment ‘next line’ outputs the next line of the edited Algol program and stores in ‘buffer’ the tab symbols at the beginning of the next line; begin integer i, j; if linenumber = 0 then begin if od = 10 then begin outline(od, buffer, lc-1); gap(od, 50); end else begin buffer[lc] ≔ newline; outline(od, buffer, lc); end; linenumber ≔ 31; end else begin linenumber ≔ linenumber+1; buffer[lc] ≔ newline; outline(od, buffer, lc); end; lc ≔ tabspace × tabs; for i ≔ 1 step tabspace until lc do begin buffer[i] ≔ tab; for j ≔ i+1 step 1 until i+tabspace-1 do buffer[j] ≔ tabdummy; end for i; lc ≔ lc + 1; end next line; procedure comment statement; comment ‘comment statement’ edits a comment from the basic symbol c̲o̲m̲m̲e̲n̲t̲ up to the semicolon; begin next line; tabs ≔ tabs+1; out(bs); label9 :; if lc > 150 then fail(113); readsymbol; if bs ≠ semicolon then begin if bs = newline then next line else if bs = tab then out1(space) else out1(bs); goto label9; end; out1(semicolon); tabs ≔ tabs-1; next line; next line; nbs; end comment statement; procedure out1(char); value char; integer char; comment ‘out 1’ inserts the symbol ‘char’ into the output buffer and increases the counter ‘lc’ by one; begin buffer[lc] ≔ char; lc ≔ lc+1; end out1; procedure out(char); value char; integer char; comment ‘out’ inserts the symbol ‘char’into the output buffer. If necessary ‘out’ also puts a space before and/or after‘char’. ‘out’ also checks to see if the buffer is full, if so it is emptied; begin if buffer[lc - 1] = subscript ten then begin if char = plus ∨ char = minus then begin out1(char); nbs; out1(bs); goto label17; end end; if spb[char] ≠ 0 ∧ buffer[lc-1] ≠ space then out1(space); if (char = comma ∨ char = semicolon) ∧ buffer[lc-1] = space then lc ≔ lc-1; out1(char); if spa[char] ≠ 0 then out1(space); label17 :; if lc > linelimit+3 then fail(106); if lc ⩾ linelimit then clear full line(space); end out character; procedure clear full line(symbol); value symbol; integer symbol; comment clear full line is called when an edited line is too long to be output on a single line. It looks for the latest occurrence of the symbol specified by the parameter ‘symbol’, and splits the line at this point. It outputs the first part of the line and puts the remaining characters at the beginning of the next line. The procedure fails if it is unable to find a point at which the line can be split; begin integer i, j, k; j ≔ lc - 1; for k ≔ 1 step 1 until linelimit - tabspace × (tabs-1) + 1 do begin if buffer[j] = symbol then goto label4; s[k] ≔ buffer[j]; j ≔ j-1; end; fail(100); label4 :; lc ≔ j; if symbol = semicolon then out1(semicolon); tabs ≔ tabs+1; next line; lc ≔ lc-1; for j ≔ 1 step 1 until k-1 do buffer[lc+j] ≔ s[k-j]; lc ≔ lc+k; tabs ≔ tabs-1; end clear full line; procedure specifications or declarations(declarations); value declarations; boolean declarations; comment If the parameter of ‘specifications or declarations’ is false, then this procedure edits the value and specification part of a procedure declaration. If the parameter is true, then the procedure edits a list of declarations separated by semicolons; begin label3 :; if bs = procedure ∧ declarations then begin proc declaration; goto label3; end else if bs = switch ∧ declarations then begin scan(becomes, becomes); nbs; end else if bs = library then begin call library; goto label3; end else if bs = comment then begin comment statement; goto label3; end else if bs = real ∨ bs = integer ∨ bs = boolean ∨ bs = array ∨ bs = switch ∨ bs = label ∨ bs = string ∨ bs = own ∨ bs = value ∨ bs = procedure then begin out(bs); nbs; goto label3; end; if lc ≠ tabspace × tabs + 1 then begin tabs ≔ tabs+1; next line; label14 :; scan(comma,semicolon); if bs = semicolon then tabs ≔ tabs-1; next line; if bs = comma then begin nbs; goto label14; end; nbs; goto label3; end; end specifications or declarations; procedure proc declaration; comment ‘proc declaration’ edits a procedure declaration. The call of statement must be extended if it is necessary to take account of procedures with code bodies; begin scan(semicolon, semicolon); tabs ≔ tabs+1; next line; nbs; specifications or declarations(false); if bs = segment then scan(semicolon, semicolon) else begin if bs = kdf9 then code body else statement; if bs = semicolon then out(bs) else fail(107); end; tabs ≔ ntabs[depth]; next line; next line; nbs; end proc declaration; procedure fail(n); value n; integer n; comment ‘fail’ outputs the current line and a brief failure message. It then looks for the end of the program and exits to the label ‘failure’. The procedures in which the various failure numbers are generated are :- 100 clear full line 101 read string 102 copy square brackets 103 copy round brackets 104 block 105 identifier or label 106 out 107 proc declaration 108 call library 109 read string 110 block 111 code body 112 code body 113 comment statement 114 read symbol 114 for variable and list 117 if clause ; begin lc ≔ if lc > linelimit then linelimit else lc; next line; print( “ fail ”, n); label6 :; readsymbol; if bs = begin then bctr ≔ bctr+1 else if bs = end then ectr ≔ ectr+1; if bctr = ectr then goto failure else goto label6; end fail; procedure expression(symbol); value symbol; integer symbol; comment This procedure edits a conditional or simple expression. It stops when the current basic sybol is e̲n̲d̲ or ‘comma’ or s̲t̲e̲p̲ or w̲h̲i̲l̲e̲ or ‘symbol’; begin if bs = if then begin tabs ≔ tabs+1; next line; label19 :; if clause; expression(else); tabs ≔ tabs-1; next line; out1(else); nbs; if bs = if then begin out1(space); goto label19 end; tabs ≔ tabs+1; next line; expression(symbol); tabs ≔ tabs-2; end else begin label20 :; if bs = lrbracket then copy round brackets else if bs = lsqbracket then copy square brackets; if bs = end ∨ bs = comma ∨ bs = step ∨ bs = while ∨ bs = symbol then else begin out(bs); nbs; goto label20 end; end; end expression; procedure for variable and list; comment for variable and list edits the first part of a f̲o̲r̲ statement, from f̲o̲r̲ upto and including d̲o̲ ; begin if bs ≠ for then fail(114); tabs ≔ tabs + 1; scan(becomes, becomes); label21 :; nbs; scan(comma,do); next line; if bs = comma then goto label21; nbs end for variable and list; procedure if clause; comment This procedure edits an if clause ; begin if bs ≠ if then fail(117); out(bs); nbs; expression(then); out(bs); tabs ≔ tabs+1; next line; nbs; end if clause; procedure statement; comment ‘statement’ edits any unlabelled statement; begin label1 :; if letter or digit then begin possible label(false); goto label1 end; if bs = if then begin if clause; goto label1 end; if bs = for then begin for variable and list; goto label1 end; if bs = begin then block(false); label22 :; if bs = lrbracket then copy round brackets else if bs = lsqbracket then copy square brackets else if bs = if then expression(semicolon) else if bs = else then begin tabs ≔ tabs-1; next line; out1(else); nbs; if bs = if then out1(space) else begin tabs ≔ tabs+1; next line; end; goto label1 end; if bs ≠ semicolon ∧ bs ≠ end then begin out(bs); nbs; goto label22 end end statement; procedure possible label(inserting a dummy statement is possible); value inserting a dummy statement is possible; boolean inserting a dummy statement is possible; comment ‘possible label’ is called at the beginning of a statement if the statement starts with a letter or digit. ‘possible label’ looks to see if this identifier or integer is followed by a colon - if it is then the statement is labelled, the label is shifted half a tab to the left and put on a line by itself; begin integer i, di; identifier or label; if bs = colon then begin if tabs ≠ 0 then begin di ≔ (tabspace+1)+2; lc ≔ lc-di; for i ≔ tabspace × tabs+1-di step 1 until lc-1 do buffer[i] ≔ buffer[i+di]; for i ≔ tabspace × (tabs-1)+1 step 1 until tabspace × tabs-di do buffer[i] ≔ space; end; out(colon); nbs; if bs ≠ semicolon then begin if inserting a dummy statement is possible then begin out(semicolon); next line end end; end; end possible label; procedure copy string; comment The two procedures ‘copy string’ and ‘read string’ edit a string ( including nested strings ). Editing characters are also copied except any tab symbols which occur immediately after a newline symbol; begin if buffer[lc-1] ≠ space then out1(space); startofstring ≔ lc; read string; end copy string; procedure read string; comment The two procedures ‘copy string’ and ‘read string’ edit a string ( including nested strings ). Editing characters are also copied except any tab symbols which occur immediately after a newline symbol; begin integer i; if bs ≠ lstrbracket then fail(101); label8 :; out1(bs); if lc > linelimit then begin lc ≔ startofstring; tabs ≔ tabs+1; next line; tabs ≔ tabs-1; if lc ⩾ startofstring then fail(109); startofstring ≔ lc; for i ≔ startofstring step 1 until linelimit do out1(buffer[i]); end; readsymbol; if bs = lstrbracket then begin read string; goto label8; end else if bs = newline then begin tabs ≔ tabs+1; next line; tabs ≔ tabs-1; startofstring ≔ lc; nbs; goto label8; end else if bs ≠ rstrbracket then goto label8; end read string; procedure copy square brackets; comment ‘copy square brackets’ edits a balanced syntactic structure enclosed in square brackets; begin if bs ≠ lsqbracket then fail(102); label5 :; out(bs); nbs; if bs = lrbracket then begin copy round brackets; goto label5 end; if bs = lsqbracket then begin copy square brackets; goto label5 end; if bs ≠ rsqbracket then goto label5; end copy square brackets; procedure copy round brackets; comment ‘copy round brackets’ edits a balanced syntactic structure enclosed in round brackets; begin if bs ≠ lrbracket then fail(103); label12 :; out(bs); nbs; if bs = lstrbracket then begin copy string; goto label12 end; if bs = lrbracket then begin copy round brackets; goto label12 end; if bs ≠ rrbracket then goto label12; end copy round brackets; procedure block(inner); value inner; boolean inner; comment ‘block’ edits a block. If the parameter ‘inner’ is true then the block being edited is a statement of the enclosing block and its declarations and statements start with an extra tab. But if the value of ‘inner’ is false then the block to be edited is a part of a conditional or f̲o̲r̲ statement and extra tabs are unnecessary. e̲n̲d̲ comments are copied except that newline symbols are ignored and tab symbols are replaced by a space. Dummy statements which are not followed by e̲n̲d̲ are put on a line by themselves; begin out(begin); bctr ≔ bctr+1; depth ≔ depth+1; ntabs[depth] ≔ tabs ≔ tabs + (if inner then 1 else 0); next line; nbs; specifications or declarations(true); label11 :; if letter or digit then begin possible label(true); goto label11; end; if bs = begin then block(true) else if bs = comment then begin comment statement; goto label11; end else if bs = library then begin call library; goto label11; end else statement; tabs ≔ ntabs[depth]; if bs = semicolon then begin out(semicolon); nbs; if bs ≠ end then next line; goto label11; end; if bs ≠ end then fail(104); if inner then tabs ≔ tabs-1; next line; out(end); ectr ≔ ectr+1; depth ≔ depth-1; if depth = 0 then begin next line; out(endmessage); next line; if id = 120 then begin nbs; if bs ≠ endmessage then fail(110); end end else begin label10 :; readsymbol; if bs = newline then goto label10; if bs = tab then begin out(space); goto label10 end; if bs ≠ end ∧ bs ≠ else ∧ bs ≠ semicolon then begin out(bs); goto label10 end end end block; procedure call library; comment ‘call library’ edits a library call by assuming that the call is followed by a comment; begin nbs; if bs ≠ comment then fail(108); bs ≔ library; comment statement; out(comment); label13 :; if buffer[lc] ≠ semicolon then begin lc ≔ lc+1; goto label13; end; lc ≔ lc+1; next line; next line; end call library; procedure code body; comment ‘code body’ edits a procedure body written in KDF9 User-code; begin integer i, j; scan(semicolon, semicolon); bs ≔ newline; label15 :; if bs = newline then begin next line; nbs; i ≔ space; if bs = 23 ∨ bs = 27 ∨ bs = 49 ∨ bs = 53 then begin i ≔ bs; nbs; end; if bs ⩽ nine then begin if i ≠ space then begin next line; out1(i); end; end else begin out1(tab); for j ≔ 1 step 1 until tabspace-1 do out1(tabdummy); if i ≠ space then out1(i); end; goto label15; end else if bs = library then begin next line; out(library); nbs; if bs ≠ lrbracket then fail(111); label16 :; nbs; if bs ≠ rrbracket then begin out(bs); goto label16; end; i ≔ lc; out(semicolon); next line; out(lrbracket); buffer[i] ≔ rrbracket; lc ≔ i+1; nbs; if bs ≠ semicolon then fail(112); out(bs); next line; nbs; goto label15 end else if bs ≠ algol then begin out1(bs); if lc ⩾ linelimit then clear full line(semicolon); readsymbol; goto label15; end; if lc ≠ (tabs+1) × tabspace+1 then next line else lc ≔ tabs × tabspace+1; out(algol); nbs; end code body; comment The declarations in algol edit end here; comment Assign a suitable value to each of the variables representing an Algol basic symbol. This section of ‘algol edit’ is machine dependent; capital A ≔ 12; and ≔ 147; array ≔ 72; becomes ≔ 181; begin ≔ 140; boolean ≔ 67; colon ≔ 185; comma ≔ 166; comment ≔ 128; divide ≔ 161; do ≔ 214; else ≔ 165; end ≔ 156; equals ≔ 162; eqv ≔ 195; false ≔ 205; for ≔ 134; goto ≔ 136; greaterthan ≔ 194; gtequal ≔ 178; if ≔ 133; imp ≔ 179; intdiv ≔ 145; integer ≔ 66; label ≔ 121; lrbracket ≔ 132; lsqbracket ≔ 137; lstrbracket ≔ 141; lessthan ≔ 130; ltequal ≔ 146; minus ≔ 209; multiply ≔ 177; newline ≔ 160; nine ≔ 9; not ≔ 131; notequal ≔ 131; or ≔ 163; own ≔ 143; plus ≔ 193; procedure ≔ 80; real ≔ 65; rrbracket ≔ 148; rsqbracket ≔ 153; rstrbracket ≔ 157; semicolon ≔ 152; space ≔ 158; step ≔ 182; string ≔ 122; subscript ten ≔ 10; switch ≔ 88; tab ≔ 174; then ≔ 149; true ≔ 221; until ≔ 198; value ≔ 159; while ≔ 150; zero ≔ 0; small z ≔ 63; comment Assign suitable values to the variables representing pseudo basic symbols; algol ≔ 192; endmessage ≔ 190; exit ≔ 240; kdf9 ≔ 176; library ≔ 208; segment ≔ 224; tabdummy ≔ 254; comment Assign suitable values for the elments of ‘spa’ and ‘spb’ arrays. This part of ‘algol edit’ is partly a matter of taste; for i ≔ 0 step 1 until 255 do spb[i] ≔ spa[i] ≔ 0; for i ≔ plus, minus, divide, intdiv, lessthan, equals, gtequal, greaterthan, notequal, becomes, and, or, not, then, else, colon, eqv, imp, step, until, while do spb[i] ≔ spa[i] ≔ 1; for i ≔ real, integer, boolean, procedure, comment, if, for, goto, own, end, rstrbracket, comma, semicolon, switch do spa[i] ≔ 1; for i ≔ do, lstrbracket do spb[i] ≔ 1; for i ≔ kdf9, library, segment do spa[i] ≔ 1; comment Assign the initial values to the global variables of ‘algol edit’; bctr ≔ depth ≔ ectr ≔ 0; bs ≔ - 1; lc ≔ 1; linenumber ≔ tabs ≔ 0; tabspace ≔ 6; if id = 120 then begin findprog(20, discbuffer); printtitle(od); end; next line; start :; nbs; if bs ≠ begin then begin out(bs); goto start end; next line; block(true); end algoledit; integer cases, i, id, no, out; open(20); out ≔ read(20); cases ≔ read(20); if (out = 10 ∨ out = 30) ∧ cases > 0 then open(out) else begin open(30); writetext(30, “ error _ in _ initial _ data ” ); close(30); goto boob2 end; for i ≔ 1 step 1 until cases do begin no ≔ read(20); id ≔ read(20); if (id = 20 ∨ id = 120) ∧ no > 0 then begin algoledit(no, id, out, boob); gap(out, if out = 10 then 200 else 1); end else begin writetext(outc, “ error _ in _ data ” ); goto boob end; end; boob :; close(out); boob2 :; close(20); end