Previous: ick_create, Up: External Calls to C [Index]
Because the external calls system merges the
INTERCAL NEXT
stack with the C return
value and data storage stack (note for pedants: the C standards nowhere
mandate the existence of such a stack, or even mention one, but the
restrictions stated in them imply that implementations have to act as
if such a stack existed, because of the way the scoping rules and
recursion work), the external calls system therefore has severe effects
on data that happens to be stored there. (In
INTERCAL terms, imagine what would happen if data
could be stored on the NEXT
stack; if C used the more
sensible system of having a STASH
for each variable, these
problems would never occur in the first place, instead causing an
entirely different set of problems.) Similar considerations apply to
the common nonstandard C extension alloca
, which
dynamically alters the size of the stack; also, in what goes below,
register
variables should be considered to be
auto
, because the compiler may choose to allocate them on
the stack. Theoretical considerations would lead one to conclude that
variable-length arrays should obey most of the same restrictions; in
practice, though, it’s unwise to attempt to mix those with
INTERCAL code at all, except by separating them into
separate functions which aren’t flagged with
ICK_EC_FUNC_START
and use no ick_
-prefixed
identifiers, even indirectly. (They may cause a compile to fail
completely because they don’t mix well with goto
.)
In the description below, INTERCAL commands should be taken to include the equivalent C macros.
NEXT
/NEXT FROM
paired with
RESUME
have the least effect, and the most obvious effect,
on auto
variables in the function that was
NEXT
ed from, which is the same effect that the standard C
function longjmp
has. That is, alloca
storage
stays intact, and auto
variables have their values
‘clobbered’ (that is, their value is no longer reliable and
should not be used) if they changed since the corresponding
NEXT
and are not marked as volatile
. (This is
a very easy restriction to get around, because changing the values of
such variables is quite difficult without using statically-allocated
pointers to point to them (a dubious practice in any case), and
volatile
is trivial to add to the declaration.)
COME FROM
has more restrictions; it deallocates all
alloca
storage in the function that was COME
FROM
, and functions that called it or that called functions that
called it, etc., using C calls (as opposed to NEXT
), and
those invocations of the functions will cease to exist (thus destroying
any auto
variables in them), even in the case of
COMING FROM
a function into the same function.
auto
variables in the function that is come into will
start uninitialised, even if initialisers are given in their
declaration, and it will be a ‘new’ invocation of that
function. (It is quite possible that the uninitialised values in the
auto
variables will happen by chance to have the values
they had in some previous invocation of the function, though, because
they are likely to be stored in much the same region of memory; but it
is highly unwise to rely on this.) Note that volatile
will
not help here. Observant or source-code-reading readers may note that
there is a mention of an ick_goto
in the source code to
C-INTERCAL; this is undocumented and this manual does not
officially claim that such a macro exists (after all, if it did, what
in INTERCAL could it possibly correspond to?), but
if such a macro does exist it obeys the same restrictions as COME
FROM
.
FORGET
is the worst of all in terms of preserving data on
the stack; it deallocates alloca
data and clobbers or
deletes auto
variables in all function invocations that
have come into existence since the NEXT
that created the
topmost remaining NEXT
stack entry was called, or since
the start of the program if the NEXT
stack is emptied, and
the current function will continue in a new invocation.
volatile
is useless in preventing this, because the
relevant parts of the stack where the data were stored are deleted by
the command (that’s what FORGET
does, remove stack).
If any of these data are required, they have to be backed up into
static storage (variables declared with static
or global
variables), or into heap storage (as in with malloc
), or
other types of storage (such as temporary files) which are not on the
stack. (Incidentally, suddenly deleting parts of the stack is excellent
at confusing C debuggers; but even RESUME
and COME
FROM
tend to be sufficient to confuse such debuggers. More
worrying is probably the fact that the C standard provides a portable
method for deleting the stack like that, and in fact the external calls
runtime library is written in standard freestanding-legal C89 (with the
exception of +printflow debug output which requires a
hosted implementation), meaning that in theory it would be possible to
split it out to create an implementation of a C-plus-COME-FROM-and-NEXT
language, and doing so would not be particularly difficult.)
Note that INTERCAL variables are not stored on the C stack, nor are any of the metadata surrounding them, and so are not affected unduly by control flow operations.
Previous: ick_create, Up: External Calls to C [Index]