"There's glory for you!"
"I don't know what you mean by 'glory,'" Alice said.
Humpty Dumpty smiled contemptuously. "Of course you don't--till I
tell you. I meant 'there's a nice knock-down argument for you!'"
"But 'glory' doesn't mean 'a nice knock-down argument.'" Alice
objected.
"When I use a word," Humpty Dumpty said, in a rather scornful
tone, "it means just what I choose it to mean--neither more nor less."
In this section is described the format of INTERCAL statements.
Statements may be entered in "free format". That is, more than one statement may occur on a single card (or line), and a statement may begin on one card (line) 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 <- ".1$'&:51~"#?1$!12~;&75SUB"?'V.1~
DO .2 <- '"!1$"&';?79SUB",&7SUB:173"'~!?9$
.2'$,&1SUB:5~#33578"'"'"~'#65535$"?'V#&85'"'
#8196'"'~.1"$.2'~'#&5$"'#1279$#4351'~#65535"'
The above statements are obviously meaningless. (For that matter, so are the statements
DO .1 <- ".1$'&:51~"#?1$!12~;&75SUB"?'V.1~
.2'$,&1SUB:5~#33578"'"'"~'#65535$"?'V#&85'"'
DO .2 <- '"!1$"&';?79SUB",&7SUB:173"'~!?9$
#8196'"'~.1"$.2'~'#&5$"'#1279$#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 identifier (see section 4.3) may contain any spaces.
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.
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 executed
each time it is encountered in the course of execution.
Following the qualifiers (or, if none are used, the identifier) must occur one of the 14 valid operations. (Exception: see section 4.5.) These are described individually in the following sections.
The INTERCAL equivalent of the half-mesh (=) in FORTRAN,
BASIC, PL/I, and others, is represented by an angle
(<) followed by a worm (-). This
combination 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 <- '?",1SUB#1#1"$#1'~'#0$#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"$':7~#7'
This is, of course, different from the statement:
;7 <- #7 BY .7 BY ,7SUB"#7$':7~#7'"
INTERCAL also permits the redefining of array dimensioning, which is
done the same way as is the initial dimensioning. All values 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.
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 statement 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 section 4.4.3 and section 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 entries. A program's attempting to initiate an
80th level of NEXTing will result in the fatal error
message, PROGRAM HAS DISAPPEARED INTO THE BLACK LAGOON.
The statement 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 indicated. 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
The statement PLEASE RESUME exp has the same
effect as FORGET, except that program control is 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) NEXT
.
.
(1) DO (2) NEXT
PLEASE FORGET #1
.
.
(2) DO RESUME .1
Unlike the FORGET statement, an attempt to
RESUME more levels of NEXTing than has been
stacked will cause program termination. See also
section 4.4.11.
Since subroutines are not explicitly implemented in INTERCAL, the
NEXT and RESUME statements must be used to
execute common routines. However, as these routines might use the
same variables as the main 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 statement,
which has the form DO STASH list, where
list represents a string of one or more variable or array
names, separated 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.
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, the 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 RETRIEVING.
The statement DO IGNORE list causes all
subsequent statements to have no effect upon variables and/or arrays
named in 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 and
retrieving (see section 4.4.12 and
section 4.4.6) into an ignored variable also has no
effect on the variable, and the values that would have been input or
retrieved are discarded. 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 available for use in expressions
and the like.
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 if the
variable has not been IGNOREd at all.
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 routine which occasionally skips around
certain statements. The IGNORE statement (see
section 4.4.7) is helpful in some cases, but a more
viable method is often required. In keeping with the goal of INTERCAL
having nothing in common with any other language, this is made
possible via the ABSTAIN statement.
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 from. 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
PLEASE ABSTAIN FROM CALCULATING
Statements may also be automatically abstained from at the start of
execution via the NOT or 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 REINSTATING (although this
latter is not usually recommended). However, the statement DO
ABSTAIN FROM GIVING UP is not accepted, even though DON'T
GIVE UP is.
The REINSTATE statement, like 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 not equal to 0, y not equal to 0, Prove: x + y = 0.
Since x does not equal 0, then x + 1 does not equal 1, x + a does not equal a, x + y does not equal y.
But what is y? y is anything but 0.
Thus x + y is not equal to 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 REINSTATEment can be used to "free" a
statement, regardless of whether the statement was abstained from by
gerund list, line label, or NOT. Thus, PLEASE
REINSTATE REINSTATING is not necessarily an irrelevant
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
attempting 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.
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.
Input is accomplished with the statement DO WRITE IN
list, where list represents a string of
variables and/or elements of arrays, separated by intersections.
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. Thus the range of (32-bit) input values
permissible extends from ZERO through FOUR TWO NINE
FOUR NINE SIX SEVEN TWO NINE FIVE. A zero (0) may be spelled
as either ZERO or OH, and, for the
convenience of aviators, C-INTERCAL accepts the spelling
NINER for NINE. In the service of
internationalization, C-INTERCAL also accepts input digits in
Sanskrit, Basque, Tagalog, Classical Nahuatl, Georgian, Kwakiutl, and
Volapuk.
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 YOU CAN CHEW.
The programmer desiring to handle input on a character basis should consider using another language. Failing that, refer to section 5.
Values may be output to the printer (or screen), 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
#3999 would read out as
#4000 would read out as
READ OUT statement can also
be used with arrays to produce other kinds of output; see
section 5.
The earliest known description of the COME FROM statement
in the computing literature is in R. L. Clark, "A linguistic
contribution to GOTO-less programming," Commun. ACM 27 (1984),
pp. 349-350, part of the famous April Fools issue of CACM. The
subsequent rush by language designers to include the statement in
their languages was underwhelming, one might even say nonexistent. It
was therefore decided that COME FROM would be an
appropriate addition to C-INTERCAL.
There are two useful ways to visualize the action of the COME
FROM statement. The simpler is to see that it acts like a
GOTO when the program is traced backwards in time. More
precisely, the statements
(1) DO <any statement>
.
.
.
(2) DO COME FROM (1)
should be thought of as being equivalent to
(1) DO <any statement>
(2) DO GOTO (3)
.
.
.
(3) DO NOTHING
if INTERCAL actually had a GOTO statement at all, which
of course it doesn't.
What this boils down to is that the statement DO COME FROM
(label), anywhere in the program, places a kind of
invisible trap door immediately after statement (label).
Execution or abstention of that statement is immediately followed by
an unconditional jump to the COME FROM, unless the
(label)ed statement is an executed NEXT, in
which case the jump occurs if the program attempts to
RESUME back to that NEXT statement. It is
an error for more than one COME FROM to refer to the same
(label).
Modification of the target statement by ABSTAIN or by the
% qualifier affects only that statement, not the
subsequent jump. Such modifications to the COME FROM
itself, however, do affect the jump. Encountering the COME
FROM statement itself, rather than its target, has no effect.
Unrecognizable statements, as noted in section 9, are flagged with a splat (*) during compilation, and are not considered fatal errors unless they are encountered during execution, at which time the statement (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 intended comment will be taken as the beginning of a new statement. Thus, the first example on the preceding 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-O, since INTERCAL does not ignore extraneous spaces in statement identifiers.
(Note that the C-INTERCAL compiler does not produce a program listing during compilation, this being a rather less necessary feature of a compiler when text files are used in place of punch cards. Thus, the comments regarding splat-flagged lines do not apply to C-INTERCAL.)
* The original INTERCAL-72 manual claimed that #3999
should render as MMMIM, but the C-INTERCAL developers
have been unable to find an algorithm that does this and is consistent
with the rest of the rules.