11 Operand Overloading
**********************
INTERCAL-72 C-INTERCAL CLC-INTERCAL J-INTERCAL
------------------------------------------------------------------------
no version 0.26+ version 0.05+ no
(Operand overloading in C-INTERCAL is nowhere near as advanced as it is
in CLC-INTERCAL. This chapter only explains the partial implementation
used by C-INTERCAL; for a full implementation, see CLC-INTERCAL and its
documentation.)
Operand overloading is a method of using a onespot or twospot variable
as a substitute for an expression. When a variable is overloaded to an
expression (which could be another variable, or something more
complex), any uses of that variable cause the expression to be
substituted instead.
At the beginning of the program, all variables stand for themselves; so
`.1' really does mean `.1', for instance. The meaning of a variable
can be overloaded using the slat operator (`/'), which is the same in
both Princeton and Atari syntax: it is a binary operator whose left
argument must be a onespot or variable and whose right argument can be
any expression. The slat operator returns the true value of its left
argument, but as a side effect, changes the meaning of its left
argument to be its right argument. Here is an example:
DO .1 <- .2/'.3~.4'
The example causes `.2''s true value to be assigned to `.1' (unless of
course `.1' is read-only), but also causes `.2' from then on to
actually mean `'.3~.4'', except when it's the left operand of a slat
operator. So for instance, `DO .1 <- .2' would actually assign
`'.3~.4'' to `.1'. Somewhat confusingly, this also works in the other
direction; `DO .2 <- .1' would assign `.1' to `'.3~.4'', which would
have the effect of changing the values of `.3' and `.4' so that
`'.3~.4'' had the correct value, or throw an error if it couldn't
manage this. (The general rule in this case is that any variable or
constant in the expression that overloads the variable is at risk of
being changed; this is known as a `reverse assignment'. Code like `DO
.1 <- .1/#1' is entirely capable of changing the value of `#1',
although to protect new INTERCAL users C-INTERCAL will refuse to carry
out operations that change the value of constants unless a command-line
switch (*note -v::) is used to give it permission. In C-INTERCAL,
changing the value of a constant only changes meshes with that value,
but in CLC-INTERCAL it can also change non-mesh uses of that constant,
so doing so is not portable anyway.)
When multiple overloading rules are in effect, they are all applied;
overloading `.1' to `'.2~.3'' and `.2' to `'.3$.4'' will cause `.1' to
refer to `''.3$.4'~.3''. However, this expansion stops if this would
cause a loop; to be precise, overloading is not expanded if the
expansion is nested within the same expansion at a higher level (so
`.1/.2' and `.2/.1' together cause `.1' to expand to `.2', which
expands to `.1', which cannot expand any further). In C-INTERCAL, the
expression on the right hand side of a slat is not evaluated and not
expanded by operand overloading.
`STASHING' a variable causes its overloading information to be stashed
too; `RETRIEVING' it causes its overload rule to also be retrieved from
the stash (or any overload rule on the variable to be removed if there
wasn't one when the variable was stashed).
Overloading a onespot variable to a twospot variable or vice versa is
possible, but the results are unlikely to be predictable, especially if
a onespot variable is used to handle a twospot value. Possible
outcomes include truncating the value down to the right bitwidth,
throwing an error if a value outside the onespot range is used, and
even temporarily handling the entire twospot value as long as it
doesn't end up eventually being assigned a value greater than twospot.
Note that reverse assignments can cause unpredictable behaviour if an
attempt is made to reverse-assign the same variable twice in the same
expression. In particular, sequences of commands like `DO .1 <-
.2/'.3$.3' DO .2 <- #6' are liable to succeed assigning garbage to `.3'
rather than failing as they ought to do, and likewise any situation
where a variable is reverse-assigned twice in the same expression may
assign garbage to it. This behaviour is seen as unsatisfactory,
though, and plans exist to improve it for future versions.
12 PIC-INTERCAL
***************
INTERCAL-72 C-INTERCAL CLC-INTERCAL J-INTERCAL
------------------------------------------------------------------------
no version 0.26+ no no
PIC-INTERCAL is a simplified version of INTERCAL designed especially
for embedded systems, designed to minimise code and data usage by
INTERCAL programs so that they can fit on devices whose memory is
measured in bytes rather than megabytes. (It is named after the first
microcontroller for which code was successfully generated, and which
influenced the choices of commands, the PIC16F628 manufactured by
Microchip, and is most likely to be portable to other microcontrollers
in the same range.) C-INTERCAL only compilers as far as C code when
producing PIC-INTERCAL; it is up to the user to find the appropriate
cross-compiler to translate this C into the relevant dialect of machine
code. (Two header files in the distribution, `src/pick1.h' and
`src/pick2.h', don't have any affect on the compiler but are referenced
by the generated code, and the intent is for the user to change them to
suit the behaviour of the PIC compiler used, because these are not as
standardised as C compilers for everyday systems.)
There are several restrictions on PIC-INTERCAL programs:
* It's impossible to store more than one item in the STASH for any
given variable.
* Many errors are not checked at runtime; it is the programmer's job
to ensure that runtime errors are avoided. (The few errors that
are detected will send the program into an infinite loop, as there
is no sensible way to exit from a PIC program.)
* Double-oh-sevens are not randomised, but instead depend merely on
whether the probability given is greater than 50% or not.
* The NEXT stack is limited to 16 entries rather than the usual 80.
* `ABSTAIN' and `REINSTATE' still work, but cannot be computed
`ABSTAIN's, and will not necessarily work when used to affect the
system library or calls to it.
* `READ OUT' and `WRITE IN' don't work. (See below for a
replacement.)
* `COME FROM' and `NEXT FROM' must aim at a label, not an expression
or gerund.
* Multithreading and TriINTERCAL cannot be used on PICs. (Operand
overloading can be used, but only if your PIC cross-compiler
supports function pointers; some don't.)
In order to provide I/O capabilities, a new command `PIN' is available.
It controls up to 16 I/O pins on the PIC or other embedded system; an
I/O pin is capable of receiving or sending voltages to an electrical or
electronic circuit. This explanation assumes that the device being
controlled is a PIC16F628A, and therefore has its pins in two blocks of
8 named `PORTA' and `PORTB'; for other microcontrollers, adapting the
code in `src/pick1.h' is likely to be necessary to tell the compiler
how to control the I/O pins, and the way in which this done will affect
which I/O pins it is that the program will end up being able to
communicate with.
The `PIN' command takes one twospot variable as its argument, like this:
DO PIN :2
The twospot variable is conceptually divided into 4 blocks of 8 bits.
The highet two blocks control the directions of the pins in `PORTB'
(most significant block) and `PORTA' (second most significant block); a
1 on any bit means that the corresponding I/O pin should be set to send
data, and a 0 means that it should be set to receive data. The lower
two blocks control the values on the pins that are sending (and are
ignored for receiving pins); the second least significant block
controls `PORTB' and the least significant block controls `PORTA', with
a 1 causing the program to set the output voltage to that of the
microcontroller's negative voltage supply rail, and a 0 causing the
program to set the output voltage to that of the microcontroller's
positive voltage supply rail. (These voltages may vary on other
systems; consult your system's datasheet and the changes you made to
the header files.) After setting the pins, the `PIN' command then
reads them as part of the same operation, this time setting the values
of the lower blocks that are receiving, rather than setting the pins
from the lower blocks that are sending. However, 1 and 0 bits on all
bits of the twospot variable have the opposite meaning when doing this,
so that 1 means receiving/positive voltage rail and 0 means
sending/negative voltage rail. There is no way to input without
output, or vice versa, but it's trivial to just send the same output
again (which has no effect, because the voltage on sending pins is
maintained at the same level until it is changed), or to ignore the
input received.