From: ken@aiai.ed.ac.uk (Ken Johnson) Newsgroups: alt.folklore.computers Subject: Intercal Manual (was re: Hacker's Dictionary) LONG, 1484 LINES Date: 26 Apr 90 13:00:21 GMT In article <801@barsoom.nhh.no> tih@barsoom.nhh.no (Tom Ivar Helbekkmo) writes: >I'm all for it! Let's get hold of some specs and implement the thing! THE INTERCAL PROGRAMMING LANGUAGE REFERENCE MANUAL Donald R. Woods & James M. Lyon Copyright Donald R. Woods & James M. Lyon 1973 INTERCAL 1. INTRODUCTION The names you are about to ignore are true. However, the story has been changed significantly. Any resemblance of the programming language portrayed here to other programming languages, living or dead, is purely coincidental. 1.1 ORIGIN AND PURPOSE The INTERCAL programming language was designed the morning of May 26, 1972 by Donald R. Woods and James M. Lyon, at Princeton University. Exactly when in the morning will become apparent in the course of this manual. It was inspired by one ambition; to have a compiler language which has nothing at all in common with any other major language. By 'major' was meant anything with which the authors were at all familiar, e.g., FORTRAN, BASIC, COBOL, ALGOL, SNOBOL, SPITBOL, FOCAL, SOLVE, TEACH, APL, LISP, and PI/I. For the most part, INTERCAL has remained true to this goal, sharing only the basic elements such as variables, arrays, and the ability to do I/O, and eschewing all conventional operations other than the assignment statement (FORTRAN "="). 1.2 ACRONYM The full name of the compiler is "Compiler Language With No Pronounceable Acronym", which is, for obvious reasons, abbreviated "INTERCAL". 1.3 ACKNOWLEDGEMENTS The authors are deeply indebted to Eric M. Van and Daniel J. Warmenhoven, without whose unwitting assistance this manual would still have been possible. 2. FUNDAMENTAL CONCEPTS In this section an attempt is made to describe how and why INTERCAL may be used; i.e., what it is like and what it is good for. 2.1 SAMPLE PROGRAM Shown below is a relatively simple INTERCAL program which will read in 32-bit unsigned integers, treat them as signed, 2's-complement numbers, and print out their absolute values. The program exits if the absolute value is zero. Note in particular the inversion routine (statements 6 through 14), which could be greatly simplified if the subroutine library (see section 5) were used. A more detailed analysis of a program is made in section 6 of this manual. DO (5) NEXT (5) DO FORGET #1 PLEASE WRITE IN :1 DO .1 <- 'V":1~'#32768$#0'"$#1'~#3 DO (1) NEXT DO :1 <- "'V":1~'#65535$#0'"$#65535' ~'#0$#65535'"$"'V":1~'#0$#65535'" $#65535'~'#0$#65535'" DO :2 <- #1 PLEASE DO (4) NEXT (4) DO FORGET #1 DO .1 <- "'V":1~'#65535$#0'"$":2~'#65535 $#0'"'~'#0$65535'"$"'V":1~'#0 $#65535'"$":2~'#65535$#0'"'~'#0$#65535'" DO (1) NEXT DO :2 <- ":2~'#0$#65535'" $"'":2~'#65535$#0'"$#0'~'#32767$#1'" DO (4) NEXT (2) DO RESUME .1 (1) PLEASE DO (2) NEXT PLEASE FORGET #1 DO READ OUT :1 PLEASE DO .1 <- 'V"':1~:1'~#1"$#1'~#3 DO (3) NEXT PLEASE DO (5) NEXT (3) DO (2) NEXT PLEASE GIVE UP 2.2 USES FOR INTERCAL INTERCAL's main advantage over other programming languages is its strict simplicity. It has few capabilities, and thus there are few restrictions to be kept in mind. Since it is an exceedingly easy language to learn, one might expect it would be a good language for initiating novice programmers. Perhaps surprising, than, is the fact that it would be more likely to initiate a no- vice into a search for another line of work. As it turns out, INTERCAL is more useful (which isn't saying much) as a challlenge to professional programmers. Those who doubt this need only refer back to the sample program in section 2.1. This 23-statement program took somewhere from 15 to 30 minutes to write, whereas the same objectives can be achieved by single-statement programs in either SNOBOL; PLEASE INPUT POS(0) ('-' ! '') + (SPAN('0123456789') $ OUTPUT) + *NE(OUTPUT) :S(PLEASE)F(END) or APL; [1] >-0=/?<-? Admittedly, neither of these is likely to appear more intelligible to any- one unfamiliar with the languages involved, but they took roughly 60 seconds and 15 seconds, respectively, to write. Such is the overwhelming power of INTERCAL! The other major importance of INTERCAL lies in its seemingly inexhaustible capacity for amazing one's fellow programmers, confounding programming shop managers, winning friends, and influencing people. It is a well-known and oft-demonstrated fact that a person whose work is incomprehensible is held in high esteem. For example, if one were to state that the simplest way to store a value of 65535 in a 32-bit INTERCAL variable is: DO :1 <- #0?#256 any sensible programmer would say that that was absurd. Since this is in- deed the simplest method, the programmer would be made to look foolish in front of his boss, who would of course happened to turn up, as bosses are wont to do. The effect would be no less devastating for the programmer hav- ing been correct. 3. DESCRIPTION The examples of INTERCAL programming which have appeared in the preceeding sections of this manual have probably seemed highly esoteric to the reader unfamiliar with the language. With the aim of making them more so, we pre- sent here a description of INTERCAL. 3.1 VARIABLES INTERCAL allows only 2 different types of variables, the 16-bit integer, and the 32-bit interger. These are represented by a spot (.) or two-spot (:), respectively, followed by any number between 1 and 65535, inclusive. These variables may contain only non-negative numbers; thus they have the respec- tive ranges of values: 0 to 65535 and 0 to 4294967295. Note: .123 and :123 are two distinct variables. On the other hand, .1 and .0001 are identical. Furthermore, the latter mau NOT be written as 1E-3. 3.2 CONSTANTS Constants are 16-bit values only and may range from 0 to 65535. Thay are prefixed by a mesh (#). Caution! Under no circumstances confuse the mesh with the interleave operator, except under confusing circumstances! 3.3 ARRAYS Arrays are reprsented by a tail (,) for 16-bit values, or a hybrid (;) for 32-bit values, followed by a number between 1 and 65535, inclusive. The number is suffixed by the word SUB, followed by the subscripts, separated optionally by spaces. Subscripts may be any expressions, including those involving subscripted variables. This occasionally leads to ambiguous con- structions, which are resolved as discussed in section 3.4.3 Definition of array dimensions will be discussed later in greater detail, sice discussing it in less detail would be difficult. As before, ,123 and ;123 are distinct. In summary, .123, :123, #123, ,123, and :123 are all distinct. 3.4 OPERATORS INTERCAL recognizes 5 operators--2 binary and 3 unary. Please be kind to our operators: they may not be very intelligent, but they're all we've got. In a sense, all 5 operators are binary, as they are all bit-oriented, but it is not our purpose here to quibble about bits of trivia. ******* proofread versus the paper copy only this far !!!! ************ 3.4.1 BINARY OPERATORS The binary operators are INTERLEAVE (also called MINGLE) and SELECT, which are represented by a change (c) and a sqiggle [sic] (~), respectively. The interleave operator takes two 16-bit values and produces a 32-bit result by alternating the bits of the operands. Thus, #65535c#0 has the 32-bit binary form 101010....10 or 2863311530 decimal, while #0c#65535 = 0101....01 binary = 1431655765 decimal, and #255c#255 is equivalent to #65535. The select operator takes from the first operand whichever bits correspond to 1's in the second operand, and packs these bits as the right in the result. Both operands are automatically padded on the left with zeros to 32 bits before the selction takes place, so the variable types are unresrticted. If more than 16 bits are selected, the result is a 32-bit value, otherrwise it is a 16-bit value. For example, #179~#201 (binary value 10110011~11001001) selects from the first argument the 8th, 7th, 4th, and 1st from last bits, namely, 1001, which = 9. But #201~#179 selects from binary 11001001 the 8th, 6th, 5th, 2nd, and 1st from last bits, giving 10001 = 17. #179~#179 has the value 31, while #201~#201 has the value 15. Perhaps a simpler way of understanding the operation of the select operator would be to examine the logic diagram on the following page (Figure 1), which performs the select operstion upon two 8-bit values, A and B. The gates used are Warmenhovian logic gates, which means the outputs have four possible values: low, high, undefined (value of an uninitialized flip-flop), and oscillating (output of a NOR gate with one input low and the other input connected to the output). These values are represented symbolocally by '0', '1', '2', and 'F'. Note in particular that, while NOT-0 is 1 and NOT-2 is 0 as in two-valued logic, NOT-? is ? and NOT-F is F. The functions of the various gates are listed on Table 1. 3.4.2 UNARY OPERATORS The unary operators a & (loghical AND), V (logical OP), and V (logical XOR). This last character is obtained by overpunching a worm (-) on a V (V). The operator is inserted between the spot, two-spot, mesh, or what-have-you, and the integer, thus: .&123, #V123. Multipe unary operators may not be concatenated, thus the form #V&123 is invalid. This will be covered later when precedence is discussed. These operators perform their respective logical operations on all pairs of adjacent bits, the result from the first and last bits going into the first bit of the result. The effect is that of rotating the operand one place to the right and ANDing, ORing, or XORing with its initial value. Thus, #&77 (binary = 1001101) is binary 000000000000 0100 = 4, #V77 is binary 1000000001101111 = 32879, and #V77 is binary 1000000001101011 = 32875. 3.4.3 PRECEDENCE Precedence of operators is as follows: [1] (The remainder of this page intentionally left blank) _________________ 1) Keep in mind that the aim in designing INTERCAL was to have no precedents. This precedence (or lack therreof) may be overruled by grouping expressions between pairs of sparks (') or rabbit-ears ("). Thus '#165c#203'~#358 binary value '10100101c11001011'~101100110) has the value 15, but #165c'#203~#358' has the value 34815, and #165c#203~#358 is invalid syntax and is completely valueless (except perhaps as an educational tool to the programmer). A unary operator is applied to a sparked or rabbit-eared expression by inserting the operator immediately following the opening spark or ears. Thus, the invalid expression #V&123, which was described earlier, could be coded a 'V#&123' or 'V"{"'. Note: In the interests of simplifying the sometimes overly-complex form of expressions, INTERCAL allows a spark-spot combination ('.) to be replaced with a wow (!). Thus '.1~.2' is equivalent to !1~.2', and 'V.1c.2' is equivalent to "V!1c.2'". Combining a rabbit-ears with a spot to form a rabbit (V) is not permitted, although the programmer is free to use it should he find an EBCDIC reader which will properly translate a 12-3-7-8 punch. Sparks and/or rabbit-ears must also be used to distinguish among such other- wise ambiguous subscripted and multipy-subscripted expressions as: ,1 SUB #1 ~ #2 ,1 SUB ,2 SUB #1 #2 #3 ,1 SUB " ,2 SUB " ,3 SUB #1 " #2 " " #3 " The third case may be isolated into either of its possible interpretations by simply changing some pairs of rabbit-ears to sparks, instead of adding more ears (which would only confuse the issue further). Ambiguous cases are defined as those for which the compiler being used finds a legitimate inter- pretation which is different from that which the user had in mind. See also section 8.1. 4. STATEMENTS In this section is described the format of INTERCAL statements. 4.1 GENERAL FORMAT Statements may be entered in 'free format'. That is, more than one statement may occur on a single card, and a statement may begin on one card and end on a later one. Note that if this is done, all intervening cards and portions thereof must be part of the same statement. That this restriction is necessary is immediately apparent from the following example of what, might occur if statements could be interlaced. DO .1 <- ".1c'&:51~"#V1c!12~;&75SUB"V'V.1~ DO .2 <- '"!1c"&';V79SUB",&7SUB:173"'~!V9c .2'c,&1SUB:5~#33578"'"'"~'#65535c"V'V#&85'"' #8196'"'~.1"c.2'~'#&5c"'#1279c#4351'~#65535"' The above statements are obviously meaningless. (For that matter, so are the statements DO .1 <- ".1c"&:51~"#V1C!12~;&75SUB"V'V.1~ .2'C,&1SUB:5~/333578"'"'"~#65535c"V'V#&85'"' DO .2 <- '"!1c"&';V79SUB",&7SUB:173"'~!V9c #8196'"'~.1"c.2'~'#&5c"'#1279c!4351'~#65535"' but this is not of interest here.) Spaces may be used freely to enhance program legibility (or at least reduce program illegibility), with the restriction that no word of a statement ident -ifier (see section 4.3) may contain any spaces. 4.2 LABELS A statement may begin with a LOGICAL LINE LABEL enclosed in wax-wane pairs (()). A statement may not have more than one label, although it is possible to omit the label entirely. A line label is any integer from 1 to 65535, which must be unique within each program. The user is cautioned, however, that many line labels between 1000 and 1999 are used in the INTERCAL System Library functions. 4.3 IDENTIFIERS AND QUALIFIERS After the line label (if any), must follow one of the following statement identifiers: DO, PLEASE, or PLEASE DO. These may be used interchangeably to improve the aesthetics of the program. The identifier is then followed by either, neither, or both of the following optional parameters (qualifiers): (1) either of the character strings NOT or N'T, which causes the statement to be automatically abstained from (see section 4.4.9) when execution begins, and (2) a number between 0 and 100, preceded by a double-oh-seven (%), which causes the statement to have only the specified percent chance of being exe- cuted each time it is encountered in the course of execution. 4.4 STATEMENTS Following the qualifiers (or, if none are used, the identifier) must occur one of the 13 valid operations. (Exception: see section 4.5.) These are described individually in sections 4.4.1 through 4.4.13. 4.4.1 CALCULATE The INTERCAL equivalent of the half-mesh (=) in FORTRAN, BASIC, PL/I, and others, is represented by an angle (<) followed by a worm (-). This combi- nation is read 'gets'. 32-bit variables may be assigned 16-bit values, which are padded on the left with 16 zero bits. 16-bit variables may be assigned 32-bit values only if the value is less than 65535. Thus, to invert the least significant bit of the first element of 16-bit 2-dimensional array number 1, one could write: ,1SUB#1#1 <- 'V,1SUB#1#1c#1'~'#0c#65535' Similarly to SNOBOL and SPITBOL, INTERCAL uses the angle-worm to define the dimensions of arrays. An example will probably best describe the format. To define 32-bit array number 7 as 3-dimensional, the first dimension being seven, the second being the current value of 16-bit variable number seven, and the third being the current value of the seventh element of 16-bit array number seven (which is one-dimensional) mingled with the last three bits of 32-bit variable number seven, one would write (just before they came to take him away): ;7 <- #7 BY .7 BY ",7SUB#7/'c':7~#7' This is, of course, different from the statement: ;7 <- #7 BY .7 BY ,7SUB"#7c':7~#7'" INTERCAL also permits the redefining of array dimensioning, which is done the same way as is the initial dimensioning. Allvalues of items in an array are lost upon redimensioning, unless they have been STASHed (see section 4.4.5), in which case restoring them also restores the old dimensions. 4.4.2 NEXT The NEXT statement is used both for subroutine calls and for unconditional transfers. This statement takes the form: DO (label) NEXT (or, of course, PLEASE DO (label) NEXT etc.), where (label) represents any logical line label which appears in the program. The effect of such a statement is to transfer control to the state- mant specified, and to store in a push down list (which is initially empty) the location from which the transfer takes place. Items may be removed from this list and may be discarded or used to return to the statement immediately following the NEXT statement. These operations are described in sections 4.4.3 and 4.4.4 respectively. The programmer is generally advised to discard any stack entries which he does not intend to utilize, since the stack has a maximum depth of 79 enteies. A program's attempting to initiate an 80th level of NEXTing will result on the fatal error message, "PROGRAM HAS DIS- APPEARED INTO THE BLACK LAGOON." 4.4.3 FORGET The staement PLEASE FORGET exp, where exp represents any expression (except colloquial and facial expressions), causes the expression to be evaluated, and the specified number of entries to be removed from the NEXTing stack and discarded. An attempt to FORGET more levels of NEXTing than are currently stacked will cause the stack to be emptied, and no error condition is indi- cated. This is because the condition is not considered to be an error. As described in section 4.4.2, it is good programming practice to execute a DO FORGET #1 after using a NEXT statement as an unconditional transfer, so that the stack does not get cluttered up with unused entries: DO (123) NEXT . . (123) DO FORGET #1 4.4.4 RESUME The statement PLEASE RESUME exp has the same effect as FORGET, except that program control os returned to the statement immediately following the NEXT statement which stored in the stack the last entry to be removed. Note that a rough equivalent of the FORTRAN computed GO TO and BASIC ON exp GO TO is performed by a sequence of the form: DO (1) EXT . . (1) DO (2) NEXT PLEASE FORGET #1 . . (2) DO RESUME .1 Unlike the FORGET statement, an attempt to RESUME more levels of NEXTing than been stacked will cause program termination. Se also section 4.4.11. 4.4.5 STASH Since subroutines are nit explicitly implemented in INTERCAL, the NEXT and RESUME statements must be used to execute common routines. However, as these routines might use tje sa,e variabless as the ,ain program, it is necessary for them to save the values of any variables whose values they alter, and later restore them. This process is simplified by the STASH state- ment, which has the form DO STASH list, where list represents a string of one or more variable or array names, seperated by intersections (+). Thus PLEASE STASH .123+:123+,123 stashes the values of two variables and one entire array. The values are left intact, and copies thereof are saved for later retrieval by (what else?) the RETRIEVE statement (see section 4.4.6). It is not possible to STASH single array items. 4.4.6 RETRIEVE PLEASE RETRIEVE list restores the previously STASHed values of the variables and arrays named in the list. If a value has been stashed more than once, teh most recently STASHed values are RETRIEVEd, and a second RETRIEVE will restore the second most recent values STASHed. Attempting to RETRIEVE a value which has not been STASHed will result in the error message, "THROW STICK BEFORE RETIEVING." 4.4.7 IGNORE The statement DO IGNORE list causes all subsequent statements to have no effect upon variables and/or arrays named in the list. Thus, for example, after the sequence DO .1 <- #1 PLEASE IGNORE .1 DO .1 <- #0 16-bit variable number 1 would have the value 1, not 0. Inputting (see sec- tion 4.4.12) into an IGNOREd variable also has no effect. The condition is annulled via the REMEMBER statement (see section 4.4.8). Note that, when a variable is being IGNOREd, its value, though immutable, is still avail- able for use in expressions and the like. 4.4.8 REMEMBER PLEASE REMEMBER list terminates the effect of the IGNORE statement for all variables and/or arrays named in the list. It does not matter if a variable has been IGNOREd more than once, nor is it an error of the variable has not been IGNOREd at all. 4.4.9 ABSTAIN INTERCAL contains no simple equivalent to an IF statement or computed GO TO, making it difficult to combine similar sections of code into a single rou- tine which occasionally skips around certain statements. The IGNORE state- ment (see section 4.4.7) is helpful in some cases, but a more viable method is often required. Inkeeping with the goal of INTERCAL having nothing in common with any other language, this is made possible via the ABSTAIN state- ment. This statement takes on one of two forms. It may not take on both at any one time. DO ABSTAIN FROM (label) causes the statement whose logical line label is (label) to be abstained form. PLEASE ABSTAIN FROM gerund list causes all statements of the specified type(s) to be abstained from, as in PLEASE ABSTAIN FROM STASHING PLEASE ABSTAIN FROM IGNORING + FORGETTING PLEASE ABSTAIN FROM NEXTING or PLEASE ABSTAIN FROM CALCULATING Statements may also be automatically abstained from at the start of execu- tion via the NOT nr N'T parameter (see section 4.3). If, in the course of execution, a statement is encountered which is being abstained from, it is ignored and control passes to the next statement in the program (unless it, too, is being abstained from). The statement DO ABSTAIN FROM ABSTAINING is perfectly valid, as is DO ABSTAIN FROM REINSTSTING (altough this latter is not usually recommended.) However, the statement DO ABSTAIN FROM GIVING UP is not accepted, even though DON'T GIVE UP is. 4.4.10 REINSTATE The REINSTATE statement, like the ABSTAIN, takes as an argument either a line label or a gerund list. No other form of argument is permitted. For example, the following is an invalid argument: Given: x=/0, y=/o, Prove: x+y=0 Since x=/0, then x+1=/1, x+a=/a, x+y=/y. Thus x+y =/ anything but 0. Since x+y cannot equal anything but 0, x+y=0. Q.E.D. REINSTATEment nullifies the effects of an abstention. Either form of REIN- STATEment can be used to "free" a statement, regardless of whether the state- ment was abstained from by gerund list, line label, or NOT. Thus, PPLEASE REINSTATE REINSTATING is not necessarily an irrelavant statement, since it might free a DON'T REINSTATE command or a REINSTATE the line label of which was abstained from. However, DO REINSTATE GIVING UP is invalid, and attempt- ing to REINSTATE a GIVE UP statement by line label will have no effect. Note that this insures that DON'T GIVE UP will always be a "do-nothing" statement. 4.4.11 GIVE UP PLEASE GIVE UP is used to exit from a program. It has the effect of a PLEASE RESUME #80. DON'T GIVE UP, as noted in section 4.4.10, is effectively a null statement. 4.4.12 Input Input is accomplished with the statement DO WRITE IN list, where list repre- sents a string of variables and/or elements or arrays, separated by inter- sections. Numbers are represented on cards, each number on a separate card, by spelling out each digit (in English) and separating the digits with one or more spaces. A zero (0) may be spelled as either ZERO or OH. Thus the range of (32-bit) input values permissible extends from ZERO (or OH) through FOUR TWO NINE FOUR NINE SIX SEVEN TWO NINE FIVE. Attempting To write in a value greater than or equal to SIX FIVE FIVE three six for a 16-bit variable will result in the error message, "DON'T BYTE OFF MORE THAN YOOU CAN CHEW." 4.4.13 Output Values may be output to the printer, one value per line, via the statement DO READ OUT list, where the list contains variables, array elements, and/or constants. Output is in the form of "extended"_Roman numerals (also called "butchered Roman numerals), with an overline ( ) indicating the value below is "times 1000", and lower-case letters indicating "times 1000000". Zero is indicated by an overline with no character underneath. Thus, the range of (32-bit) output values possible is from through ivccxcivCMLXVIICCXCV. Note: For values whose residues modulo 1000000 are less than 4000, M is used to represent 1000; for values whose residues are 400 or greater, I is used. Thus #3999 would read out as MMMIM while #4000 would read out as IV> Similar rules apply to the use of M and i for 1000000, and to that of m and i for 1000000000. 4.4.4 RESUME The statement PLEASE RESUME exp has the same effect as FORGET, except that program control os returned to the statement immediately following the NEXT statement which stored in the stack the last entry to be removed. Note that a rough equivalent of the FORTRAN computed GO TO and BASIC ON exp GO TO is performed by a sequence of the form: DO (1) EXT . . (1) DO (2) NEXT PLEASE FORGET #1 . . (2) DO RESUME .1 Unlike the FORGET statement, an attempt to RESUME more levels of NEXTing than been stacked will cause program termination. Se also section 4.4.11. 4.4.5 STASH Since subroutines are nit explicitly implemented in INTERCAL, the NEXT and RESUME statements must be used to execute common routines. However, as these routines might use tje sa,e variabless as the ,ain program, it is necessary for them to save the values of any variables whose values they alter, and later restore them. This process is simplified by the STASH state- ment, which has the form DO STASH list, where list represents a string of one or more variable or array names, seperated by intersections (+). Thus PLEASE STASH .123+:123+,123 stashes the values of two variables and one entire array. The values are left intact, and copies thereof are saved for later retrieval by (what else?) the RETRIEVE statement (see section 4.4.6). It is not possible to STASH single array items. 4.4.6 RETRIEVE PLEASE RETRIEVE list restores the previously STASHed values of the variables and arrays named in the list. If a value has been stashed more than once, teh most recently STASHed values are RETRIEVEd, and a second RETRIEVE will restore the second most recent values STASHed. Attempting to RETRIEVE a value which has not been STASHed will result in the error message, "THROW STICK BEFORE RETIEVING." 4.4.7 IGNORE The statement DO IGNORE list causes all subsequent statements to have no effect upon variables and/or arrays named in the list. Thus, for example, after the sequence DO .1 <- #1 PLEASE IGNORE .1 DO .1 <- #0 16-bit variable number 1 would have the value 1, not 0. Inputting (see sec- tion 4.4.12) into an IGNOREd variable also has no effect. The condition is annulled via the REMEMBER statement (see section 4.4.8). Note that, when a variable is being IGNOREd, its value, though immutable, is still avail- able for use in expressions and the like. 4.4.8 REMEMBER PLEASE REMEMBER list terminates the effect of the IGNORE statement for all variables and/or arrays named in the list. It does not matter if a variable has been IGNOREd more than once, nor is it an error of the variable has not been IGNOREd at all. 4.4.9 ABSTAIN INTERCAL contains no simple equivalent to an IF statement or computed GO TO, making it difficult to combine similar sections of code into a single rou- tine which occasionally skips around certain statements. The IGNORE state- ment (see section 4.4.7) is helpful in some cases, but a more viable method is often required. Inkeeping with the goal of INTERCAL having nothing in common with any other language, this is made possible via the ABSTAIN state- ment. This statement takes on one of two forms. It may not take on both at any one time. DO ABSTAIN FROM (label) causes the statement whose logical line label is (label) to be abstained form. PLEASE ABSTAIN FROM gerund list causes all statements of the specified type(s) to be abstained from, as in PLEASE ABSTAIN FROM STASHING PLEASE ABSTAIN FROM IGNORING + FORGETTING PLEASE ABSTAIN FROM NEXTING or PLEASE ABSTAIN FROM CALCULATING Statements may also be automatically abstained from at the start of execu- tion via the NOT nr N'T parameter (see section 4.3). If, in the course of execution, a statement is encountered which is being abstained from, it is ignored and control passes to the next statement in the program (unless it, too, is being abstained from). The statement DO ABSTAIN FROM ABSTAINING is perfectly valid, as is DO ABSTAIN FROM REINSTSTING (altough this latter is not usually recommended.) However, the statement DO ABSTAIN FROM GIVING UP is not accepted, even though DON'T GIVE UP is. 4.4.10 REINSTATE The REINSTATE statement, like the ABSTAIN, takes as an argument either a line label or a gerund list. No other form of argument is permitted. For example, the following is an invalid argument: Given: x=/0, y=/o, Prove: x+y=0 Since x=/0, then x+1=/1, x+a=/a, x+y=/y. Thus x+y =/ anything but 0. Since x+y cannot equal anything but 0, x+y=0. Q.E.D. REINSTATEment nullifies the effects of an abstention. Either form of REIN- STATEment can be used to "free" a statement, regardless of whether the state- ment was abstained from by gerund list, line label, or NOT. Thus, PPLEASE REINSTATE REINSTATING is not necessarily an irrelavant statement, since it might free a DON'T REINSTATE command or a REINSTATE the line label of which was abstained from. However, DO REINSTATE GIVING UP is invalid, and attempt- ing to REINSTATE a GIVE UP statement by line label will have no effect. Note that this insures that DON'T GIVE UP will always be a "do-nothing" statement. 4.4.11 GIVE UP PLEASE GIVE UP is used to exit from a program. It has the effect of a PLEASE RESUME #80. DON'T GIVE UP, as noted in section 4.4.10, is effectively a null statement. 4.4.12 Input Input is accomplished with the statement DO WRITE IN list, where list repre- sents a string of variables and/or elements or arrays, separated by inter- sections. Numbers are represented on cards, each number on a separate card, by spelling out each digit (in English) and separating the digits with one or more spaces. A zero (0) may be spelled as either ZERO or OH. Thus the range of (32-bit) input values permissible extends from ZERO (or OH) through FOUR TWO NINE FOUR NINE SIX SEVEN TWO NINE FIVE. Attempting To write in a value greater than or equal to SIX FIVE FIVE three six for a 16-bit variable will result in the error message, "DON'T BYTE OFF MORE THAN YOOU CAN CHEW." 4.4.13 Output Values may be output to the printer, one value per line, via the statement DO READ OUT list, where the list contains variables, array elements, and/or constants. Output is in the form of "extended"_Roman numerals (also called "butchered Roman numerals), with an overline ( ) indicating the value below is "times 1000", and lower-case letters indicating "times 1000000". Zero is indicated by an overline with no character underneath. Thus, the range of (32-bit) output values possible is from through ivccxcivCMLXVIICCXCV. Note: For values whose residues modulo 1000000 are less than 4000, M is used to represent 1000; for values whose residues are 400 or greater, I is used. Thus #3999 would read out as MMMIM while #4000 would read out as IV> Similar rules apply to the use of M and i for 1000000, and to that of m and i for 1000000000. 4.5 Comments Unrecognizable statements, as noted in section 7, are flagged with a splat (*) during compilation, and are not considered fatal errors unless they areencountered during execution, at which time the atatement (as input at compilation time) is printed and execution is terminated. This allows for an interesting (and, by necessity, unique) means of including comments in an INTERCAL listing. For example, the statement: * PLEASE NOTE THAT THIS LINE HAS NO EFFECT will be ignored during execution due to the inclusion of the NOT qualifier. User-supplied error messages are also easy to implement: * DO SOMETHING ABOUT OVERFLOW IN ;3 as are certain simple conditional errors: * (123) DON'T YOU REALIZE THIS STATEMENT SHOULD ONLY BE ENCOUNTERED ONCE? PLEASE REINSTATE (123) This pair of statements will cause an error exit the second time they are encountered. Caution!! The appearance of a statement identifier in an in- tended comment will be taken as the beginning of a new statement. Thus, the first example on the prceding page could not have been: * PLEASE NOTE THAT THIS LINE DOES NOTHING The third example, however, is valid, despite the appearance of two cases of D-space-0, since INTERCAL does not ignore extraneous spaces in statement identifiers. 5. SUBROUTINE LIBRARY INTERCAL provisws severa; bio;t-in subroutines to which control can be trans- ferred to perform various operations. These operations include many useful functions which are not easily representable in INTERCAL, such as addition, subtraction, etc. 5.1 Usage In general, the operands are .1, .2, etc., or :1, :2, etc., and the result(s) are stored in what would have been the next operand(s). For instance, one routine adds .1 to .2 and store the sum in .3, with .4 being used to indicate overflow. All variables not used for results are left unchanged. 5.2 Available Functions At the time of this writing, only the most fundamental operations are offered in the library, as a more complete selection would require prohibitive time and coree to implement. These function, along with their corresponding entry points (entered via DO (entry) NEXT) are listed below. (1000) .3 <- .1 plus .2, erroe exit on overflow (1009) .3 <- .1 plus .2 .4 <- #1 if no overflow, else .4 <- #2 (1010) .3 <- .1 minus .2, no action on overflow (1020) .1 <- .1 plus #1, no action on overflow (1030) .3 <- .1 times .2, error exit on overflow (1039) .3 <- .1 times .2 .4 <- #1 if no overflow, else .4 <- #2 (1040) .3 <- .1 divided by .2 .3 <- #0 if .2 is #0 (1050) .2 <- :1 divided by .1, error exit on overflow .2 <- #0 if .1 is #0 (1500) :3 <- :1 plus :2, error exit on overflow (1509) :3 <- :1 plus :2 :4 <- #1 if no overflow, else :4 <- #2 (1510) :3 <- :1 minus :2, no action on overflow (1520) :1 <- .1 concatenated with .2 (1525) This subroutine is intended solely for internal use within the subroutine library and is therefore not described here. Its effect is to shift .3 logic- ally 8 bits to the left. (1530) :1 <- .1 times .2 (1540) :3 <- :1 times :2, error exit on overflow (1549) :3 <- :1 times :2 :4 <- #1 if no overflow, else :4 <- #2 (1550) :3 <- :1 divided by :2 :3 <- #0 if :2 is #0 (1900) .1 <- uniform random no. from #1 to #65535 (1910) .2 <- normal random no. from #0 to .1, with standard deviation .1 divided by #12 6. PROGRAMMING HINTS For the user looking to become more familiar with the INTERCAL language, we present in this section an analysis of a complex program, as well as some suggested projects for the ambitious programmer. Considering the effort involved in writing an INTERCAL program, it was decided in putting together this manual to use an already existing program for instructive analysis. Since there was only one such program available, we have proceded to use it. It is known as the "INTERCAL System Library." 6.1 Description The program listing begins on the second page following. It is in the same format as would be produced by the Princeton INTERCAL compiler in FORMAT mode with WDITH=62 (see section 8). For a descriptioon of the functions performed by the Library, see section 5.2. 6.2 Analysis We shall not attempe to discuss here the algorithms used, but rather we shall point out some of the general techniques applicable to a wide range of prob- lems. Statements 10, 14, 15, and 26 make up a virtual "computed GO TO". When state- ment 10 is executed, control passes eventually to statement 16 or 11, de- pending on whether .5 contains #1 or #2, respectively. The value of .5 is determined in statement 9. which demonstrates another handy technique. To turn an expression, exp, with value #0 or #1, into #1 or #1 (for use in a "GO TO"), use "V'exp'c#1"~#3. To reverse the condition (i.e., convert #0 to #2 and leave #1 alone) use "V'exp'c#2"~#3. Certain conditions are easily checked. For example, to test for zero, select the value from itself and select the bottom bit (see statement 54). To test for all bits being 1's, select the value from itself and select the top bit (see statement 261). The test to greater than, performed in statements 192 and 193 on 32-bit values, employs binary logical operations, which are per- formed as follows: 'V.1c.2'~'#0c#65535' for 16-bit values or, for 32-bit values: "'V":1~'#65535c30'"c":2~'#65535c#0'"'~'#0 c#65535'"c"'V":1~'#0c#65535'"c":2~'#0 c#65535'"'~'#0c#65535'" (The proofs are left as an exercise to the reader.) Testing for greater-than with 16-bit values is somewhat simpler and is done with the pair of statements: DO .C <- 'V.Ac.B'~'#0c#65535' DO .C <- '&"'.A~.C'~'"V'V.C~.C'c#32768" ~"#0c#65535"'"c".C~.CZ''ZZZ`#1 This sets .C (a dummy variable) to #1 if .A > .B, and #0 otherwiswe. The expression may be expanded as described above to instead set .C to #1 or #2. Note also in statement 220 the occurance of ~"#65535c65535". Although these operations select the entire value, they are not extraneous, as they ensure that the forthcoming Vs will be operating on 32-bit values. In several vitual computed GO TOs the DO FORGET #1 (statement 15 in the earlier example) has been omitted, since the next transfer of control would be a DO RESUME #1. By making this a DO RESUME #2 instead, the FORGET may be forgotten. In statement 64, note that .2 is STASHed twice by a single statement. This is perfectly legal. Lastly, note in statements 243 and 214 respectively, expressions for shifting 16- and 32-bit variables logically one place to the left. Statement 231 dem- onstrates right-shifting for 32-bit variables. MIKE GETS TO INSERT THE PROGRAM HERE! 6.3 Program Listing 1 (1000) PLEASE IGNORE .4 2 PLEASE ABSTAIN FROM (1005) 3 (1009) DO STASH .1 + .2 + .5 + .6 4 DO .4 <- #1 5 DO (1004) NEXT 6 (1004) PLEASE FORGET #1 7 DO .3 <- 'V.1c.2'~'#0c#65535' 8 DO .6 <- '&.1c.2'~'#0c#65535' 9 PLEASE DO .5 <- "V!6~#32768'c#1"~#3 10 DO (1002) NEXT 11 DO .4 <- #2 12 (1005) DO (1006) NEXT * 13 (1999) DOUBLE OR SINGLE PRECISION OVERFLOW 14 (1002) DO (1001) NEXT 15 (1006) PLEASE FORGET #1 16 DO .5 <- 'V"!6~.6'~#1"c#1'~#3 17 DO (1003) NEXT 18 DO .1 <- .3 19 DO .2 <- !6c#0'~'#32767c#1' 20 DO (1004) NEXT 21 (1003) DO (1001) NEXT 22 DO REINSTATE (1005) 23 (1007) PLEASE RETRIEVE .1 + .2 + .5 + .6 24 DO REMEMBER .4 25 PLEASE RESUME #2 26 (1001) DO RESUME .5 27 (1010) DO STASH .1 + .2 + .4 28 DO .4 <- .1 29 DO .1 <- 'V.2c#65535'~'#0c#65535' 30 DO (1020) NEXT 31 PLEASE DO .2 <- .4 32 PLEASE DO (1009) NEXT 33 DO RETRIEVE .1 + .2 + .4 34 PLEASE RESUME #1 35 (1020) DO STASH .2 + .3 36 DO .2 <- #1 37 PLEASE DO (1021) NEXT 38 (1021) DO FORGET #1 39 DO .3 <- "V!1~.2'c#1"~#3 40 PLEASE DO .1 <- 'V.1c.2'~'#0c#65535' 41 DO (1022) NEXT 42 DO .2 <- !2c#0'~'#32767c#1' 43 DO (1021) NEXT 44 (1023) PLEASE RESUME .3 45 (1022) DO (1023) NEXT 46 PLEASE RETRIEVE .2 + .3 47 PLEASE RESUME #2 48 (1030) DO ABSTAIN FROM (1033) 49 PLEASE ABSTAIN FROM (1032) 50 (1039) DO STASH :1 + .5 51 DO (1530) NEXT 52 DO .3 <- :1~#65535 53 PLEASE DO .5 <- :1~'#65280c#65280' 54 DO .5 <- 'V"!5~.5'~#1"c#1'~#3 55 DO (1031) NEXT 56 (1032) DO (1033) NEXT 57 DO (1999) NEXT 58 (1031) DO (1001) NEXT 59 (1033) DO .4 <- .5 60 DO REINSTATE (1032) 61 PLEASE REINSTATE (1033) 62 DO RETRIEVE :1 + .5 63 PLEASE RESUME #2 64 (1040) PLEASE STASH .1 + .2 + .2 + :1 + :2 + :3 65 DO .2 <- #0 66 DO (1520) NEXT 67 DO STASH :1 68 PLEASE RETRIEVE .2 69 DO .1 <- .2 70 DO .2 <- #0 71 PLEASE DO (1520) NEXT 72 DO :2 <- :1 73 DO RETRIEVE .1 + .2 + :1 74 DO (1550) NEXT 75 PLEASE DO .3 <- :3 76 DO RETRIEVE :1 + :2 + :3 77 DO RESUME #1 78 (1050) PLEASE STASH :2 + :3 + .5 79 DO :2 <- .1 80 PLEASE DO (1550) NEXT 81 DO .5 <- :3~'#65280c#65280' 82 DO .5 <- 'V"!5~.5'~#1"c#1'~#3 83 DO (1051) NEXT 84 DO (1999) NEXT 85 (1051) DO (1001) NEXT 86 DO .2 <- :3 87 PLEASE RETRIEVE :2 + :3 + .5 88 DO RESUME #2 89 (1500) PLEASE ABSTAIN FROM (1502) 90 PLEASE ABSTAIN FROM (1506) 91 (1509) PLEASE STASH :1 + .1 + .2 + .3 + .4 + .5 + .6 92 DO .1 <- :1~#65535 93 PLEASE DO .2 <- :2~#65535 94 DO (1009) NEXT 95 DO .5 <- .3 96 PLEASE DO .6 <- .4 97 DO .1 <- :1~'#65280c#65280' 98 DO .2 <- :2~'#65280c#65280' 99 DO (1009) NEXT 100 DO .1 <- .3 101 PLEASE DO (1503) NEXT 102 DO .6 <- .4 103 DO .2 <- #1 104 DO (1009) NEXT 105 DO .1 <- .3 106 DO (1501) NEXT 107 (1504) PLEASE RESUME .6 108 (1503) DO (1504) NEXT 109 (1501) DO .2 <- .5 110 DO .5 <- 'V"'&.6c.4'~#1"c#2'~#3 111 DO (1505) NEXT 112 (1506) DO (1502) NEXT 113 PLEASE DO (1999) NEXT 114 (1505) DO (1001) NEXT 115 (1502) DO :4 <- .5 116 DO (1520) NEXT 117 DO :3 <- :1 118 PLEASE RETRIEVE :1 + .1 + .2 + .3 + .4 + .5 .6 119 DO REINSTATE (1502) 120 DO REINSTATE (1506) 121 PLEASE RESUME #3 122 (1510) DO STASH :1 + :2 + :4 123 DO :1 <- "'V/":2~'#65535c#0'"c#65535'~'#0c#6553 5'"c"'V":2~'#0c#65535'"c#65535'~'#0c65535 '" 124 DO :2 <- #1 125 DO (1509) NEXT 126 PLEASE RETRIEVE :1 127 DO :2 <- :3 128 PLEASE DO (1509) NEXT 129 DO RETRIEVE :2 + :4 130 PLEASE RESUME #1 131 (1520) PLEASE STASH .3 + .4 132 DO .3 <- .1~#43690 133 DO (1525) NEXT 134 PLEASE DO .4 <- 'V.3c".2~#43690"'~'#0c#65535' 135 DO .3 <- .1~#21845 136 PLEASE DO (1525) NEXT 137 DO :1 <- .4c"'V.3c".2~#21845"'~'#0c#65535'" 138 PLEASE RETRIEVE .3 + .4 139 DO RESUME #1 140 (1525) DO .3 <- '"'"'"!3c#0'~'#32767c#1'"c#0'~'#32767 c#1'"c#0'~'#16383c#3'"c#0'~'#4095c#15' 141 PLEASE RESUME #1 142 (1530) DO STASH :2 + :3 + .3 + .5 143 DO :1 <- #0 144 DO :2 <- .2 145 DO .3 <- #1 146 DO (1535) NEXT 147 (1535) PLEASE FORGET #1 148 DO .5 <- "V!1~.3'c#1"~#3 149 DO (1531) NEXT 150 DO (1500) NEXT 151 DO :1 <- :3 152 PLEASE DO (1533) NEXT 153 (1531) PLEASE DO (1001) NEXT 154 (1533) DO FORGET #1 155 DO .3 <- !3c#0'~'#32767c#1' 156 DO :2 <- ":2~'#0c#65535'"c"'":2~'#32767c#0'"c# 0'~'#32767c#1'" 157 PLEASE DO .5 <- "V!3~.3'c#1"~#3 158 DO (1532) NEXT 159 DO (1535) NEXT 160 (1532) DO (1001) NEXT 161 PLEASE RETRIEVE :2 + :3 + .3 + .5 162 DO RESUME #2 163 (1540) PLEASE ABSTAIN FROM (1541) 164 DO ABSTAIN FROM (1542) 165 (1549) PLEASE STASH :1 + :2 + :4 + :5 + .1 + .2 + .5 166 DO .1 <- :1~#65535 167 PLEASE DO .2 <- :2~'#65280c#65280' 168 DO .5 <- :1~'#65280c#65280' 169 DO (1530) NEXT 170 DO :3 <- :1 171 DO .2 <- :2~#65535 172 PLEASE DO (1530) NEXT 173 DO :5 <- :1 174 DO .1 <- .5 175 DO (1530) NEXT 176 DO :4 <- :1 177 PLEASE DO :1 <- ":3~'#65280c#65280'"c":5~'652 80c#65280'" 178 DO .5 <- ':1~:1'~#1 179 DO .2 <- :2~'#65280c#65280' 180 DO (1530) NEXT 181 PLEASE DO .5 <- '"':1~:1'~#1"c.5'~#3 182 DO .1 <- :3~#65535 183 DO .2 <- #0 184 DO (1520) NEXT 185 PLEASE DO :2 <- :1 186 PLEASE DO .1 <- :4~#65535 187 DO (1520) NEXT 188 DO (1509) NEXT 189 DO .5 <- !5c":4~#3"'~#15 190 DO :1 <- :3 191 DO :2 <- :5 192 DO (1509) NEXT 193 PLEASE DO .5 <- !5c"4~#3"'~#63 194 DO .5 <- 'V"!5~.5'~#1"c#1'~#3 195 PLEASE RETRIEVE :4 196 (1541) DO :4 <- .5 197 DO (1543) NEXT 198 (1542) DO (1544) NEXT 199 PLEASE DO (1999) NEXT 200 (1543) DO (1001) NEXT 201 (1544) DO REINSTATE (1541) 202 PLEASE REINSTATE (1542) 203 PLEASE RETRIEVE :1 + :2 + :5 + .1 + .2 + .5 204 DO RESUME #2 205 (1550) DO STASH :1 + :4 + :5 + .5 206 DO :3 <- #0 207 DO .5 <- 'V"':2~:2'~#1"c#1'~#3 208 PLEASE DO (1551) NEXT 4.6 Programming Suggestions For the novice INTERCAL programmer, we provide here a list of suggested INTERCAL programming projects: Write an integer exponentiation subroutine. :1 <- .1 raised to the .2 power. Write a double-precision sorting subroutine. Given 32-bit array ;1 of size :1. sort the contents into numerically increasing order, leaving the results in ;1. Generate a table of prime numbers. Put together. a floating-point library, using 32-bit variables to represent floating-point numbers (let the upper half be the mantissa and the lower half be the characteristic). The library should be capable of performing floating-point addition, subtraction, multiplication, and division, as well as the natural logarithm function. Program a Fast Fourier Transform (FFT). This project would probably entail the writing of the floating-point library as well as sine ans cosine functions. Calculate, to :1 places, the value of pi. 7. ERROR MESSAGES Due to INTERCAL's implementation of comment lines (see section 4.5), most error messages are produced during execution instead of during compilation. All errors except those not causing immediate termination of program execution are treated as fatal. 7.1 Format All error messages appear in the following form: ICLnnnI (error message) ON THE WAY TO STATEMENT nnnn CORRECT SOURSE AND RESUBMIT The message varies depending upon the error involved. For undecodable state- ments the message is the statement itself. The second line tells which state- ment would have been executed next had the error not occurred. Note that if the error is due to 80 attempted levels of NEXTing, the statement which would have been executed next need not be anywhere near the statement causing the error. 7.2 Messages Brief descriptions of the different error types are listed below according to message number. 000 An undecodable statement has been encountered in the course of exe- cution. Note that keypunching errors can be slightly disastrous, since if 'FORGET' were misspelled F-O-R-G-E-R, the results would probably not be those desired. Extreme misspellings may have even more surprising conequences. For example, misspelling 'FORGET' R-E-S-U-M-E could have drastic results. 017 An expression contains a syntax error. 079 Improper use has been made of statement identifiers. 099 Improper use has been made of statement identifiers. 123 Program has attempted 80 levels of NEXTing. 129 Program has attempted to transfer to a non-existent line label. 139 An ABSTAIN or REINSTATE statement referances a non-existent line label. 182 A line label has been multiply defined. 197 An invalid line label has been encountered. 200 An expression involves an unidentified variable. 240 An attempt has been made to give an array a dimension of zero. 241 Invalid dimensioning information was supplied in defining or using an array. 275 A 32-bit value has been assigned to a 16-bit variable. 436 A retrieval has been attempted for an unSTASHed value. 533 A WRITE IN statement or interleave (c) operation has produced value requiring over 32 bits to represent. 562 Insufficient data. 579 Input data is invalid. 621 The expression of a RESUME statement evaluated to #0. 632 Program execution was terminated via a RESUME statement instead of GIVE UP. 633 Execution has passed beyond the last statment of the program. 774 A compiler error has occurred (see section 8.1). 778 An unexplainable compiler error has occurred (see J. Lyon or B. Woods). [3] TONSIL A The Official INTERCAL Character Set Tabulated on page XX are all the characters used in INTERCAL, excepting letters and digits, along with their names and interpretations. Also included are several characters not used in INTERCAL, which are presented for complete- ness and to allow for future expansion. _____________________ 3) Since all other reference manuals have Appendices, it was decided that the INTERCAL manual should contain some other type of removable organ. 4) This footnote intentionally unreferenced. _______________________________________________________________________ | | |Character Name Use (if any) | | | | . spot identify 16-bit variable | | : two-spot identify 32-bit variable | | , tail identify 16-bit array | | ; hybrid identify 32-bit array | | # mesh identify constant | | = half-mesh | | ' spark grouper | | ` backspark | | ! wow equivalent to spark-spot | | ? what | | " rabbit-ears grouper | | !` rabbit equivalent to ears-spot | | | spike | | % double-oh-seven percentage qualifier | | - worm used with angles | | < angle used with worms | | > right angle | | ( wax precedes line label | | ) wane follows line label | | [ U turn | | ] U turn back | | { embrace | | } bracelet | | * splat flags invalid statements | | & ampersand[5] unary logical AND | | V V unary logical OR | | (or book) | | V bookworm unary exclusive OR | | (or universal qualifier) | | $ big money | | c change binary mingle | | ~ sqiggle binary select | | _ flat worm | | overline indicates "times 1000" | | + intersection separates list items | | / slat | | \ backslat | | @ whirlpool | | -' hookworm | | ^ shark | | (or simply sharkfin) | | #I[] blotch | |_____________________________________________________________________| Table 2 (top view). INTERCAL character set. __________________________________ 5) Got any better ideas? NOTES ON THE ATARI IMPLEMENTATION The Atari implementation of INTERCAL differs from the original Princeton version primarily in the use of ASCII rather than EBCDIC. Since there is no "change" sign (c) in ASCII, we have substituted the "big money" ($) as the mingle operator. We feel that this correctly represents the increasing cost of software in relation to hardware. (Consider that in 1970 one could get RUNOFF for free, to run on a $20K machine, whereas today a not quite as powerful formatter costs $99 and runs on a $75 machine.) We also feel that there should be no defensible contention that INTERCAL has any sense. Also, since overpunches are difficult to read on the average VDT, the exclusive-or operator may be written ?. This correctly expresses the average person's reaction on first encountering exclusive-or, especially on a PDP-11. Note that in both of these cases, the over-punched symbol may also be used if one is masochistic, or concerned with portability to the Princeton compiler. The correct over-punch for "change" is "c/" and the correct over-punch for V is "V-". These codes will be properly printed if you have a proper printer, and the corresponding EBCDIC code will be produced by the /IBM option on the LIST command. cheers, Mike -- Ken Johnson, AI Applications Institute, 80 South Bridge, Edinburgh EH1 1HN E-mail ken@aiai.ed.ac.uk, phone 031-225 4464 extension 212 `I have read your article, Mr Johnson, and I am no wiser now than when I started'. -- `Possibly not, sir, but far better informed.'