Previous: , Up: External Calls to C   [Index]


14.1.11 External Calls and auto

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 NEXTed 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: , Up: External Calls to C   [Index]