The Perl INTERCAL compiler

... Statements

The statements are described in an order which minimises forward references. In other words, the first time you read this page go from beginning to end. For easy reference, an alphabetic list follows. A splat (*) in the alphabetic list is a statement not found in INTERCAL-72.

Comments

Any statement which cannot be recognised is simply inserted in the compiled program. Executing this statement is very likely to be an error, however one can make sure the comments are ABSTAINed FROM (see below), so they won't be executed.

The following statement is initially ABSTAINed FROM (because of the word "NOT" as a prefix of "NOTE"):

    PLEASE NOTE THAT WE DO NOT KNOW WHAT WE ARE TALKING ABOUT
(in fact, this example contains two statements, but this is OK as they are both ABSTAINed FROM). If a comment is executed, it is printed as an error message. For example,
    DO YOU REALISE THAT USING INTERCAL IS BAD FOR YOUR SANITY?
    PLEASE DO SOMETHING ELSE.
would print itself and terminate the program.

If you ask the compiler to produce a program listing, it will flag comments with a splat (*) in column 1, followed by a three digit error code, which might help you to figure out why the statement has been treated as a comment, in case you had other ideas. The above programs list as:

     STMT #          (LABEL)         STATEMENT

*0   I                               PLEASE NOTE THAT WE 
*0   II                              DO NOT KNOW WHAT WE ARE TALKING ABOUT
and
     STMT #          (LABEL)         STATEMENT

*0   I                               DO YOU REALISE THAT USING INTERCAL IS BAD
*0                                   FOR YOUR SANITY?
*0   II                              PLEASE DO SOMETHING ELSE.
The error code 0 means that the statement has not been recognised. Other error codes are listed in the chapter about Errors.

Calculate

This statement has the form of a register name, a left arrow (<-) and an expression. The effect is to assign the value of the expression to the register.

Examples:
.1 <- #3
,1 SUB .1 .2 <- .3~#3

If the left-hand side contains an array without subscripts, this statement will dimension the array (or redimension it, throwing away the old contents). In this case, it is possible to specify multidimensional arrays by including more than one expression, separated by the keyword "BY".

Example:
,1 <- #3 BY #4 BY .1

IGNORE

The keyword "IGNORE" is followed by a list of registers, separated by intersection (+). After this, any attempt to modify the values of the registers will be silengly ignored (but any side effect will still happen, so if you try to WRITE IN an ignored register you discard one card from the input).

Note that you can IGNORE whole arrays, but not single subscripts.

The effect of IGNORE ceases when a REMEMBER lists the same registers.

Examples:
IGNORE .1 + ,1 + :3
IGNORE $49.99

Quantum INTERCAL allows the programmer to set the "ignore" state of a variable to both true and false symultaneously, for example:
IGNORE .1 + ,1 + :3 WHILE REMEMBERING THEM
IGNORE $49.99 WHILE REMEMBERING IT
This is described in more detail in the chapter about Quantum INTERCAL.

REMEMBER

The keyword is followed by a list of registers, separated by intersection (+). It undoes the effect of an IGNORE on those registers, so subsequent changes will affect them. It is not an error to REMEMBER a register which had not been IGNOREd. It is possible to follow the list with WHILE IGNORING THEM to produce a program which symultaneously remembers and ignores the registers: see the chapter about Quantum INTERCAL.

ABSTAIN FROM

This is followed by either a label or a list of gerunds separated by intersection (+). The statement corresponding to that label, or all statements corresponding to the gerunds, will not be executed from now on (until a REINSTATE is executed).

It is not possible to ABSTAIN FROM GIVING UP. If you ABSTAIN FROM a label, and that happens to be a GIVE UP statement, this is silently ignored.

For example, the following program will assign 12 to register .1

    PLEASE ABSTAIN FROM (1)
(1) DO ABSTAIN FROM CALCULATING + ABSTAINING
    DO .1 <- #12
    DO ABSTAIN FROM (2)
(2) DO .1 <- #4
    PLEASE GIVE UP
It is possible to ABSTAIN FROM ABSTAINING. It is also possible to ABSTAIN FROM REINSTATING, although we do not recommend it.

