"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
STASH
ed (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 NEXT
ing 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 NEXT
ing stack
and discarded. An attempt to FORGET
more levels of
NEXT
ing 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 NEXT
ing 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
STASH
ed values of the variables and arrays named in the
list. If a value has been stashed more than once, the most
recently STASH
ed values are RETRIEVE
d, and a
second RETRIEVE
will restore the second most recent
values STASH
ed. Attempting to RETRIEVE
a
value which has not been STASH
ed 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 IGNORE
d,
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 IGNORE
d more than once, nor is it an error if the
variable has not been IGNORE
d 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.
REINSTATE
ment nullifies the effects of an abstention.
Either form of REINSTATE
ment 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.