IMP Signal Mechanism Definition
Document_IMP_Signals Version 2.1.0 (2-APR-1985)
Draft for circulation; return to IAY
Copyright (c) 1984
Lattice Logic Ltd
9 Wemyss Place
Edinburgh EH3 6DH
This document is a simplified proposal for the core specification of
the IMP signal facility; it is based on thoughts and discussions
prompted by the first version of "Document_IMP_Signals".
This paper makes no attempt to define the syntax and semantics of the
event mechanism itself, leaving this to the proposed more formal
revision of the IMP language manual, but rather concentrates on the
three questions:
1. What information should be contained in the global record
describing an event?
2. What events should be predefined by the language?
3. How can separately compiled IMP modules cooperate via events?
Changes to the EVENT record
The current format of the global record accessed via the external
EVENT record is:
record format EVENT FM ( -
integer EVENT,
SUB,
EXTRA,
string(255) MESSAGE )
This format allows some user information about the event (EXTRA and
MESSAGE) to be propagated with the signal but is not a general facility.
To avoid user programs having to declare extra "parallel" event
descriptors, the EVENT record should be generalised to allow the
procedure which signals an event to pass an arbitrary amount of
parameter information. Also, implementations may wish to provide
system-specific extra information about the event. It would be tidier
and user programs would be more clearly marked as system-dependent if
such information were grouped into a sub-record of EVENT.
One concrete proposal is as follows:
record format SYS EVENT FM ( {is implementation defined} )
const integer MAX EVENT PARAM
record format EVENT PARAM FM ( string(*) name S or
integer I or
long real R or
record(*) name X )
record(EVENT PARAM FM) array Param(1:MAX EVENT PARAM)
record format EVENT FM ( -
integer EVENT,
SUB,
EXTRA,
string(255) MESSAGE,
record(SYS EVENT FM) SYSTEM,
record(*) name USER, {extra user-defined information}
record(EVENT PARAM FM) array PARAM(1:MAX EVENT PARAM) )
The contents of SYSTEM would be implementation-defined but the record
format SYS EVENT FM and the field EVENT_SYSTEM would always exist.
The value of MAX EVENT PARAM would be implementation-dependent, but
would always be at least (say) five.
The USER record pointer would make the event record format
user-extensible in arbitrary ways. It would be used in cases where it
was inappropriate to represent the required event parameter information
as integer values or pointers to character string values.
Please make suggestions for simplifying or extending the format of
the EVENT record.
Predefined events
The following identifiers for events should be predefined on all
implementations of IMP, i.e. should be part of the core library. These
events must be signalled by all implementations in the circumstances
indicated.
[ADC: The exact circumstances are not yet written down. This will
get done if this proposal meets with general approval.]
Signalling or trapping events by number should be strongly
discouraged. Numeric equivalences are given for some identifiers for
compatibility with previous implementations of IMP.
constant integer PROGRAM STOP = 0
constant integer OVERFLOW = 1
constant integer STORE EXCEEDED = 2
constant integer CONVERSION ERROR = 4
constant integer ARGUMENT ERROR = 5
constant integer RANGE ERROR = 6
constant integer STRING RESOLUTION FAILS = 7
constant integer UNDEFINED VALUE = 8
constant integer INPUT ENDED = 9
constant integer IO ERROR = 10
constant integer JUMP OUT = 11
constant integer USER EVENT = 12 {See next section, "modular programs"}
[IAY requested that the numeric equivalences for the last three
events be added; this has been done].
[IAY: Suggest that event numbers 13..15 be 'reserved'. Note
that this would make some existing programs illegal].
Events and modular programs
Separately compiled packages of external procedures (program modules)
may wish to use the IMP event mechanism to signal a range of error
conditions to calling procedures. Since event numbers must be known at
compile-time, and there are only sixteen of them anyway, it is not
possible to give each package its own unique event number.
To work round this problem, a single event, USER EVENT above, is
dedicated for use by all such packages. A unique sub-event number must
be claimed by a package at runtime (during its initialisation phase)
from a central pool maintained by the IMP runtime library. The
package's subevent number is made available to its callers via an
external integer variable. The EVENT_EXTRA field is used for further
discrimination between the various events which may be signalled by that
package.
The IMP runtime library procedure which dispenses subevent numbers to
be used with the event USER EVENT would be as follows:
integer function spec FACILITY CODE ( string(255) FAC NAME )
[RMM: why not "FACILITY NAME"?]
[ADC: because I think the name should indicate the returned value. I
myself would now prefer the name "MODULE NUMBER" or "MODULE CODE".]
The FAC NAME supplied to FACILITY CODE is a text string which is the
identifier of the package (e.g. "stack_manager", "I/O-Library" etc).
The value returned by FACILITY CODE is a module number, 'n', which can
be used later in statements of the form:
signal USER EVENT, n, m
Where 'm' is a number indicating one of the events detected by this
package. 'm' defaults to zero if not specified.
As an example, consider a small package maintaining a stack data
structure (yawn), which can signal two error conditions: stack overflow
and stack underflow.
Note that as this scheme requires more runtime checking of event
numbers by event handlers, the following code presupposes the existance
of a core IMP library procedure RESIGNAL which will re-signal the
current event as described by the event record.
!
! Package specification (STACK.INC)
!
external routine spec INITIALISE STACK
external routine spec PUSH ( real X )
external routine spec POP ( real name X )
!
! Event identifier
!
external integer spec STACK ERROR
constant integer STACK OVERFLOW = 1 { type of STACK ERROR }
constant integer STACK UNDERFLOW = 2
end of file
!
! STACK package body
!
!
! Private data objects
!
constant integer MAX STACK = 100
own integer SP = 0
own real array STACK(1:MAX STACK)
!
! Externally visible data objects
!
external integer STACK ERROR
!
! Externally visible operations
!
external routine INITIALISE STACK
SP = 0
STACK ERROR = FACILITY CODE("stack_manager")
end
external routine PUSH ( real X )
SP = SP + 1
signal USER EVENT, STACK ERROR, STACK OVERFLOW -
unless 0 < SP <= MAX STACK
STACK(SP) = X
end
external routine POP ( real name X )
signal USER EVENT, STACK ERROR, STACK UNDERFLOW -
unless 0 < SP <= MAX STACK
X = STACK(SP)
SP = SP - 1
end
end of file
!
! Calling program (uses STACK to reverse a list of numbers)
!
begin
include "STACK.INC" { access specifications }
real X
on INPUT ENDED start
begin
integer J
real VAL
on USER EVENT start
if EVENT_SUB = STACK ERROR and
EVENT_EXTRA = STACK UNDERFLOW start
return { from begin...end block }
else
RESIGNAL { some other sort of error -- propagates }
finish
else
cycle { till stack underflows }
POP(VAL)
PRINT(VAL, 5, 3)
NEW LINE
repeat
finish
end
else
INITIALISE STACK
cycle { terminates when INPUT ENDED }
READ(X)
PUSH(X)
repeat
finish
end