home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
intercal.zip
/
doc
/
intercal.txt
< prev
next >
Wrap
Text File
|
1996-09-03
|
104KB
|
3,565 lines
TTHHEE IINNTTEERRCCAALL PPRROOGGRRAAMMMMIINNGG LLAANNGGUUAAGGEE
RREEVVIISSEEDD RREEFFEERREENNCCEE MMAANNUUAALL
_D_o_n_a_l_d _R_. _W_o_o_d_s
_a_n_d
_J_a_m_e_s _M_. _L_y_o_n
_C_-_I_N_T_E_R_C_A_L _r_e_v_i_s_i_o_n_s_:
_L_o_u_i_s _H_o_w_e_l_l
_a_n_d
_E_r_i_c _S_. _R_a_y_m_o_n_d
_C_o_p_y_r_i_g_h_t _(_C_) _1_9_7_3 _b_y _D_o_n_a_l_d _R_. _W_o_o_d_s
_a_n_d _J_a_m_e_s _M_. _L_y_o_n
_C_o_p_y_r_i_g_h_t _(_C_) _1_9_9_6 _b_y _E_r_i_c _S_. _R_a_y_m_o_n_d
_R_e_d_i_s_t_r_i_b_u_t_i_o_n _e_n_c_o_u_r_a_g_e_d _u_n_d_e_r _G_P_L
_(_T_h_i_s _v_e_r_s_i_o_n _d_i_s_t_r_i_b_u_t_e_d _w_i_t_h _C_-_I_N_T_E_R_C_A_L _0_._1_5_)
- 1 -
_1_. _I_N_T_R_O_D_U_C_T_I_O_N
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 _O_r_i_g_i_n _a_n_d _P_u_r_p_o_s_e
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.
Eighteen years later (give or take a few months) Eric S.
Raymond perpetrated a UNIX-hosted INTERCAL compiler as a
weekend hack. The C-INTERCAL implementation has since been
maintained and extended by an international community of
technomasochists, including Louis Howell, Steve Swales,
Michael Ernst, and Brian Raiter.
(There was evidently an Atari implementation sometime
between these two; notes on it got appended to the
INTERCAL-72 manual. The culprits have sensibly declined to
identify themselves.)
INTERCAL 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
PL/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 _A_c_r_o_n_y_m
The full name of the compiler is "Compiler Language With No
Pronounceable Acronym", which is, for obvious reasons,
abbreviated "INTERCAL".
_1_._3 _A_c_k_n_o_w_l_e_d_g_m_e_n_t_s
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 -
_2_. _F_U_N_D_A_M_E_N_T_A_L _C_O_N_C_E_P_T_S
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 _S_a_m_p_l_e _P_r_o_g_r_a_m
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 7) were used.
A more detailed analysis of a program is made in section 8
of this manual.
DO (5) NEXT
(5) DO FORGET #1
PLEASE WRITE IN :1
DO .1 <- 'V-":1~'#32768c/#0'"c/#1'~#3
DO (1) NEXT
DO :1 <- "'V-":1~'#65535c/#0'"c/#65535'
~'#0c/#65535'"c/"'V-":1~'#0c/#65535'"
c/#65535'~'#0c/#65535'"
DO :2 <- #1
PLEASE DO (4) NEXT
(4) DO FORGET #1
DO .1 <- "V-':1~:2'c/#1"~#3
DO :1 <- "'V-":1~'#65535c/#0'"c/":2~'#65535
c/#0'"'~'#0c/#65535'"c/"'V-":1~'#0
c/#65535'"c/":2~'#65535c/#0'"'~'#0c/#65535'"
DO (1) NEXT
DO :2 <- ":2~'#0c/#65535'"
c/"'":2~'#65535c/#0'"c/#0'~'#32767c/#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"c/#1'~#3
DO (3) NEXT
PLEASE DO (5) NEXT
(3) DO (2) NEXT
PLEASE GIVE UP
_2_._2 _U_s_e_s _f_o_r _I_N_T_E_R_C_A_L
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
- 3 -
would be a good language for initiating novice programmers.
Perhaps surprising, than, is the fact that it would be more
likely to initiate a novice into a search for another line
of work. As it turns out, INTERCAL is more useful (which
isn't saying much) as a challenge to professional
programmers. Those who doubt this need only refer back to
the sample program in section 2.1. This 22-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 anyone 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 65536 in a 32-bit INTERCAL
variable is:
DO :1 <- #0c/#256
any sensible programmer would say that that was absurd.
Since this is indeed 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 having been correct.
- 4 -
_3_. _D_E_S_C_R_I_P_T_I_O_N
The examples of INTERCAL programming which have appeared in
the preceding 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 present here a
description of INTERCAL.
_3_._1 _V_a_r_i_a_b_l_e_s
INTERCAL allows only 2 different types of variables, the
1166--bbiitt iinntteeggeerr and the 3322--bbiitt iinntteeggeerr.. 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 respective 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 may NOT be written as 1E-3.
_3_._2 _C_o_n_s_t_a_n_t_s
CCoonnssttaannttss are 16-bit values only and may range from 0 to
65535. They are prefixed by a mesh (#). Caution! Under no
circumstances confuse the mesh with the interleave operator,
except under confusing circumstances!
_3_._3 _A_r_r_a_y_s
AArrrraayyss are represented 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 constructions, which are resolved as discussed in
section 3.4.3. Definition of array dimensions will be
discussed later in greater detail, since 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 _O_p_e_r_a_t_o_r_s
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.
_3_._4_._1 _B_i_n_a_r_y _O_p_e_r_a_t_o_r_s
The binary operators are iinntteerrlleeaavvee (also called mmiinnggllee) and
sseelleecctt, which are represented by a change (c/) and a sqiggle
- 5 -
[sic] (~), respectively. (In C-INTERCAL'S ASCII
environment, EBCDIC c/ is replaced by a big money ($).)
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 to the right in the result. Both operands are
automatically padded on the left with zeros to 32 bits
before the selection takes place, so the variable types are
unrestricted. If more than 16 bits are selected, the result
is a 32-bit value, otherwise 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.
_3_._4_._1_._1 _R_e_t_u_r_n _t_y_p_e _o_f _S_E_L_E_C_T
INTERCAL-72 defined the return type of a SELECT operation to
depend on the number of bits SELECTed. The C-INTERCAL
compiler takes the easier route of defining the return type
to be that of the right operand, independent of its actual
value. This form has the advantage that all types can be
determined at compile time. Putting in run time type
checking would add significant overhead and complication, to
effect a very minor change in language semantics.
The only time this distinction makes any difference is when
a unary operator is applied to the SELECT result. This
happens extremely rarely in practice, the only known
instance being the 32-bit greater-than test in the standard
library, where an XOR operator is applied to the result of
SELECTing a number against itself. The INTERCAL-72 authors
first SELECT the result against #65535c/#65535 to insure that
XOR sees a 32-bit value. With the current compiler this
extra step is unnecessary, but harmless.
The cautious programmer should write code that does not
depend on the compiler version being used. We therefore
suggest the following guideline for determining the SELECT
return type:
A SELECT operation with a 16-bit right operand returns a
16-bit value. The return type of a SELECT operation with a
32-bit right operand is undefined, but is guaranteed to be
an acceptable input to a MINGLE operation so long as 16 or
fewer bits are actually selected. Correct code should not
- 6 -
depend on whether the return type is 16 or 32 bits.
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
operation 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 symbolically by '0',
'1', '?', and 'O|'. Note in particular that, while NOT-0 is
1 and NOT-1 is 0 as in two-valued logic, NOT-? is ? and
NOT-O| is O|. The functions of the various gates are listed in
Table 1.
[Warning: The following picture will be garbled or missing.
Get a better output device.]
- 7 -
--+-+---- --+---- +--+---- --+---- +--+----
A1 | | 1 +-+--+-+ 2 +-++-+ 3 ++-+-+ 3 ++|--+ 1 +--
B --+++ | |--+-+ | || | ||||++ |||| | | TO
1 +++------++-+-+------+|-+--- +++++-----++|-+--- ---NEW
+-------++-+---------+-------+++++-----+ | YORK
+-+------++-+-+-----+ | +---- ||| +-----+ | +---- TO
A2 --+-+ | || +-+ || --+ |+++-+ |+-+-+ | ---NEW
--+-+ 1 +-++-+-+ 2 +++--+ 7 +-++-+ 3 +--+-+ 2 +-- YOTROK
B2 |-+--- |||+-+--- || -+--- |+-+------++-+------- ---NEW
+--------+++-+------++---------+--------+|+--------- YORK
+-+------+++-++-----++--+-----+| ++-----++--+-----+ TO
A --+-+ | +++-++ |++--+ |++-++ ||+--+ || B ---NEW
3 | 1 +-+++-+| 2 +-++-+ 3 +-++++ 3 ++++-+ 3 ++- YORK
B3 --+-+--- ||||+++--- |||-+--- ++|++--- ||+++--- | TO
+-------++++++------+++-------++++------++++------+-U ---NEW
+-+-----+++-+++-----+++-+-----+++|| ++++| | YORK
A --+-+----|||| ||+----||++-+----||++++----|+++++----|| S TO
4 | 1 +++++|++ 2 ++++-+ 7 ++++++ 3 ++++-+ 4 ++- ---NEW
B --+-+--- ||||+-+--- ||+-+--- |||++--- ++--++--- | YOTROK
4 | |||+++ ++--+ +---++++++++++|+-+------+ ---NEW
+-------+++-++-------++++-+--+||+++++++-++++--+ YORK
--+-+-----+++-+++-----+++++-+--+++-++++++ +++++-+-- L TO
A5 | 1 ++++++++ 2 ++++++ 3 +++ ++ 3 +-++++ 5 +-- ---NEW
B --+-+ |||+++++ | ||| ||| || |++++| | YORK
5 |-+--- |||||++-------|++----+|+--+-----+++++-------I TO
+-------+++++--------++------++++ +--- |+++ ---NEW
+-+-----+++++-+-----+|| +----++++++-----+|||+---- N YORK
A6 --+-+ |||-++++ |+++-+ |+++++ | ++++ | TO
--+-+ 1 +++-++++ 2 ++++-+ 3 +-++++ 4 ++++++ 4 +-- ---NEW
B6 |-+--- +++++++--- +++-+-----+||++-----+++++-------E YORK
+--------++++--------++------+||| ++-+ ---TO
+-+------++++-+-----+|| +----++++++---- || +---- NEW
A --+-+ | -+++-+ |+++-+ |+++++ ||+--+ | YOTROK
7 | 1 +--+|+-+ 2 +-++-+ 3 ++|+++ 4 ++-+-+ 5 +-- ---NEW
B7 --+-+--- ||++-+--- ||++--- || ++--- --+++--- YORK
+----+---++++--------+++------++ +------+-++------+- TO
+-+--+---++++-+-------+|| | || | || | ---NEW
A --+-+----| |+++-+----|+-+++----|+--++----||+--+----|| YORK
8 | 1 +-+ |+-+ 2 ++ +++ 4 ++ +++ 3 ++++-+ 5 ++-8 TO
B --+-+--- +--+--- | ++--- | |++--- | |-+--- | ---NEW
8 +----------------+ ++-+ +-++---+ ++-+------+| YORK
+--+++--------+|| +-++++------++- TO
+---- +-+--+-----+++-+---- ++++----+|++-+----++- ---NEW
| 6 +-+ +--+ 2 ++-+-+ 7 +-++-+ 3 +++|++ 4 ++- YOTROK
| | -+--+ |+---+ | | | || ||| || --P-HILA-
-+--- | -+--- -+--- |-+--- +-+++--- | DELPHIA
+---------------------+---------+-------+-
+---- |+--+---------+------++-+-----+ +----
| | ++--+ | +-+ | |--+ ||+--+ |
| 6 +--++--+ 1 +-++-+ 1 +-+--+ 1 +++--+ 1 ++
-+--- -+--- --++-+--- | -+--- | -+-----+-
--- ---
FIGURE 1. CIRCUITOUS DIAGRAM
- 8 -
__________________________________________________________
|\ \
| \ 1. Logic gate. Inputs A, B. Output O = AB. \
| \ \
| \ \ 2. Logic gate. Inputs A, B, C. Output O = A+BC. \
| |\ \ \
| | \ \ 3. Logic gate. Inputs A, B. Output O = A+AB. \
| | \ \ \
| | |\ \ 4. Logic gate. Inputs A, B. Output O = AB O+ -(A+-B) \
| | | \ \ \
| | | \ \ 5. Logic gate. Inputs A, B. Output O = AO+A + AA \
| | | \ \ \
| | | \ \ 6. Uninitialized flip-flop. Inputs none. Output O = ? \
| | | \ \ \
| | | \ \ 7. Flip-flop-flap. Inputs A, B, C. Output O = 1 if \
| | | \ \ A=0 or B+C=0 and A=1. O = 0 if AC=1, B=0. O = O| if \
| | | \ \ AB=1, C=0. O = ? if ABC=1. O as yet undetermined \
| | | \ \ for other Warmenhovian inputs. See Figure 2. \
| | | \ \ \
| | | \ \ 8. Bus line. \
| | | \ \_________________________________________________________\
| | | \ | |
| | | | | _____________________________________________________ |
| | | | | | | | | | | |
| | | | | | | | | | | |
| | | | | | | | | | | |
| | | | | | | | | | | |
| | | | | | | | | | | |
\|__| | | | \|__| | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
\|__| \|__|
Table 1. Logical (and other) functions.
- 9 -
[Warning: The following picture will be garbled or missing.
Get a better output device.]
-------------------------+----
A +---+ |----+------------D
| | | |
+----
| | |
+---+---- |
B-------------------------+ |----+ |
+----| | |
| |
| |
| |
| |
| | |
C-------------------------+----| | |
+----------------+ |--+ | |
| +---- | | |
| | | |
| |
| |
| |
| | | | |
| | +-+----| |
| +---+ +- +-------+
| +-+--
1-----+
FIGURE 2. FLIP FLAP FLOP
- 10 -
[Warning: The following picture will be garbled or missing.
Get a better output device.]
-----
----- -----
-----
----- -----
----- -----
-----
----- -----
----- GATE TYPE 9. BLACK BOX
----- 9 ----- INPUTS A1-8, B1-8.
----- OUTPUT D1-8 = A1-8~B1=8
----- -----
-----
----- -----
----- -----
-----
----- -----
-----
FIGURE 1 (CONTINUED). NEW YORK
- 11 -
_3_._4_._2 _U_n_a_r_y _O_p_e_r_a_t_o_r_s
The unary operators are & (logical AANNDD), V (logical OORR), and
V- (logical XXOORR). This last character is obtained by
overpunching a worm (-) on a V (V). (In C-INTERCAL'S ASCII
environment, EBCDIC V- is replaced by the what (?). The
compiler recognizes -<backspace>V as a valid equivalent, in
case you are concerned about compatibility with the
Princeton compiler. The operator is inserted between the
spot, two-spot, mesh, or what-have-you, and the integer,
thus: .&123, #V-123. Multiple 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 0000000000000100 = 4, #V77 is binary
1000000001101111 = 32879, and #V-77 is binary
1000000001101011 = 32875.
_3_._4_._3 _P_r_e_c_e_d_e_n_c_e
Precedence of operators is as follows:
(The remainder of this page intentionally left blank)1
____________________
1. Keep in mind that the aim in designing INTERCAL was to
have no precedents.
- 12 -
This precedence (or lack thereof) may be overruled by
grouping expressions between pairs of sparks (') or rabbit-
ears ("). Thus '#165c/#203'~#358 (binary value
'10100101c/11001011'~101100110) has the value 15, but
#165c/'#203~#358' has the value 34915, 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 as '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 (".) 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 otherwise ambiguous subscripted and multiply-
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
interpretation which is different from that which the user
had in mind. See also section 12.
- 13 -
_4_. _S_T_A_T_E_M_E_N_T_S
In this section is described the format of INTERCAL
statements.
_4_._1 _G_e_n_e_r_a_l _F_o_r_m_a_t
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~"#V-1c!12~;&75SUB"V-'V.1~
DO .2 <- '"!1c/"&';V-79SUB",&7SUB:173"'~!V-9c/
.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~"#V-1c/!12~;&75SUB"V-'V.1~
.2'c/,&1SUB:5~#333578"'"'"~#65535c/"V-'V#&85'"'
DO .2 <- '"!1c/"&';V-79SUB",&7SUB:173"'~!V-9c/
#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 identifier (see section 4.3) may
contain any spaces.
_4_._2 _L_a_b_e_l_s
A statement may begin with a llooggiiccaall lliinnee llaabbeell 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 _I_d_e_n_t_i_f_i_e_r_s _a_n_d _Q_u_a_l_i_f_i_e_r_s
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
- 14 -
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.
_4_._4 _S_t_a_t_e_m_e_n_t_s
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.14.2.
_4_._4_._1 _C_a_l_c_u_l_a_t_e
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 <- '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.
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.
- 15 -
_4_._4_._2 _N_E_X_T
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 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 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."
_4_._4_._3 _F_O_R_G_E_T
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
_4_._4_._4 _R_E_S_U_M_E
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:
- 16 -
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 been stacked will cause program
termination. See also section 4.4.11.
_4_._4_._5 _S_T_A_S_H
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.
_4_._4_._6 _R_E_T_R_I_E_V_E
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."
_4_._4_._7 _I_G_N_O_R_E
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
- 17 -
16-bit variable number 1 would have the value 1, not 0.
Inputting (see section 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
available for use in expressions and the like.
Though the INTERCAL-72 manual laid down that the value of an
IGNOREd variable cannot change, it was unclear about whether
or not a statement which appears to change an IGNOREd
variable is executed or not. This may appear to be a "If a
tree falls in the forest..." type of question, but if the
statement in question has other side effects it is not.
Since another mechanism already exists for ABSTAINing from a
statement, C-INTERCAL's IGNORE only prevents the changing of
the specific variable in question, not the execution of the
entire statement. In the present version of the language
this only makes a difference for the WRITE IN statement.
Attempting to WRITE IN to an IGNOREd variable will cause a
number to be read from the input, which will be discarded
since it cannot be stored in the variable.
_4_._4_._8 _R_E_M_E_M_B_E_R
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.
_4_._4_._9 _A_B_S_T_A_I_N
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
or PLEASE ABSTAIN FROM CALCULATING
- 18 -
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.
_4_._4_._1_0 _R_E_I_N_S_T_A_T_E
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!=0, Prove: x+y=0
Since x!=0, then x+1!=1, x+a!=a, x+y!=y.
But what is y? y is anything but 0.
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 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.
_4_._4_._1_1 _G_I_V_E _U_P
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_._1_2 _I_n_p_u_t
Input is accomplished with the statement DO WRITE IN list,
where list represents a string of variables and/or elements
or 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
- 19 -
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. (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."
_4_._4_._1_3 _O_u_t_p_u_t
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 4000 or greater,
_
I
is used. Thus #3999 would read out as MMMCMXCIX 2 while
#4000 would readout as
__
IV
Similar rules apply to the use of
_
M
and i for 1000000, and to that of m and
_
i
for 1000000000.
____________________
2. 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.
- 20 -
_4_._4_._1_4 _C_O_M_E _F_R_O_M
In which we try to precisely define a statement that should
never have been born, but is nevertheless one of the more
useful statements in INTERCAL.
_4_._4_._1_4_._1 _B_a_c_k_g_r_o_u_n_d
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.
_4_._4_._1_4_._2 _D_e_s_c_r_i_p_t_i_o_n
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 %
- 21 -
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.
_4_._5 _C_o_m_m_e_n_t_s
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.
- 22 -
_5_. _O_U_T_S_I_D_E _C_O_M_M_U_N_I_C_A_T_I_O_N
In which we try to remedy the fact that, due to I/O
limitations, INTERCAL can not even in principle perform the
same tasks as other languages. It is hoped that this
addition will permit INTERCAL users to waste vast quantities
of computer time well into the 21st century.
_5_._1 _M_o_t_i_v_a_t_i_o_n
One of the goals of INTERCAL was to provide a language
which, though different from all other languages, is
nevertheless theoretically capable of all the same tasks.
INTERCAL-72 failed to accomplish this because its I/O
functions could not handle arbitrary streams of bits, or
even arbitrary sequences of characters. A language which
can't even send its input directly to its output can hardly
be considered as capable as other languages.
_5_._2 _T_u_r_i_n_g _T_e_x_t _M_o_d_e_l
To remedy this problem, character I/O is now provided in a
form based on the "Turing Text" model, originally proposed
by Jon Blow. The C-INTERCAL programmer can access this
capability by placing a one- dimensional array in the list
of items given to a WRITE IN or READ OUT statement. On
execution of the statement, the elements of the array will,
from first to last, be either loaded from the input or sent
to the output, as appropriate, in the manner described
below. There is currently no support for I/O involving
higher-dimensional arrays, but some form of graphics might
be a possible 2-D interpretation.
The heart of the Turing Text model is the idea of a
continuous loop of tape containing, in order, all the
characters in the machine's character set. When a character
is received by the input routine, the tape is advanced the
appropriate number of spaces to bring that character under
the tape head, and the number of spaces the tape was moved
is the number that is actually seen by the INTERCAL program.
Another way to say this is that the number placed in an
INTERCAL array is the difference between the character just
received and the previous character, modulo the number of
characters in the machine character set.
Output works in just the opposite fashion, except that the
characters being output come from the other side of the
tape. From this position the characters on the tape appear
to be in reverse order, and are individually backwards as
well. (We would show you what it looks like, but we don't
have a font with backwards letters available. Use your
imagination.) The effect is that a number is taken out of
an INTERCAL array, subtracted from the last character
output--- i.e., the result of the last subtraction---and
- 23 -
then sent on down the output channel. The only catch is
that the character as seen by the INTERCAL program is the
mirror-image of the character as seen by the machine and the
user. The bits of the character are therefore taken in
reverse order as it is sent to the output. Note that this
bit reversal affects only the character seen by the outside
world; it does not affect the character stored internally by
the program, from which the next output number will be
subtracted. All subtractions are done modulo the number of
characters in the character set.
Two different tapes are used for input and for output to
allow for future expansion of the language to include
multiple input and output channels. Both tapes start at
character 0 when a program begins execution. On input, when
an end of file marker is reached the number placed in the
array is one greater than the highest- numbered character on
the tape.
_5_._3 _E_x_a_m_p_l_e _P_r_o_g_r_a_m
If all this seems terribly complicated, it should be made
perfectly clear by the following example program, which
simply maps its input to its output (like a simplified UNIX
"cat"). It assumes that characters are 8 bits long, but
that's fine since the current version of C-INTERCAL does
too. It uses the standard library routines for addition and
subtraction.
DO ,1 <- #1
DO .4 <- #0
DO .5 <- #0
DO COME FROM (30)
DO WRITE IN ,1
DO .1 <- ,1SUB#1
DO (10) NEXT
PLEASE GIVE UP
(20) PLEASE RESUME '?.1$#256'~'#256$#256'
(10) DO (20) NEXT
DO FORGET #1
DO .2 <- .4
DO (1000) NEXT
DO .4 <- .3~#255
DO .3 <- !3~#15'$!3~#240'
DO .3 <- !3~#15'$!3~#240'
DO .2 <- !3~#15'$!3~#240'
DO .1 <- .5
DO (1010) NEXT
DO .5 <- .2
DO ,1SUB#1 <- .3
(30) PLEASE READ OUT ,1
For each number received in the input array, the program
first tests the #256 bit to see if the end of file has been
- 24 -
reached. If not, the previous input character is subtracted
off to obtain the current input character. Then the order
of the bits is reversed to find out what character should be
sent to the output, and the result is subtracted from the
last character sent. Finally, the difference is placed in
an array and given to a READ OUT statement. See? We told
you it was simple!
- 25 -
_6_. _T_r_i_I_N_T_E_R_C_A_L
In which it is revealed that bitwise operations are too
ordinary for hard-core INTERCAL programmers, and extensions
to other bases are discussed. These are not, strictly
speaking, extensions to INTERCAL itself, but rather new
dialects sharing most of the features of the parent
language.
_6_._1 _M_o_t_i_v_a_t_i_o_n
INTERCAL is really a pretty sissy language. It tries hard
to be different, but when you get right down to its roots,
what do you find? You find bits, that's what. Plain old
ones and zeroes, in groups of 16 and 32, just like every
other language you've ever heard of. And what operations
can you perform on these bits? The INTERCAL operators may
arrange and permute them in weird and wonderful ways, but at
the bit level the operators are the same AND, OR and XOR
you've seen countless times before.
Once the prospective INTERCAL programmer masters the unusual
syntax, she finds herself working with the familiar Boolean
operators on perfectly ordinary unsigned integer words.
Even the constants she uses are familiar. After all, who
would not immediately recognize #65535 and #32768? It may
take a just a moment more to figure out #65280, and #21845
and #43690 could be puzzles until she notices that they sum
to #65535, but basically she's still on her home turf. The
16-bit limit on constants actually works in the programmer's
favor by insuring that very long anonymous constants can not
appear in INTERCAL programs. And this is in a language that
is supposed to be different from any other!
_6_._2 _A_b_a_n_d_o_n _A_l_l _H_o_p_e_._._.
Standard INTERCAL is based on variables consisting of
ordinary bits and familiar Boolean operations on those bits.
In pursuit of uniqueness, it seems appropriate to provide a
new dialect, otherwise identical to INTERCAL, which instead
uses variables consisting of trits, i.e. ternary digits, and
operators based on tritwise logical operations. This is
intended to be a separate dialect, rather than an extension
to INTERCAL itself, for a number of reasons. Doing it this
way avoids word-length conflicts, does not spoil the
elegance of the Spartan INTERCAL operator set, and dodges
the objections of those who might feel it too great an
alteration to the original language. Primarily, though,
giving INTERCAL programmers the ability to switch numeric
base at will amounts to excessive functionality. So much
better that a programmer choose a base at the outset and
then be forced to stick with it for the remainder of the
program.
- 26 -
_6_._3 _C_o_m_p_i_l_e_r _O_p_e_r_a_t_i_o_n
The same compiler, ick, supports both INTERCAL and
TriINTERCAL. This has the advantage that future bug fixes
and additions to the language not related to arithmetic
immediately apply to both versions. The compiler recognizes
INTERCAL source files by the extension '.i', and TriINTERCAL
source files by the extension '.3i'. It's as simple as
that. There is no way to mix INTERCAL and TriINTERCAL
source in the same program, and it is not always possible to
determine which dialect a program is written in just by
looking at the source code.
_6_._4 _D_a_t_a _T_y_p_e_s
The two TriINTERCAL data types are 10-trit unsigned integers
and 20-trit unsigned integers. All INTERCAL syntax for
distinguishing data types is ported to these new types in
the obvious way. Small words may contain numbers from #0 to
#59048, large words may contain numbers from #0$#0 to
#59048$#59048. Errors are signaled for constants greater
than #59048 and for attempts to WRITE IN numbers too large
for a given variable or array element to hold.
Note that though TriINTERCAL considers all numbers to be
unsigned, nothing prevents the programmer from implementing
arithmetic operations that treat their operands as signed.
Three's complement is one obvious choice, but balanced
ternary notation is also a possibility. This latter is a
very pretty and symmetrical system in which all 2 trits are
treated as if they had the value -1.
_6_._5 _O_p_e_r_a_t_o_r_s
The TriINTERCAL operators are designed to inherit the
relevant properties of the standard INTERCAL operators, so
that both can be considered as merely different aspects of
the same Platonic ideal. (Not that the word "ideal" is ever
particularly relevant when used in connection with
INTERCAL.)
_6_._5_._1 _B_i_n_a_r_y _O_p_e_r_a_t_o_r_s _I
The binary operators carry over from the original language
with only minor changes. The MINGLE operator ($) creates a
20-trit word by alternating trits from its two 10-trit
operands. The SELECT operator (~) is a little more
complicated, since the ternary tritmask may contain 0, 1,
and 2 trits. If we observe that the SELECT operation on
binary operands amounts to a bitwise AND and some
rearrangement of bits, it seems appropriate to base the
SELECT for ternary operands on a tritwise AND in the
analogous fashion. We therefore postpone the definition of
SELECT until we know what a tritwise AND looks like.
- 27 -
_6_._5_._2 _U_n_a_r_y _O_p_e_r_a_t_o_r_s
The unary operators in INTERCAL are all derived from the
familiar Boolean operations on single bits. To extend these
operations to trits, we first ask ourselves what the
important properties of these operations are that we wish to
be preserved, then design the tritwise operators so that
they behave in a similar fashion.
_6_._5_._2_._1 _U_n_a_r_y _L_o_g_i_c_a_l _O_p_e_r_a_t_o_r_s
Let's start with AND and OR. To begin with, these can be
considered "choice" or "preference" operators, as they
always return one of their operands. AND can be described
as wanting to return 0, but returning 1 if it is given no
other choice, i.e., if both operands are 1. Similarly, OR
wants to return 1 but returns 0 if that is its only choice.
From this it is immediately apparent that each operator has
an identity element that "always loses", and a dominator
element that "always wins".
AND and OR are commutative and associative, and each
distributes over the other. They are also symmetric with
each other, in the sense that AND looks like OR and OR looks
like AND when the roles of 0 and 1 are interchanged (De
Morgan's Laws). This symmetry property seems to be a key
element to the idea that these are logical, rather than
arithmetic, operators. In a three-valued logic we would
similarly expect a three- way symmetry among the three
values 0, 1 and 2 and the three operators AND, OR and (of
course) BUT.
The following tritwise operations have all the desired
properties: OR returns the greater of its two operands.
That is, it returns 2 if it can get it, else it tries to
return 1, and it returns 0 only if both operands are 0. AND
wants to return 0, will return 2 if it can't get 0, and
returns 1 only if forced. BUT wants 1, will take 0, and
tries to avoid 2. The equivalents to De Morgan's Laws apply
to rotations of the three elements, e.g., 0 -> 1, 1 -> 2, 2
-> 0. Each operator distributes over exactly one other
operator, so the property "X distributes over Y" is not
transitive. The question of which way this distributivity
ring goes around is left as an exercise for the student.
In TriINTERCAL programs the whirlpool (@) symbol denotes the
unary tritwise BUT operation. You can think of the
whirlpool as drawing values preferentially towards the
central value 1. Alternatively, you can think of it as
drawing your soul and your sanity inexorably down...
On the other hand, maybe it's best you _n_o_t think of it that
way.
- 28 -
A few comments about how these operators can be used. OR
acts like a tritwise maximum operation. AND can be used
with tritmasks. 0's in a mask wipe out the corresponding
elements in the other operand, while 1's let the
corresponding elements pass through unchanged. 2's in a
mask consolidate the values of nonzero elements, as both 1's
and 2's in the other operand yield 2's in the output. BUT
can be used to create "partial tritmasks". 0's in a mask
let BUT eliminate 2's from the other operand while leaving
other values unchanged. Of course, the symmetry property
guarantees that the operators don't really behave
differently from each other in any fundamental way; the
apparent differences come from the intuitive view that a 0
trit is "not set" while a 1 or 2 trit is "set".
_6_._5_._2_._2 _B_i_n_a_r_y _O_p_e_r_a_t_o_r_s _I_I
At this point we can define SELECT, since we now know what
the tritwise AND looks like. SELECT takes the binary
tritwise AND of its two operands. It shifts all the trits
of the result corresponding to 2's in the right operand over
to the right (low) end of the result, then follows them with
all the output trits corresponding to 1's in the right
operand. Trits corresponding to 0's in the right operand,
which are all 0 anyway, occupy the remaining space at the
left end of the output word. Both 10-trit and 20-trit
operands are accepted, and are padded with zeroes on the
left if necessary. The output type is determined the same
way as in standard INTERCAL.
_6_._5_._2_._3 _U_n_a_r_y _A_r_i_t_h_m_e_t_i_c _O_p_e_r_a_t_o_r_s
Now that we've got all that settled, what about XOR? This
is easily the most-useful of the three unary INTERCAL
operators, because it combines in one package the operations
ADD WITHOUT CARRY, SUBTRACT WITHOUT BORROW, BITWISE NOT-
EQUAL, and BITWISE NOT. In TriINTERCAL we can't have all of
these in the same operator, since addition and subtraction
are no longer the same thing. The solution is to split the
XOR concept into two operators. The ADD WITHOUT CARRY
operation is represented by the new sharkfin (^) symbol,
while the old what (?) symbol represents SUBTRACT WITHOUT
BORROW. The reason for this choice is so that what (?) will
also represent the TRITWISE NOT-EQUAL operation.
Note that what (?), unlike the other four unary operators,
is not symmetrical. It should be thought of as rotating its
operand one trit to the right (with wraparound) and then
subtracting off the trits of the original number. These
subtractions are done without borrowing, i.e., trit-by-trit
modulo 3.
- 29 -
_6_._5_._3 _E_x_a_m_p_l_e_s
The TriINTERCAL operators really aren't all that bad once
you get used to them. Let's look at a few examples to show
how they can be used in practice. In all of these examples
the input value is contained in the 10-trit variable .3.
In INTERCAL, single-bit values often have to be converted
from {0,1} to {1,2} for use in RESUME statements. Examples
of how to do this appear in the original manual. In
TriINTERCAL the expression "^.3$#1"~#1 sends 0 -> 1 and 1 ->
2. If the 1-trit input value can take on any of its three
possible states, however, we will also have to deal with the
2 case. The expression "V.3$#1"~#1 sends {0,1} -> 1 and 2
-> 2. To test if a trit is set, we can use
"V'"&.3$#2"~#1'$#1"~#1, sending 0 -> 1 and {1,2} -> 2. To
reverse the test we use "?'"&.3$#2"~#1'$#1"~#1, sending 0 ->
2 and {1,2} -> 1. Note that we have not been taking full
advantage of the new SELECT operator. These last two
expressions can be simplified into "V!3~#2'$#1"~#1 and
"?!3~#2'$#1"~#1, which perform exactly the same mappings.
Finally, if we need a 3-way test, we can use
"@'"^.3$#7"~#4'$#2"~#10, which obviously sends 0 -> 1, 1 ->
2, and 2 -> 3.
For an unrelated example, the expression
"^.3$.3"~"#0$#29524" converts all of the 1-trits of .3 into
2's and all of the 2-trits into 1's. In balanced ternary,
where 2-trits represent -1 values, this is the negation
operation.
_6_._6 _B_e_y_o_n_d _T_e_r_n_a_r_y_._._.
While we're at it, we might as well extend this multiple
bases business a little farther. The ick compiler actually
recognizes filename suffixes of the form '.Ni', where N is
any number from 2 to 7. 2 of course gives standard
INTERCAL, while 3 gives TriINTERCAL. We cut off before 8
because octal notation is the smallest base used to
facilitate human-to-machine communication, and this seems
quite contrary to the basic principles behind INTERCAL. The
small data types hold 16 bits, 10 trits, 8 quarts, 6 quints,
6 sexts, or 5 septs, and the large types are always twice
this size.
As for operators, '?' is always SUBTRACT WITHOUT BORROW, and
'^' is always ADD WITHOUT CARRY. 'V' is the OR operation
and always returns the max of its inputs. '&' is the AND
operation, which chooses 0 if possible but otherwise returns
the max of the inputs. '@' is BUT, which prefers 1, then 0,
then the max of the remaining possibilities. Rather than
add more special symbols forever, a numeric modifier may be
placed directly before the '@' symbol to indicate the
operation that prefers one of the digits not already
- 30 -
represented. Thus in files ending in '.5i', the permitted
unary operators are '?', '^', '&', '@', '2@', '3@', and 'V'.
Use of such barbarisms as '0@' to represent '&' are not
permitted, nor is the use of '@' or '^' in files with either
of the extensions '.i' or '.2i'. Why not? You just can't,
that's why. Don't ask so many questions.
As a closing example, we note that in balanced quinary
notation, where 3 means -2 and 4 means -1, the negation
operation can be written as either
DO .1 <- "^'"^.3$.3"~"#0$#3906"'$'"^.3$.3"~"#0$#3906"'"~"#0$#3906"
or as
DO .1 <- "^.3$.3"~"#0$#3906"
DO .1 <- "^.1$.1"~"#0$#3906"
These work because multiplication by -1 is the same as
multiplication by 4, modulo 5.
Now go beat your head against the wall for a while.
- 31 -
_7_. _S_U_B_R_O_U_T_I_N_E _L_I_B_R_A_R_Y
INTERCAL provides several built-in subroutines to which
control can be transferred to perform various operations.
These operations include many useful functions which are not
easily representable in INTERCAL, such as addition,
subtraction, etc.
_7_._1 _U_s_a_g_e
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.
_7_._2 _A_v_a_i_l_a_b_l_e _F_u_n_c_t_i_o_n_s
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 functions, along with their corresponding
entry points (entered via DO (entry) NEXT) are listed below.
- 32 -
(1000) .3 <- .1 plus .2, error 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
(1060) .3 <- logical or of .1 and .2
(1070) .3 <- logical and of .1 and .2
(1080) .3 <- logical xor of .1 and .2
(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
logically 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 #0 to #65535
(1910) .2 <- normal random no. from #0 to .1, with
standard deviation .1 divided by #12
_7_._3 _A_u_t_o_m_a_g_i_c_a_l _I_n_c_l_u_s_i_o_n _O_f _T_h_e _S_u_b_r_o_u_t_i_n_e _L_i_b_r_a_r_y
The C-INTERCAL compiler will automatically include the
system library if a DO (1xxx) NEXT statement is used, and if
no (1xxx) labels are defined anywhere, where (1xxx) is a
label in the 1000-1999 range, inclusive. This was not an
INTERCAL-72 feature.
- 33 -
_8_. _P_R_O_G_R_A_M_M_I_N_G _H_I_N_T_S
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
proceeded to use it. It is known as the "INTERCAL System
Library."
_8_._1 _D_e_s_c_r_i_p_t_i_o_n
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 WIDTH=62 (see section
12). For a description of the functions performed by the
Library, see section 7.2.
_8_._2 _A_n_a_l_y_s_i_s
We shall not attempt to discuss here the algorithms used,
but rather we shall point out some of the general techniques
applicable to a wide range of problems.
Statements 10, 14, 15, and 26 make up a virtual "computed GO
TO". When statement 10 is executed, control passes
eventually to statement 16 or 11, depending 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 #2 (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 for greater than, performed in
statements 192 and 193 on 32-bit values, employs binary
logical operations, which are performed as follows:
'V-.1c/.2'~'#0c/#65535'
for 16-bit values or, for 32-bit values:
"'V-":1~'#65535c/30'"c/":2~'#65535c/#0'"'~'#0
c/#65535'"c/"'V-":1~'#0c/#65535'"c/":2~'#0
c/#65535'"'~'#0c/#65535'"
- 34 -
(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~.C"'~#1
This sets .C (a dummy variable) to #1 if .A > .B, and #0
otherwise. The expression may be expanded as described above
to instead set .C to #1 or #2.
Note also in statement 220 the occurrence of
~"#65535c/#65535". Although these operations select the
entire value, they are not extraneous, as they ensure that
the forthcoming V-s will be operating on 32-bit values.
In several virtual 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 demonstrates right-
shifting for 32-bit variables.
- 35 -
_8_._3 _P_r_o_g_r_a_m _L_i_s_t_i_n_g
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
- 36 -
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
- 37 -
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'~'#0c/#65535
'"
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'"
- 38 -
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
209 DO :4 <- #1
- 39 -
210 PLEASE DO (1553) NEXT
211 (1553) DO FORGET #1
212 DO .5 <- 'V-":2~'#32768c/#0'"c/#2'~#3
213 DO (1552) NEXT
214 DO :2 <- ":2~'#0c/#65535'"c/"'":2~'#32767c/#0'"c/#
0'~'#32767c/#1'"
215 PLEASE DO :4 <- ":4~'#0c/#65535'"c/"'":4~'#32767
c/#0'"c/#0'~'#32767c/#1'"
216 DO (1553) NEXT
217 (1552) DO (1001) NEXT
218 (1556) PLEASE FORGET #1
219 DO :5 <- "'V-":1~'#65535c/#0'"c/":2~'#65535c/#0'"'
~'#0c/#65535'"c/"'V-":1~'#0c/#65535'"c/":2~'#0c/
#65535'"'~'#0c/#65535'"
220 DO .5 <- 'V-"'&"':2~:5'~'"'V-"'V-":5~:5"~"#65535~
#65535"'~'#65535c/#0'"c/#32768'~'#0c/#65535'"
c/"'V-":5~:5"~"#65535c/#65535"'~'#0c/#65535'"'
"c/"':5~:5'~#1"'~#1"c/#2'~#3
221 DO (1554) NEXT
222 DO :5 <- :3
223 DO (1510) NEXT
224 PLEASE DO :1 <- :3
225 DO :3 <- "'V":4~'#65535c/#0'"c/":5~'#65535c/#0'"'
~'#0c/#65535'"c/"'V":4~'#0c/#65535'"c/":5~'#0c/
#65535'"'~'#0c/#65535'"
226 DO (1555) NEXT
227 (1554) PLEASE DO (1001) NEXT
228 (1555) DO FORGET #1
229 DO .5 <- "V-':4~#1'c/#2"~#3
230 DO (1551) NEXT
231 DO :2 <- ":2~'#0c/#65534'"c/":2~'#65535c/#0'"
232 DO :4 <- ":4~'#0c/#65534'"c/":4~'#65535c/#0'"
233 PLEASE DO (1556) NEXT
234 (1551) DO (1001) NEXT
235 PLEASE RETRIEVE :1 + :4 + :5 + .5
236 PLEASE RESUME #2
237 (1900) DO STASH .2 + .3 + .5
238 DO .1 <- #0
239 DO .2 <- #1
240 PLEASE DO (1901) NEXT
241 (1901) DO FORGET #1
242 DO %50 .1 <- 'V.1c/.2'~'#0c/#65535'
243 DO .2 <- !2c/#0'~'#32767c/#1'
244 PLEASE DO .5 <- "V-!2~.2'c/#1"~#3
245 DO (1902) NEXT
246 DO (1901) NEXT
247 (1902) DO (1001) NEXT
248 DO RETRIEVE .2 + .3 + .5
249 PLEASE RESUME #2
250 (1910) PLEASE STASH .1 + .3 + .5 + :1 + :2 + :3
251 DO .3 <- #65524
252 DO :1 <- #6
253 DO (1911) NEXT
* 254 PLEASE NOTE THAT YOU CAN'T GET THERE FROM HERE
- 40 -
255 (1912) DO (1001) NEXT
256 (1911) DO FORGET #1
257 PLEASE DO (1900) NEXT
258 DO :2 <- .1
259 DO (1500) NEXT
260 PLEASE DO :1 <- :3
261 DO .1 <- .3
262 DO (1020) NEXT
263 PLEASE DO .3 <- .1
264 DO .5 <- 'V-"!3~.3'~#1"c/#2'~#3
265 DO (1912) NEXT
266 DO .1 <- #12
267 PLEASE DO (1050) NEXT
268 DO RETRIEVE .1
269 DO (1530) NEXT
270 DO :2 <- #32768
271 DO (1500) NEXT
272 PLEASE DO .2 <- :3~'#65280c/#65280'
273 PLEASE RETRIEVE .3 + .5 + :1 + :2 + :3
274 DO RESUME #1
275 (1060) DO .3<-'V".1c/.2"'~'#0c/#65535'
276 (1070) DO .3<-'&".1c/.2"'~'#0c/#65535'
277 (1080) DO .3<-'V-".1c/.2"'~'#0c/#65535'
- 41 -
_8_._4 _P_r_o_g_r_a_m_m_i_n_g _S_u_g_g_e_s_t_i_o_n_s
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 and cosine functions.
Calculate, to :1 places, the value of pi.
(The first three and last one of the preceding suggested
projects from the INTERCAL-72 manual are included in the C-
INTERCAL distribution's pit directory of sample code. The
floating-point library and FFT routine remain as worthy
challenges...)
- 42 -
_9_. _E_R_R_O_R _M_E_S_S_A_G_E_S
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.
_9_._1 _F_o_r_m_a_t
All error messages appear in the following form:
ICLnnnI (error message)
ON THE WAY TO STATEMENT nnnn
CORRECT SOURCE AND RESUBMIT
The message varies depending upon the error involved. For
undecodable statements the message is the statement itself.
The second line tells which statement 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.
_9_._2 _M_e_s_s_a_g_e_s
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 execution. 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 consequences. 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 references a non-
existent line label.
182 A line label has been multiply defined.
- 43 -
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 a 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 statement of the
program.
774 A compiler error has occurred (see section 12).
778 An unexplainable compiler error has occurred.
The following error codes are new in C-INTERCAL:
111 You tried to use a C-INTERCAL extension with the
`traditional' flag on.
127 Can't find syslib.i file when it's needed for magical
inclusion.
222 Out of stash space.
333 Too many variables.
444 A COME FROM statement references a non-existent line
label.
555 More than one COME FROM references the same label.
666 Too many source lines.
777 No such source file.
- 44 -
888 Can't open C output file
999 Can't open C skeleton file.
998 Source file name with invalid extension (use .i or
.[3-7]i).
997 Illegal possession of a controlled unary operator.
- 45 -
_1_0_. _T_h_e _C_-_I_N_T_E_R_C_A_L _C_o_m_p_i_l_e_r
_1_0_._1 _C_h_a_r_a_c_t_e_r _S_e_t
The C-INTERCAL compiler uses ASCII rather than EBCDIC. We
follow the Atari implementation by (a) replacing the change
sign (c/) with big money ($) as the mingle operator, and (b)
replacing the bookworm (V-) symbol with what (?) as the
exclusive-or operator.
_1_0_._2 _U_s_a_g_e _a_n_d _C_o_m_p_i_l_a_t_i_o_n _O_p_t_i_o_n_s
To compile an INTERCAL program `foo.i' to executable code,
just do
ick foo.i
There's a -c option that leaves the generated C code in
place for inspection (suppressing compilation to machine
code), a -d option that enables verbose parse reporting from
the yacc/bison parser, a -t option that requires strict
INTERCAL-72 compliance (rejecting COME FROM and the
extensions for bases other than two), a -b option that
disables the INTERCAL-72 random-bug feature (E774), and an
-O option that enables the (hah!) optimizer. Invoking ick
-? prints a usage message.
Another compilation switch affects C-INTERCAL's runtime
behavior. The `-C' option forces output in "clockface"
mode, for superstitious users who believe writing "IV"
upside-down offends IVPITER and would rather see IIII.
_1_0_._3 _R_u_n_t_i_m_e _O_p_t_i_o_n_s
Every C-INTERCAL runtime also accepts certain options at
runtime. These include [+/-]help, [+/-]traditional, and
[+/-]wimpmode. The help option (with either + or -)
triggers a 'usage' message. The +traditional option is
presently a no-op.
Steve explains: "The wimpmode option is the most
interesting. I found myself always running my test programs
with filters on both ends to work around the 'nifty'
INTERCAL number representations. This was so painful that I
decided it would be LESS painful (and a lot less code) if I
added a 'wimp' option. With the +wimpmode option, the user
is subjected to a humiliating message about what a wimp he
or she is to use this mode, but after that is allowed to use
conventional numerical notation. While such a mode
doubtless violates to some extent the INTERCAL philosophy,
the fact that a 'unbutcher' command has been posted clearly
indicates the need for it. Anyway... if you don't like it,
don't use it... the default is -wimpmode (i.e. NOT wimp
mode)."
- 46 -
_1_0_._4 _P_L_E_A_S_E _P_o_l_i_t_e_s_s_e _C_h_e_c_k_i_n_g
A feature of INTERCAL-72 not documented in the original
manual was that it required a certain level of politesse
from the programmer. If fewer than 1/5th of the program
statements included the PLEASE qualifier, the program would
be rejected as insufficiently polite. If more than 1/3rd of
them included PLEASE, the program would be rejected as
excessively polite.
This check has been implemented in C-INTERCAL. To assist
programmers in coping with it, the intercal.el mode included
with the distribution randomly expands "do " in entered
source to "DO PLEASE" or "PLEASE DO" 1/4th of the time.
- 47 -
_1_1_. _T_h_e _A_t_a_r_i _I_m_p_l_e_m_e_n_t_a_t_i_o_n
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<backspace>/" and the correct over-punch for V- is
"V<backspace>-". 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.
- 48 -
_1_2_. _T_h_e _P_r_i_n_c_e_t_o_n _C_o_m_p_i_l_e_r
The Princeton compiler, written in SPITBOL (a variant of
SNOBOL), performs the compilation in two stages. First the
INTERCAL source is converted into SPITBOL source, then the
latter is compiled and executed.
It should be noted that the Princeton compiler fails to
properly interpret certain multiply-subscripted expressions,
such as:
",1SUB",2SUB#1"#2"
This is not a "bug". Being documented, it is merely a
"restriction". Such cases may be resolved by alternating
sparks and ears in various levels of expression nesting:
",1SUB',2SUB#1'#2"
which is advisable in any case, since INTERCAL expressions
are unreadable enough as is.
Since there is currently no catalogued procedure for
invoking the compiler, the user must include the in-line
procedure shown on the following page in his job before the
compilation step. Copies of this in-line procedure may be
obtained at any keypunch if the proper keys are struck.
The compiler is then executed in the usual manner:
// EXEC INTERCAL[,PARM='parameters']
//COMPILE.SYSIN DD *
{INTERCAL source deck}
/*
//EXECUTE.SYSWRITE DD *
{input data}
/*
The various parameters are described following the in-line
procedure. At most one parameter from each set may apply to
a given compilation; if more than one are specified, the
results are undefined, and may vary depending upon the
particular set of options. The default parameters are
underlined.
- 49 -
//INTERCAL PROC
//COMPILE EXEC PGM=INTERCAL
//STEPLIB DD DSN=U.INTERCAL.LIBRARY,DISP=SHR
// DD DSN=SYS1.FORTLIB,DISP=SHR
//SYSPRINT DD SYSOUT=A,DCB=(BLKSIZE=992,LRECL=137,RECFM=VBA)
//SYSPUNCH DD DUMMY
//SCRATCH DD DSN=&COMPSET,UNIT=SYSDA,SPACE=(CYL,(3,1)),DISP=(,PASS)
//EXECUTE EXEC PGM=EXECUTE,COND=(4,LT) 3
//SOURCES DD DSN=U.INTERCAL.SOURCES,DISP=SHR
//STEPLIB DD DSN=U.INTERCAL.LIBRARY,DISP=SHR
// DD DSN=SYS5.SPITLIB,DISP=SHR
// DD DSN=SYS1.FORTLIB,DISP=SHR
//SYSIN DD DSN=&COMPSET,DISP=(OLD,DELETE)
//SYSOBJ DD SYSOUT=B,DCB=(BLKSIZE=80,LRECL=80,RECFM=F)
//SYSPRINT DD SYSOUT=A,DCB=(BLKSIZE=992,LRECL=137,RECFM=VBA)
//SYSPUNCH DD DUMMY
// PEND
Figure 3. Inline procedure for using INTERCAL.
OOPPTT
NOOPT
In the default mode, the compiler will print a list of
all options in effect, including the defaults for
unspecified parameter groups and the effective option
for those sets where one was specified. If NOOPT is
requested, it causes the default mode to be assumed.
OOPPTTSSUUBB
NOOPTSUB
NOSUB
Unless 'NOOPTSUB' is requested, the System Library is
optimized, resulting in much more rapid NOSUB
processing of function calls. Specifying NOOPTSUB
causes the non-optimized INTERCAL code shown in section
6.3 to be used, whereas NOSUB requests that the System
Library be omitted altogether.
IAMBIC
PPRROOSSEE
The IAMBIC parameter permits the programmer to use
poetic license and thus write in verse. If the reader
does not believe it possible to write verse in
____________________
3. Pending acquisition of SPITBOL release 3.0, the SOURCES
DD card must be replaced by the five cards:
//NOOPTPFX DD DSN=U.INTERCAL.SOURCES(NOOPTPFX),DISP=SHR
//NOOPTSUB DD DSN=U.INTERCAL.SOURCES(NOOPTSUB),DISP=SHR
//OPTPFX DD DSN=U.INTERCAL.SOURCES(OPTPFX),DISP=SHR
//OPTSUB DD DSN=U.INTERCAL.SOURCES(OPTSUB),DISP=SHR
//PRELIM DD DSN=U.INTERCAL.SOURCES(PRELIM),DISP=SHR
- 50 -
INTERCAL, he should send the authors a stamped, self-
addressed envelope, along with any INTERCAL program,
and they will provide one which is verse.
FFOORRMMAATT
NOFORMAT
In FORMAT mode, each statement printed is put on a
separate line (or lines). In NOFORMAT mode, the free-
format source is printed exactly as input. In this
latter case, statement numbers are provided only for
the first statement on a card, and they may be only
approximate. Also, unrecognizable statements are not
flagged.
SEQ
NNOOSSEEQQ
If the source deck has sequence numbers in columns 73
through 80, specifying 'SEQ' will cause them to be
ignored.
SOURCE
NNOOSSOOUURRCCEE
If NOSOURCE is selected, all source listing is
suppressed.
LIST
NNOOLLIISSTT
If LIST is specified, the compiler will provide a list
of statement numbers catalogued according to type of
statement. The compiler uses this table to perform
abstentions by gerund.
WIDTH=nn
This sets the width (in number of characters) of the
output line for FORMAT mode output. The default is 113322..
CODE
NNOOCCOODDEE
Include 'CODE' in the parameter list to obtain a
listing of the SPITBOL code produced for each INTERCAL
statement.
LINES=nn
This determines the number of lines per page, during
both compilation and execution. The default is 6600..
DECK
NNOODDEECCKK
Selecting 'DECK' will cause the compiler to punch out a
SPITBOL object deck which may then be run without
reinvoking the INTERCAL (or SPITBOL) compiler.
KKIIDDDDIINNGG
- 51 -
NOKIDDING
Select NOKIDDING to eliminate the snide remarks which
ordinarily accompany INTERCAL error messages.
GGOO
NOGO
Specifying 'NOGO' will cause the program to be
compiled but not executed. EXECUTE/NOEXECUTE may be
substituted for GO/NOGO, but this will result in an
error, and GO will be assumed.
BBUUGG
NOBUG
Under the default, there is a fixed probability of a
fatal compiler bug being worked at random into the
program being compiled. Encountering this bug during
execution results in error message 774 (see section
7.2). This probability is reduced to zero under
'NOBUG'. This does not affect the probability
(presumably negligible) of error message 778.
_1_2_._1 _O_t_h_e_r _I_N_T_E_R_C_A_L _C_o_m_p_i_l_e_r_s
There are no other INTERCAL compilers. 4
____________________
4. This assertion in the INTERCAL-72 manual was blatantly
contradicted by some notes on an Atari implementation
included at the end of the manual. So, you expect
compiler manuals to be consistent?
- 52 -
TTOONNSSIILL AA
The Official INTERCAL Character Set
Tabulated on page 53 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
completeness and to allow for future expansion.
____________________
4. Since all other reference manuals have Appendices, it was
decided that the INTERCAL manual should contain some
other type of removable organ.
4. 5 This footnote intentionally unreferenced.
- 53 -
+-----------------------------------------------------------------------+
| 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 _u_n_a_r_y _e_x_l_u_s_i_v_e _O_R _(_A_S_C_I_I_) |
|" 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 |
|& ampersand7 unary logical AND |
|V V (or book) unary logical OR |
|V- bookworm (or universal qualifier) unary exclusive OR |
|$ big money _b_i_n_a_r_y _m_i_n_g_l_e _(_A_S_C_I_I_) |
|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) |
|#*[] blotch |
+--------T-a-b-l-e--2--(-t-o-p--v-i-e-w-)-.--I-N-T-E-R-C-A-L--c-h-a-r-a-c-t-e-r--s-e-t-.---------------------+
____________________
7. Got any better ideas?