The presence of a negative (NOT, N'T or ¬) before a statement will cause it to be initially ABSTAINED FROM, so the above program is equivalent to:

    DO NOT ABSTAIN FROM CALCULATING + ABSTAINING
    DO .1 <- #12
    DO NOT .1 <- #4
    PLEASE GIVE UP
Which in turn is the same as:
    DO .1 <- #12
    PLEASE GIVE UP
In fact, this is what the optimiser in CLC-INTERCAL produces when it sees the first program. Note that the equivalence is not true if there are COME FROMs or NEXT pointing at label (1) or (2), or if there is any computed COME FROM (the optimiser knows that, but it also knows how to get rid of some computed COME FROMs, and can figure out if some COME FROMs can never point at some labels).

CLC-INTERCAL 1.-94 introduced ABSTAIN FROM COMMENT, which ABSTAINs from anything the compiler finds unparseable. THere is a corresponding REINSTATE COMMENTING.

If you have a quantum computer, you can symultaneously ABSTAIN and REINSTATE a statement or a list of gerunds:

    PLEASE ABSTAIN FROM (1) WHILE REINSTATING IT
(1) DO ABSTAIN FROM CALCULATING + ABSTAINING WHILE REINSTATING THEM
    DO ABSTAIN FROM CALCULATING WHILE REINSTATING IT
    PLEASE GIVE UP
This is described in more detail in the chapter about Quantum INTERCAL.

One last extension (in CLC-INTERCAL 0.05) allows to specify an expression instead of a label; and a statement template instead of a gerund. For example:

    DO ABSTAIN FROM REGISTER <- EXPRESSION
                  + REMEMBER REGISTER LIST
		  + IGNORE REGISTER LIST
is equivalent to:
    DO ABSTAIN FROM CALCULATING + REMEMBERING + IGNORING
However, statement templates give finer control than gerunds. For example, after:
    DO ABSTAIN FROM ABSTAIN FROM LABEL + REINSTATE GERUND LIST
an "ABSTAIN FROM (2)" or "REINSTATE ABSTAINING" would be ignored, but "ABSTAIN FROM REINSTATING" and "REINSTATE (3)" would be still executed.

REINSTATE

Followed by a label or a list of gerunds, undoes the effects of ABSTAINING FROM these statements. CLC-INTERCAL 0.05 or later allows an expression instead of a label.

You can REINSTATE REINSTATING, and it does make sense - maybe you want to make sure that any REINSTATE which was ABSTAINED FROM by label is REINSTATEd. You cannot REINSTATE GIVING UP, not even by label.

Quantum program might wish to add WHILE ABSTAINING FROM IT (or WHILE ABSTAINING FROM THEM). See the chapter about Quantum INTERCAL.

CLC-INTERCAL 0.05 and newer allows to REINSTATE templates, with a syntax similar to ABSTAIN FROM templates.

CLC-INTERCAL 1.-94 allows to REINSTATE COMMENTS. You probably don't want to do that.

COME FROM

This is the main program control statement in CLC-INTERCAL. It is followed by either a label or an expression. When the execution reaches the label (or a label with the same value as the expression), it will run the current statement and then jump to the COME FROM. For example, this is a subroutine call, in which register .1 is used to hold the "return address" and register .2 to hold the "subroutine address":
        DO .1 <- #1000
(100)   DO .2 <- #100
        PLEASE COME FROM .1
        DO .1 <- #0

...

        PLEASE COME FROM .2
        DO .2 <- #0
...
(1000)  DON'T PANIC
The assignment of #100 to .2 causes an immediate jump to the subroutine. At the end of the subroutine, after the no-op (DON'T PANIC does nothing because it is ABSTAINed FROM), the program jumps back to the COME FROM .1. We assign zero to the pointers just after use to avoid problems when the subroutine is called in more than one place.

It is an error to have multiple COME FROMs pointing at the same label. However, if all except one are ABSTAINed FROM, this is not a problem. So the above program can be rewritten as:

        DO REINSTATE (101)
(100)   DO .2 <- #100
(101)   PLEASE DON'T COME FROM (1000)
        DO ABSTAIN FROM (101)

...

        PLEASE COME FROM .2
        DO .2 <- #0
...
(1000)  DON'T PANIC
or even without computed COME FROMs (although this requires to change the subroutine every time you add a call - this way of removing computed COME FROMs is best left to the optimiser):
        DO REINSTATE (1001)
(100)   DO REINSTATE (101)
(101)   PLEASE DON'T COME FROM (1000)
        DO ABSTAIN FROM (101)
        DO ABSTAIN FROM (1001)

...

(1001)  PLEASE DO NOT COME FROM (100)
...
(1000)  DON'T PANIC
The simple program to implement a stack and allow recursive subroutines using this technique is left as an exorcism (sic) to the reader.

CLC-INTERCAL 1.-94 introduces COME FROM GERUND (and NEXT FROM GERUND): for example:

        PLEASE COME FROM COMING FROM
causes an infinite loop because the statement keeps reexecuting (and COMING FROM itself!). Since there are runtime overheads associated with COME FROM GERUND, it must be requested (by using suffix ".gi" or by preloading the compiler add-on "come-from-gerund").

NEXT FROM

Like COME FROM, but it saves the return address, as a NEXT would do. It has the same syntax as COME FROM:
    PLEASE NEXT FROM (666)
    ...
    DO RESUME #1
Just after executing the statement with label (666) the program jumps to the above fragment: at the end, it returns to the statement after the one with the label (666).

NEXT

The keyword must be preceded by a label. It serves the function of the GO TO statement of other languages, and can also be used for subroutine calls. For this reason, it allow to write programs which look just like any other language, and this is a Bad Idea. CLC-INTERCAL considers any programs which use NEXT, FORGET or RESUME as obsolete, and will only run them if you use the appropriate incantation.

Beginning with CLC-INTERCAL 0.05, the label preceding "NEXT" can be replaced by an expression.

The effect of NEXT is to transfer control to the stated label, and also to save a return address in an internal stack. See FORGET and RESUME below for the rest of the story.

This is an example of subroutine call:

        DO (1000) NEXT
...
(1000)  DO ....
        PLEASE RESUME #1

FORGET

Followed by an expression. It evaluates the expression, then removes that many return addresses from the stack managed by NEXT and RESUME. These addresses are simply discarded. If you want to use NEXT as a GO TO, you should FORGET #1 just afterwards so the stack does not overflow.

RESUME

Followed by an expression. It evaluates the expression, then removes that many return addresses from the stack managed by NEXT and FORGET. After that, it jumps to the last return address it removed. So RESUME #1 is a normal return from subroutine, while RESUME #3 is equivalent to FORGET #2 followed by RESUME #1.

STASH

Followed by a list of registers, it copies them to some secret place for safekeeping. You can stash whole arrays, but not single elements (well, you can always assign the element to a register and then STASH that). Note that not just the values are saved: the current BELONGS TO relation, the current overloading, and the current IGNORE/REMEMBER state are also saved. See RETRIEVE for the second half of the story.

RETRIEVE

Followed by a list of registers, it rummages through the STASH until it finds the most recent saved values of these registers, and restores them. These values are removed from the STASH, which effectively acts like a stack (yet another normal programming concept which has managed to creep into INTERCAL, sigh). After RETRIEVE, the register's value, BELONGS TO relation, overloading, and IGNORE/REMEMBER state are restored as they were before the corresponding STASH.

For example, the following program leaves .1, ;1 and ,1 SUB #1 unchanged:

        PLEASE STASH .1 + ;1
        DO .1 <- ,1 SUB #1
        DO STASH .1
        DO ,1 SUB #1 <- #0
        DO ;1 SUB .1 <- #1
...
        PLEASE RETRIEVE .1
        DO ,1 SUB #1 <- .1
        DO RETRIEVE .1 + ;1

GIVE UP

Finishes executing the program, presumably returning to saner things like a shell or perhaps JCL.

ABSTAIN FROM and REINSTATE do not have any effect on GIVE UP. This means that you can always GIVE UP, no matter how badly you've managed to screw up your program. Also, it means that DON'T GIVE UP is guaranteed to be a no-op.

READ OUT

Followed by a register list (arrays can be with or without subscripts), will read the contents of the register to the standard output. See the chapter on Input/Output.

WRITE IN

Followed by a register list (arrays can be with or without subscripts), will write into the register from the standard input. See the chapter on Input/Output.

ENSLAVE

Followed by two registers (without subscripts, if arrays), using the form:
    ENSLAVE .1 TO ,1
it sets the BELONGS TO relation between the first and the second. It is not an error if the first register is already a slave, although it can be confusing. See the chapter on Belongs TO.

FREE

Followed by two registers (without subscripts, if arrays), using the form:
    FREE .1 FROM ,1
it removes the BELONGS TO relation between the first and the second. It is an error if the first register was not a slave of the second. If the first register BELONGed TO more than one register, the other owners remain unchnanged. See the chapter on Belongs TO.

STUDY

Followed by a subject number, a lecture label, and a class name, using a format like:
    STUDY #2 AT (1030) IN CLASS @4
It advertise that the lecture is available. See the chapter on Classes and Lectures.

Beginning with CLC-INTERCAL 0.05, the subject number and the label can be replaced by expressions.

ENROL

Followed by a register (without subscripts, if an array) and a list of subjects, using a format like:
    ENROL .2 TO LEARN #1 + #4 + #5
It looks for a class where these subjects are taught, and makes a note that the register is not a student there. It is an error if no class is found which teaches these subjects, or if there is more than one eligible class. The latter case results in a CLASS WAR error. See the chapter on Classes and Lectures.

Beginning with CLC-INTERCAL 0.05, the subject numbers can be specified as expressions and need not be constant.

LEARNS

Preceded by a register (without subscripts, if an array) and followed by a subject number, as in:
    .2 LEARNS #4
The register must have ENROLled in a class which teaches that subject. The effect is to go to the lecture. The class will be temporarily ENSLAVed to the register. This can be used to replace what other languages call "self" or "this". See the chapter on Classes and Lectures.

Beginning with CLC-INTERCAL 0.05, the subject number can be specified as an expression.

FINISH LECTURE

Used in lectures to return to the statement following the last LEARNS. See the chapter on Classes and Lectures.

GRADUATES

Preceded by a register (if an array, without subscripts), it removes it from the list of students of all classes. The effect is that the register cannot LEARN anything after that, unless he ENROLs again. See the chapter on Classes and Lectures.

CONVERT

Followed by one statement template, the keyword "TO", and another statement template. At runtime, the meaning of the first statement is changed into the meaning of the second. In most back ends, this will be implemented by keeping a list of code refences (or pointer to functions or whatever), and changing them as needed. The statements must be "compatible", i.e. their syntactic definition must use the same terminals. For example, the statement ABSTAIN FROM can contain wither a single LABEL or a GERUND LIST. In the latter form, can only be converted to a REINSTATE. In the form with LABEL, it can be converted to COME FROM, NEXT, or REINSTATE. The statements to do all these conversions are:
    DO CONVERT ABSTAIN FROM GERUND LIST TO REINSTATE GERUND LIST
    DO CONVERT ABSTAIN FROM LABEL TO COME FROM LABEL
    DO CONVERT ABSTAIN FROM LABEL TO LABEL NEXT
    DO CONVERT ABSTAIN FROM LABEL TO REINSTATE LABEL
There is a quantum version of this statement, obtained adding the string "WHILE LEAVING IT UNCHANGED" at the end. This has the effect of doing the conversion but at the same time not doing it. This is described in more detail in the chapter about Quantum INTERCAL.

This statement was introduced in CLC-INTERCAL 0.05.

SWAP

Followed by one statement template, the keyword "AND", and another statement template. At runtime, the meaning of the first statement is changed into the meaning of the second, and vice versa. In most back ends, this will be implemented by keeping a list of code refences (or pointer to functions or whatever), and changing them as needed. The statements must be "compatible", i.e. their syntactic definition must use the same terminals. For example, "CALCULATE" has two terminals, a REGISTER and an EXPRESSION. The other statement which has the same terminals is LEARNS. Therefore, they can be swapped. The two following statements both do the same (and undo each other):
     DO SWAP REGISTER <- EXPRESSION AND REGISTER LEARNS EXPRESSION
     DO SWAP REGISTER LEARNS EXPRESSION AND REGISTER <- EXPRESSION
There is a quantum version of this statement, obtained adding the string "WHILE LEAVING THEM UNCHANGED" at the end. This has the effect of doing the swapping but at the same time not doing it. This is described in more detail in the chapter about Quantum INTERCAL.

This statement was introduced in CLC-INTERCAL 0.05

CREATE

This is the most powerful statement of CLC-INTERCAL, and, by necessity, the most complex. The syntax is described in detail in the chapter about parsers. It extends the C-unlike postprocessor (see the convert and swap statements) in such a way that a complete compiler can be written out of CREATE statements. In fact, CLC-INTERCAL 1.-94 and newer are written this way.

This statement was introduced in CLC-INTERCAL 1.-94.

WHILE

Preceded by a statement, and followed by another one, executes the two symultaneously. The first statement acts as a "loop control" for the second, which is repeated as many times as needed. For example:
    PLEASE STUDY #1 AT (1000) IN CLASS @1
    DO ENROL .1 TO LEARN #1
    DO .1 LEARNS #1 WHILE READ OUT .1
Would keep reading out the value of .1 until the lecture is finished. This might or might not cause disruption to the lecture.

The first statement can be replaced by an expression, in which case the WHILE statement is called "event statement". If the expression can be evaluated, the statement is executed and the program continues as normal. If the expression produces an error, the WHILE is kept in suspended animation until it is possible to execute it. For example:

    DO ,1 <- #2
    PLEASE DO ,1 SUB #1 #1 WHILE ,1 SUB #1 #1 <- #5
    DO ,1 SUB #1 <- #2
    DO ,1 <- #2 BY #2
    DO .1 <- ,1 SUB #1 #1
    DO READ OUT .1
Will read "V". This is because the ",1 SUB #1 #1" produces an error (too many subscripts), but is retried as soon as ,1 is redimensioned, and causes #5 to be assigned to ",1 SUB #1 #1" after dimensioning but before assigning to .1

This statement was introduced in CLC-INTERCAL 0.05


Back