System modules are not compilation modules, in the sense that they do not have an actual definition or implementation provided in a library, or by the user. They encapsulate predefined types, constants and procedures, for which the predefined identifiers are not pervasive.
For information only, the interfaces to system modules are shown informally in this International Standard as definition modules. The required semantics cannot be obtained by interpreting these system definition modules according to the rules for separate modules as given in section 6. In particular, as predefined entities, the procedures and functions of a system module are not assignment-compatible with any procedure type. Also, types appearing as opaque types are system basic types and cannot be used to implement user-defined opaque types.
This International Standard defines five system modules, namely SYSTEM, COROUTINES, TERMINATION, EXCEPTIONS, and M2EXCEPTION.
Change: In Programming in Modula-2 the only system module is SYSTEM and this is described as a pseudo-module. Coroutine facilities have been moved from SYSTEM to the system module COROUTINES in this International Standard.
The system module SYSTEM provides low-level facilities for gaining access to the addresses and the underlying storage of variables, for performing address arithmetic, and for manipulating the representation of values. Programs that use these facilities may be non-portable.
The interface to SYSTEM behaves as if the following were its definition module:
DEFINITION MODULE SYSTEM; (* Gives access to system programming facilities that are probably non portable. *) (* The constants and types define underlying properties of storage *) CONST BITSPERLOC = <implementation-defined constant> ; LOCSPERWORD = <implementation-defined constant> ; TYPE LOC; (* A system basic type. Values are the uninterpreted contents of the smallest addressable unit of storage *) ADDRESS = POINTER TO LOC; WORD = ARRAY [0 .. LOCSPERWORD-1] OF LOC; (* BYTE and LOCSPERBYTE are provided if appropriate for machine *) CONST LOCSPERBYTE = <implementation-defined constant> ; TYPE BYTE = ARRAY [0 .. LOCSPERBYTE-1] OF LOC; PROCEDURE ADDADR (addr: ADDRESS; offset: CARDINAL): ADDRESS; (* Returns address given by (addr + offset), or may raise an exception if this address is not valid. *) PROCEDURE SUBADR (addr: ADDRESS; offset: CARDINAL): ADDRESS; (* Returns address given by (addr - offset), or may raise an exception if this address is not valid. *) PROCEDURE DIFADR (addr1, addr2: ADDRESS): INTEGER; (* Returns the difference between addresses (addr1 - addr2), or may raise an exception if the arguments are invalid or if the address space is non-contiguous. *) PROCEDURE MAKEADR (val: <some type>; ... ): ADDRESS; (* Returns an address constructed from a list of values whose types are implementation-defined, or may raise an exception if this address is not valid. *) PROCEDURE ADR (VAR v: <anytype>): ADDRESS; (* Returns the address of variable v. *) PROCEDURE ROTATE (val: <a packedset type>; num: INTEGER): <type of first parameter>; (* Returns a bit sequence obtained from val by rotating up or down (left or right) by the absolute value of num. The direction is down if the sign of num is negative, otherwise the direction is up. *) PROCEDURE SHIFT (val: <a packedset type>; num: INTEGER): <type of first parameter>; (* Returns a bit sequence obtained from val by shifting up or down (left or right) by the absolute value of num, introducing zeros as necessary. The direction is down if the sign of num is negative, otherwise the direction is up. *) PROCEDURE CAST (<targettype>; val: <anytype>): <targettype>; (* CAST is a type transfer function. Given the expression denoted by val, it returns a value of the type <targettype>. An invalid value for the target value or a physical address alignment problem may raise an exception. *) PROCEDURE TSIZE (<type>; ... ): CARDINAL; (* Returns the number of LOCS used to store a value of the specified <type>. The extra parameters, if present, are used to distinguish variants in a variant record. *) END SYSTEM.
Declaration Semantics
The identifiers available for import from the module SYSTEM shall include the constant identifiers BITSPERLOC, and LOCSPERWORD, the type identifiers LOC, ADDRESS, and WORD, and the procedure identifiers ADDADR, SUBADR, DIFADR, MAKEADR, ADR, ROTATE, SHIFT, CAST, and TSIZE.
In addition, where appropriate for the target hardware architecture, the identifiers available for import from the module SYSTEM shall include the constant identifier LOCSPERBYTE, and the type identifier BYTE.
Note: An implementation may extend the module SYSTEM by including additional types, procedures, variables and constants appropriate to the facilities of the target hardware. The identifiers BYTE and LOCSPERBYTE are, however, reserved for use with appropriate target hardware architectures, and may not be used in SYSTEM with other meanings --- see ???.
Changes:
The module SYSTEM provides the constants BITSPERLOC and LOCSPERWORD. Additionally, if appropriate for the target hardware architecture, the constant LOCSPERBYTE is provided.
Declaration Semantics
The constant identifier BITSPERLOC shall denote the whole number literal value that is the number of bits used in the representation of values of the location type and other types occupying a single location.
The constant identifier LOCSPERWORD shall denote the whole number literal value that is the number of locations used in the representation of values of the type denoted by WORD and other types occupying a single word.
The constant identifier LOCSPERBYTE, if provided, shall denote the whole number literal value that is the number of locations used in the representation of values of the type denoted by BYTE and other types occupying a single byte.
The module SYSTEM provides system storage types to represent uninterpreted storage, and a type to represent logical addresses.
System storage types include the location type, and types based on the location type.
Declaration Semantics
The type identifier LOC shall denote the location type. A value of this type shall correspond to the uninterpreted contents of the smallest addressable unit of storage in an implementation; the value of the call TSIZE(LOC) shall therefore be one.
Notes:
The type denoted by WORD shall be defined in terms of LOC as follows:
LOCSPERWORD = <implementation-defined constant> ; WORD = ARRAY [0 .. LOCSPERWORD-1] OF LOC;
and the value of the call TSIZE(WORD) shall be LOCSPERWORD.
The type denoted by BYTE, if provided, shall be defined in terms of LOC as follows: if TSIZE(BYTE) = 1 then
LOCSPERBYTE = 1; BYTE = LOC;
and if TSIZE(BYTE) > 1 then
LOCSPERBYTE = <implementation-defined constant> ; BYTE = ARRAY [0 .. LOCSPERBYTE-1] OF LOC;
and the value of the call TSIZE(BYTE) shall be LOCSPERBYTE.
Declaration Semantics
The declaration:
TYPE ADDRESS = POINTER TO LOC;
shall define the address type. Values of this type shall correspond to the logical addresses of storage locations.
Notes:
The module SYSTEM provides function procedures for address arithmetic (ADDADR, DIFADR, and SUBADDR), for address value generation (MAKEADR and ADR), for packedset operations (ROTATE and SHIFT), for type transfer (CAST), and for determining the storage size of values of a given type (TSIZE).
The function procedures ADDADR, SUBADDR and DIFADR are provided for address arithmetic operations on values of pointer types.
The function ADDADR can be used to construct a value of the address type by adding an offset to the value of a pointer type.
Static Semantics
A call of ADDADR shall have two actual parameters. The first parameter shall be an expression that is of a pointer type, and the second parameter shall be an expression of a type with which the unsigned type is value parameter compatible. The type of a call of ADDADR shall be the address type.
Dynamic Semantics
The value of the call ADDADR(addr, offset) shall be an address calculated by adding offset to addr in an implementation-defined manner that satisfies the properties given in Properties of the address arithmetic functions.
An exception shall be raised if addr is the nil value.
An exception may occur and may be raised if the ADDADR function increments an address out of address range.
Notes:
The function SUBADR can be used to construct a value of the address type by subtracting an offset from the value of a pointer type.
Static Semantics
A call of SUBADR shall have two actual parameters. The first parameter shall be an expression that is of a pointer type, and the second parameter shall be an expression of a type with which the unsigned type is value parameter compatible. The type of a call of SUBADR shall be the address type.
Dynamic Semantics
The value of the call SUBADR(addr, offset) shall be an address calculated by subtracting offset from addr in an implementation-defined manner that satisfies the properties given in Properties of the address arithmetic functions.
An exception shall be raised if addr is the nil value.
An exception may occur and may be raised if the SUBADR function decrements an address out of address range.
Notes:
The function DIFADR can be used to calculate the offset between two addresses, by subtracting the second address from the first.
Static Semantics
A call of DIFADR shall have two actual parameters. Both parameters shall be expressions of a pointer type. The type of a call of DIFADR shall be the signed type.
Note: The two parameters need not be expressions of the same pointer type, since the address type is compatible with all pointer types.
Dynamic Semantics
The value of the call DIFADR(addr1, addr2) shall be a signed number calculated by subtracting addr2 from addr1 in an implementation-defined manner that satisfies the properties given in Properties of the address arithmetic functions.
An exception shall occur if addr1 is the nil value or if addr2 is the nil value.
An exception may occur and may be raised if the result of the DIFADR function is out of the range of the signed type, or if the result is meaningless because the address space is non-contiguous.
Given the declarations VAR adr: ADDRESS; n: CARDINAL; the following shall be true of the address arithmetic func- tion procedures if an exception is not raised:
SUBADR(ADDADR(adr,n), n) = adr ADDADR(SUBADR(adr,n), n) = adr DIFADR(ADDADR(adr,n), adr) = n DIFADR(adr, SUBADR(adr,n)) = n ADDADR(adr, 0) = adr
The function procedures MAKEADR and ADR are provided for the construction and determination of address values.
The function MAKEADR can be used to construct a value of the address type from one or more values of implementation- defined types. The actual number and types of the parameters are not defined in this International Standard in order that implementations may offer one or more alternatives appropriate to the target architecture. On some implementations, one of the parameters might be used to distinguish between the generation of logical addresses and the generation of hardware addresses, such as apply to memory-mapped I/O.
A value constructed by MAKEADR from constant parameters can be used in the optional expression that follows the identifier in a variable declaration to fix the address of storage used for that variable --- see Variable Declarations.
Static Semantics
A call of MAKEADR shall have an implementation-defined number of actual parameters of implementation-defined types. The type of a call of MAKEADR shall be the address type.
Dynamic Semantics
The value of the call MAKEADR(val1, ... valN) shall be an implementation-defined conversion of val1, ... valN. An exception may occur and may be raised if the result is not in address range.
Note: The subsequent use of an address constructed in this way may raise an exception.
The function ADR can be used to obtain the address of a variable.
Static Semantics
A call of ADR shall have one actual parameter that shall be a variable designator. The type of a call of ADR shall be the address type.
Dynamic Semantics
The value of the call ADR(v) shall be the address of the variable v such that if
TYPE Val = ... ; PtoVal = POINTER TO Val; VAR v : Val; p : PtoVal; ... p := ADR(v)
then p^ and v shall designate the same variable.
The functions ROTATE and SHIFT augment the facilities provided by packedset infix operations and packedset relational operations for the bit-level manipulation of values of packedset types.
Values of a packedset type shall be considered as sequences of bits, numbered according to the ordinal values of the members of the the host type of the base type of the packedset. Bit number n is set (i.e. has the value 1) if n is an element of the packedset, and bit number n is unset or clear (has the value 0) if n is not an element of the packedset.
The bit-numbering shall be such that bit number 0 is the least significant bit in a machine register. Bit number 1 is the next least significant bit etc. Adjacent bit numbers shall be adjacent bits in the machine register.
The ordinal values of the lower and upper bounds of the interval used to define a packedset define a bit field within which bit-level operations are to be applied. An implementation may restrict the lower and upper bounds of the interval used to define a packedset --- see ???.
In shift and rotate operations on bit sequences, a move `up' by a number of bit positions will move the bit values within the bit field in the direction of increasing bit numbers; this is also described as a `left' move since bit positions of increasing significance are often shown as being laid out from right to left. Similarly, a move `down', or `right', will move the bit values within the bit field in the direction of decreasing bit numbers. In the case of shift operations, 0 bit values replace those moved away from a boundary of a bit field; in the case of rotate operations, bit values moved out of the bit field at one boundary are moved into the bit field at the other boundary.
Notes:
CAST(CARDINAL,BITSET{0}) = VAL(CARDINAL,1)
and if v is a variable of type CARDINAL, then
CAST(CARDINAL,SHIFT(CAST(BITSET,v),-1)) = v DIV 2
and provided v < = MAX(CARDINAL) DIV 2, then
CAST(CARDINAL,SHIFT(CAST(BITSET,v),1)) = v * 2
The function ROTATE can be used to rotate a bit sequence up or down (left or right) by a specified number of positions within a bit field. The bit sequence is defined by the value of a packedset type, and the direction of rotation is down (right) if the specified number is negative; otherwise the direction is up (left).
Static Semantics
A call of ROTATE shall have two actual parameters. The first parameter shall be an expression that is of a packedset type. The second parameter shall be an expression of a type with which the signed type is value parameter compatible.
The type of a call of ROTATE shall be the type of the first parameter.
An implementation may impose restrictions on the types that are allowed as the first parameter, save that ROTATE will at least accept a value of the type BITSET --- see ??? and The Bitset Type.
Dynamic Semantics
The value of the call ROTATE(val, num) shall be a packedset whose elements are such that the offset of their ordinal values from the ordinal value of the minimum value of the base type of the packedset, is given by the offset of the ordinal values of the elements of val increased by num if it is positive, or decreased by the absolute value of num if it is negative, and scaled by the number of values in the base type.
Note: With the interpretation of a value of a packedset type as a sequence of bits, the rotate operation can be considered as a rotation of the bits upwards (leftwards), or a rotation of the bits downwards (rightwards), according to the value of the second operand, and within the bit field defined by the base type of the packedset.
The function SHIFT can be used to shift a bit sequence up or down (left or right) by a specified number of positions within a bit field. The bit sequence is defined by the value of a packedset type, and the direction of shift is down (right) if the specified number is negative; otherwise the direction is up (left).
Static Semantics
A call of SHIFT shall have two actual parameters. The first parameter shall be an expression that is of a packedset type. The second parameter shall be an expression of a type with which the signed type is value parameter compatible.
The type of a call of SHIFT shall be the type of the first parameter.
An implementation may impose restrictions on the types that are allowed as the first parameter, save that SHIFT will at least accept a value of the type BITSET --- see ??? and The Bitset Type.
Dynamic Semantics
The value of the call SHIFT(val, num) shall be a packedset whose elements are such that the offset of their ordinal values from the ordinal value of the minimum value of the base type of the packedset, is given by the offset of the ordinal values of the elements of val increased by num if it is positive, or decreased by the absolute value of num if it is negative, provided that offset is not negative and is less than the number of values of the base type.
Note: With the interpretation of a value of type packedset as a sequence of bits, the shift operation can be considered as a zero-propagating logical-shift-up (left) operation or a logical-shift-down (right) operation, according to the value of the second operand, and within the bit field defined by the base type of the packedset.
The function CAST can be used (as a type transfer function) to interpret a value of any type other than a numeric literal value as a value of another type.
Change: In Programming in Modula-2 , type transfer is effected by using a type identifier in the role of a function name, as exemplified by CARDINAL(IntExpr).
Static Semantics
A call of CAST shall have two actual parameters. The first parameter shall be a qualified identifier that denotes a type. The second shall be an expression whose type is not that of a numeric literal.
Note: The type of the expression that is the second parameter cannot be a numeric literal type, since such types do not have a defined storage size.
Dynamic Semantics
The value of the call CAST(Type, val) shall be given by a possibly unchecked conversion of val to the type Type in an implementation-defined manner satisfying the properties given below.
If the number of storage units that val occupies is the same as the number of storage units used by a variable of the type Type, the bit pattern representation of the result shall be the same as the bit pattern representation of val; otherwise the result and the value of val shall have the same bit pattern representation for a size that is equal to the smaller of the number of storage units.
An exception may occur and may be raised if a call of CAST causes an implementation-dependent alignment problem to occur, or if the resulting bit pattern is not a valid representation for a value of the target type.
properties
Let ARRAY [0 .. t] OF LOC correspond to Type where t = TSIZE(Type) - 1
Let ARRAY [0 .. v] OF LOC correspond to val where v = TSIZE(type of SourceExpression) - 1
The value of the call CAST(Type, val) shall be a value of type Type that when interpreted as an ARRAY [0 .. t] OF LOC has, for its first min elements, values that are the same as the first min elements of the value of val when interpreted as an ARRAY [0 .. v] OF LOC, where min is the minimum of t and v.
Note: If t > v, the values of remaining elements of the array from v+1 to t are not defined.
If a call of CAST causes an implementation-dependent alignment problem to occur, the following may result: non-mandatory-detection (invalid-alignment) handler
If the resulting bit pattern is not a valid representation for a value of the target type, the following may result: non-mandatory-detection (invalid-value) handler
The function TSIZE can be used to ascertain the amount of storage that is used for a variable of a particular type. There are two versions of this function. The first has a type identifier as a parameter. It returns the size occupied by values of the type in terms of the smallest addressable unit of storage. This version is closely equivalent to the standard function SIZE --- see The Function SIZE. The second version has a record type identifier as the first parameter and one or more constant expressions as the remaining parameters; the values of these constant expressions must be associated with tags of variant components of that record type. It returns the size of the variant record in terms of the smallest addressable unit of storage that would be needed to store a value of the record type, with the tag fields having the values supplied in the call.
Static Semantics
The first, and possibly only parameter, shall be a qualified identifier denoting a type.
If the second and subsequent parameters are present, they shall be constant expressions, and the first parameter shall denote a record type with variant fields. The types of the constant expressions shall correspond to the types of the tag fields contained in the record type.
Note: Values may not be given for the tag fields of any record type embedded within the record type specified as the first parameter.
The type of a call of TSIZE shall be the Z-type.
Dynamic Semantics
The value of the call TSIZE(Type) shall be the size occupied by values of the type Type in terms of the smallest addressable unit of storage.
The value of the call TSIZE(Type, val ... ) shall be the size of the variant record in terms of the smallest addressable unit of storage that would be needed to store values of the record with the tag fields having the values val ....
Auxiliaries
annotations Check that the tag fields contained in a fields-list match the values given by an expression sequence.
annotations Check that the tag fields contained in a fields match the values given by an expression sequence.
annotations Check that the type of the expression in the sequence of tag values is assignment-compatible with the type of the corresponding tag component and the expression that corresponds to any tag field is a constant expression.
annotations Check the tag values in a sequence of values correspond to any tag fields in a variant component.
annotations Calculate the number of tags in a fields-list.
annotations Calculate the number of tags in a fields.
annotations Calculate the number of tags in a variant component of a record structure, selected by the value of the tag field.
annotations Calculates the number of tags in a variant component of a record structure.
The system module COROUTINES provides facilities for creating coroutines, for the explicit transfer of control between coroutines, and for the handling of interrupts by coroutine transfer. Programs that use the interrupt handling facilities may be non-portable since the type used to identify sources of interrupts is implementation-defined.
The interface to COROUTINES behaves as if the following were its definition module.
DEFINITION MODULE COROUTINES; (* Facilities for coroutines and the handling of interrupts *) IMPORT SYSTEM; TYPE COROUTINE; (* Values of this type are created dynamically by NEWCOROUTINE and identify the coroutine in subsequent operations *) INTERRUPTSOURCE = <implementation-defined>; PROCEDURE NEWCOROUTINE (procBody: PROC; workspace: SYSTEM.ADDRESS; size: CARDINAL; VAR cr: COROUTINE[; initProtection: PROTECTION]); (* Creates a new coroutine whose body is given by procBody, and returns the identity of the coroutine in cr. workspace is a pointer to the work space allocated to the coroutine; size specifies the size of this workspace in terms of SYSTEM.LOC. initProtection is an optional parameter that specifies the initial protection level of the coroutine. *) PROCEDURE TRANSFER (VAR from: COROUTINE; to: COROUTINE); (* Returns the identity of the calling coroutine in from, and transfers control to the coroutine specified by to. *) PROCEDURE IOTRANSFER (VAR from: COROUTINE; to: COROUTINE); (* Returns the identity of the calling coroutine in from and transfers control to the coroutine specified by to. On occurrence of an interrupt, associated with the caller, control is transferred back to the caller, and the identity of the interrupted coroutine is returned in from. The calling coroutine must be associated with a source of interrupts. *) PROCEDURE ATTACH (source: INTERRUPTSOURCE); (* Associates the specified source of interrupts with the calling coroutine. *) PROCEDURE DETACH (source: INTERRUPTSOURCE); (* Dissociates the specified source of interrupts from the calling coroutine. *) PROCEDURE IsATTACHED (source: INTERRUPTSOURCE): BOOLEAN; (* Returns TRUE if and only if the specified source of interrupts is currently associated with a coroutine; otherwise returns FALSE. *) PROCEDURE HANDLER (source: INTERRUPTSOURCE): COROUTINE; (* Returns the coroutine, if any, that is associated with the source of interrupts. The result is undefined if IsATTACHED(source) = FALSE. *) PROCEDURE CURRENT (): COROUTINE; (* Returns the identity of the calling coroutine. *) PROCEDURE LISTEN (p: PROTECTION); (* Momentarily changes the protection of the calling coroutine to p. *) PROCEDURE PROT (): PROTECTION; (* Returns the protection of the calling coroutine. *) END COROUTINES.
Declaration Semantics
The identifiers available for import from the module COROUTINES shall be the type identifiers COROUTINE and INTERRUPTSOURCE, and the procedure identifiers NEWCOROUTINE, TRANSFER, IOTRANSFER, ATTACH, DETACH, IsATTACHED, HANDLER, CURRENT, LISTEN, and PROT.
The module COROUTINES provides the coroutine type (denoted by COROUTINE) in terms of which coroutines are identi- fied, and the implementation-defined interrupt source type (denoted by INTERRUPTSOURCE) in terms of which sources of interrupts are identified.
Changes:
Declaration Semantics
The type identifier COROUTINE shall denote the coroutine type, and the type identifier INTERRUPTSOURCE shall denote the implementation-defined interrupt source type.
The coroutine type shall be a system basic type, distinct from any other type, whose values identify a coroutine throughout the lifetime of that coroutine. The interrupt source type may be identical to a basic type or may be a predefined constructed type.
Note: In addition to use with the COROUTINES procedures NEWCOROUTINE, TRANSFER, IOTRANSFER, and CURRENT, as a system basic type, the operations of assignment and equality testing are applicable to the coroutine type --- see System Basic Types Relational Operations.
annotations Values of the coroutine type are represented by values of the type Coroutine in the formal model --- see ???. The INTERRUPTSOURCE-type is an implementation-defined type --- see Interrupt Handlers. Values of the interrupt source type are represented by values of the type Interrupt-source in the formal model --- see Interrupt Handlers.
The module COROUTINES provides procedures for creating coroutines (NEWCOROUTINE), transferring between coroutines (TRANSFER and IOTRANSFER), for associating and dissociating interrupt sources and coroutines (ATTACH and DETACH), and for unmasking interrupts momentarily (LISTEN).
The procedure ATTACH can be used to associate a coroutine with an interrupt source.
Static Semantics
A call of ATTACH shall have one actual parameter that shall be an expression that is of the interrupt source type.
Dynamic Semantics
The call ATTACH(source) shall associate the implementation-defined source of interrupts identified by source with the calling coroutine. If the source of interrupts is already associated with a coroutine, then that association shall first be broken.
Notes:
The procedure DETACH can be used to dissociate a coroutine from an interrupt source.
Static Semantics
A call of DETACH shall have one actual parameter that shall be an expression that is of the interrupt source type.
Dynamic Semantics
If the calling coroutine is associated with the source of interrupts identified by source, the call DETACH(source) shall dissociate that coroutine from that source.
Note: The call has no effect if the coroutine is not associated with source.
The procedure IOTRANSFER can be used to transfer control from one coroutine to another, pending an interrupt.
Static Semantics
A call of IOTRANSFER shall have two actual parameters. The first actual parameter shall designate a variable that is of the coroutine type. The second actual parameter shall be an expression that is of the coroutine type.
Change: In Programming in Modula-2, the association with the source of interrupts is made on each call of IOTRANSFER. In this International Standard, the association is made beforehand by a call or calls to ATTACH.
Dynamic Semantics
Provided that the calling coroutine is associated with a source of interrupts, the call IOTRANSFER(from,to) shall assign the identity of that coroutine to the variable from, and shall transfer control to the coroutine identified by to. An exception shall be raised if the calling coroutine is not associated with a source of interrupts.
On the granting of a subsequent interrupt, following a request from one of the sources associated with the calling coroutine, the coroutine that is then executing shall be suspended, the identity of that interrupted coroutine shall be assigned to from, and the calling coroutine shall be resumed.
Note: The coroutine that is transferred to by a call of IOTRANSFER, or one that is subsequently transferred to, must execute without protection from interrupts in order for an interrupt request to be granted.
annotations This operation models the interruption of a coroutine following an interrupt request from source. The source will be associated with a coroutine that has called IOTRANSFER. The operation is called by the coroutine that is executing when the interrupt request is granted.
The procedure LISTEN can be used to alter the protection momentarily (usually lowering it so as to allow interrupt requests to be granted).
Static Semantics
A call of LISTEN shall have one parameter that is an expression that is of the protection type.
Dynamic Semantics
The call LISTEN(p) shall momentarily change the protection of the currently executing coroutine to p.
annotations If an interrupt request is granted, the effect is for a call of interrupt-occurs to be made.
The procedure NEWCOROUTINE can be used to create a new coroutine. Control can later be passed to this coroutine by calling the procedures TRANSFER or IOTRANSFER.
Static Semantics
A call of NEWCOROUTINE shall have four or five actual parameters.
The first actual parameter shall be an expression of a type with which the proc type is value-parameter-compatible.
Note: The value of the expression that is the first actual parameter in a call of NEWCOROUTINE must therefore be a parameterless procedure declared at declaration level 0.
The second actual parameter shall be an expression that is of a pointer type.
The third actual parameter shall be an expression of a type with which the unsigned type is value parameter compatible.
The fourth actual parameter shall designate a variable that is of the coroutine type.
The fifth actual parameter, if present, shall be an expression that is of the protection type.
CHANGE 1 --- In Programming in Modula-2 , no provision is made for the initial protection of a coroutine to be specified in a call of NEWCOROUTINE.
Dynamic Semantics
Provided that the value of size is not less than the minimum workspace size, the call
NEWCOROUTINE(procBody,workspace,size,cr,initProtection)
shall create a new coroutine and shall assign a value identifying the created coroutine to the variable cr. The initial protection of the coroutine shall be given by initProtection.
Provided that the value of size is not less than the minimum workspace size, the alternative call
NEWCOROUTINE(procBody,workspace,size,cr)
shall create a new coroutine and shall assign a value identifying the created coroutine to the variable cr. The initial protection of the coroutine shall be given by the current protection of the caller of NEWCOROUTINE.
The created coroutine shall be initialized in such a way that when control is first transferred to that coroutine, the procedure given by the value of procBody will be called as the body of that coroutine. The effect shall be for the caller of procBody to be in the state of normal execution with no block body as an exception handler. The effect shall also be for the caller of procBody to have a protection from interrupts given by the initial protection for the coroutine.
Change: Programming in Modula-2 does not deal with the initial protection of a new coroutine. This International Standard defines rules for determining that initial protection.
If a procedure called as the body of a coroutine attempts to return, an exception shall be raised.
Notes:
Clarification: Programming in Modula-2 states that a program terminates when control reaches the end of a proce- dure which is the body of a coroutine. This International Standard requires that an unhandled exception is raised on any attempt to return to the effective caller of the body of a dynamically created coroutine.
The storage for a variable occupying a number of locations given by the value of size and having an address given by the value of workspace shall be given to the coroutine as its workspace. The use made of this workspace shall be implementation-dependent.
The minimum workspace size shall be implementation-defined. An exception shall be raised if the value of size is smaller than the minimum workspace size.
Notes:
The procedure TRANSFER can be used to transfer control from one coroutine to another.
Static Semantics
A call of TRANSFER shall have two actual parameters. The first actual parameter shall designate a variable that is of the coroutine type. The second actual parameter shall be an expression that is of the coroutine type.
Dynamic Semantics
The call TRANSFER(from,to) shall assign the identity of the calling coroutine to the variable from, and shall transfer control to the coroutine identified by to.
Note: If at the end of its previous execution (if any) the coroutine identified by to had transferred control to another by a call of IOTRANSFER, it will appear as if an interrupt has occurred.
The module COROUTINES provides functions for determining the identity of the current coroutine (CURRENT), the protection of the current coroutine (PROT), and for determining whether and which interrupt sources are associated with coroutines (HANDLER and IsATTACHED).
The function HANDLER can be used to identify which coroutine is attached to a specified interrupt source.
Static Semantics
A call of HANDLER shall have one actual parameter that is an expression that is of the interrupt source type. The type of a call of HANDLER shall be the coroutine type.
Dynamic Semantics
The value of the call HANDLER(source) shall be the identity of the coroutine, if any, that is associated with the source of interrupts given by source. An exception shall occur and may be raised if that source is not currently associated with any coroutine.
The function IsATTACHED can be used to determine whether a coroutine is attached to a specified interrupt source.
Static Semantics
A call of IsATTACHED shall have one actual parameter that is an expression that is of the interrupt source type. The type of a call of IsATTACHED shall be the coroutine type.
Dynamic Semantics
The value of the call IsATTACHED(source) shall be true if any coroutine is associated with the source of interrupts denoted by source, and false otherwise.
The function CURRENT can be used to determine the identity of the currently executing coroutine.
Static Semantics
A call of CURRENT shall have no actual parameters. The type of a call of CURRENT shall be the coroutine type.
Dynamic Semantics
The value of the call CURRENT() shall be the identity of the calling coroutine.
The function PROT can be used to obtain the protection of the currently executing coroutine, that is, the extent to which interrupts are currently masked.
Static Semantics
A call of PROT shall have no actual parameters. The type of a call of PROT shall be the protection type.
Dynamic Semantics
The value of the call PROT() shall be the value of the current protection against interrupts.
The system module EXCEPTIONS provides low-level facilities for identifying the source of user-defined exceptions, for reporting their occurrence, and for making enquiries concerning the execution state of the current coroutine.
User-defined exceptions are identified uniquely by an exception source/number pair. When the source of a user-defined exception is a separate module, that module may encapsulate the exception source value, thus preventing the defined exceptions of the module from being raised directly by other sources. The exception number may also be mapped to values of an enumeration type defined by the module. An example of the use of these facilities is given in The Use of EXCEPTIONS.
The interface to EXCEPTIONS behaves as if the following were its definition module.
DEFINITION MODULE EXCEPTIONS; (* Provides facilities for raising user exceptions and for making enquiries concerning the current execution state. *) TYPE ExceptionSource; (* values of this type are used within library modules to identify the source of raised exceptions *) ExceptionNumber = CARDINAL; PROCEDURE AllocateSource (VAR newSource: ExceptionSource); (* Allocates a unique value of type ExceptionSource *) PROCEDURE RAISE (source: ExceptionSource; number: ExceptionNumber; message: ARRAY OF CHAR); (* Associates the given values of source, number and message with the current context and raises an exception. *) PROCEDURE CurrentNumber (source: ExceptionSource): ExceptionNumber; (* If the current coroutine is in the exceptional execution state because of the raising of an exception from source, returns the corresponding number, and otherwise raises an exception. *) PROCEDURE GetMessage (VAR text: ARRAY OF CHAR); (* If the current coroutine is in the exceptional execution state, returns the possibly truncated string associated with the current context. Otherwise, in normal execution state, returns the empty string. *) PROCEDURE IsCurrentSource (source: ExceptionSource): BOOLEAN; (* If the current coroutine is in the exceptional execution state because of the raising of an exception from source, returns TRUE, and otherwise returns FALSE. *) PROCEDURE IsExceptionalExecution (): BOOLEAN; (* If the current coroutine is in the exceptional execution state because of the raising of an exception, returns TRUE, and otherwise returns FALSE. *) END EXCEPTIONS.
Declaration Semantics
The identifiers available for import from the module EXCEPTIONS shall be the type identifiers ExceptionSource and ExceptionNumber, and the procedure identifiers AllocateSource, RAISE, CurrentNumber, GetMessage, IsCurrentSource, and IsExceptionalExecution.
The module EXCEPTIONS provides the exception source type (denoted by ExceptionSource) in terms of which the sources of user-defined exceptions are identified, and the exception number type (denoted by ExceptionNumber) in terms of which exceptions from a particular source are identified.
Declaration Semantics
The type identifier ExceptionSource shall denote the exception source type, and the type identifier ExceptionNumber shall denote the whole number type.
Note: In addition to use with the EXCEPTIONS procedures AllocateSource, RAISE, CurrentNumber, and IsCurrentSource, as a system basic type, the operations of assignment and equality testing are applicable to the ex- ception source type --- see System Basic Types Relational Operations.
annotations Values of the exception source type are represented by values of the type Exception-source in the formal model --- see Exceptions.
The module EXCEPTIONS provides procedures for allocating a unique value of the exception source type (AllocateSource), raising a user-defined exception (RAISE), and obtaining the message associated with the current exception context (GetMessage).
The procedure AllocateSource can be used as a server for previously unallocated values of the type ExceptionSource. Values of this type are used to identify a source of exceptions, such as a library module, when an exception is raised with the procedure RAISE. The procedure is normally called once during initialization of a separate module, and the resulting value is then used in all calls of RAISE for exceptions that may be handled by clients of the module.
Static Semantics
A call of AllocateSource shall have one actual parameter which shall be a variable that is of the exception source type.
Dynamic Semantics
The call AllocateSource(newSource) shall allocate a value of the exception source type that is unique within the program and shall assign this value to the variable newSource. If a unique value cannot be allocated, an exception shall be raised.
The procedure RAISE can be used by a specified source to raise a user-defined exception.
The effect of raising an exception is the same for exceptions raised by the language implementation as for exceptions raised by explicit use of the procedure RAISE --- see Language Exceptions. Thus the raising of a user-defined exception is a termination event (see Program Termination) unless the exception is handled by an exception body (see Block Bodies and Exception Handling).
Static Semantics
A call of RAISE shall have three actual parameters. The first actual parameter shall be an expression that is of the exception source type, the second actual parameter shall be an expression of a type with which the unsigned type is value parameter compatible, and the third actual parameter shall be an expression of a type with which an open array of CHAR is value parameter compatible.
Dynamic Semantics
The call of RAISE(source, number, message) shall set the current exception source to the value of source, the current exception number to the value of number, and the current exception message to the value of message interpreted as a character string and limited to an implementation-defined length.
The procedure GetMessage can be used to obtain the message passed when an exception is raised. This may give further information about the nature of the exception for use by the program, or in the construction of other messages.
Static Semantics
A call of GetMessage shall have one actual parameter which shall be an array variable having components of the character type.
Dynamic Semantics
The call GetMessage(text) shall assign a string value to the variable text. If the calling coroutine is in the state of exceptional execution, the string value shall be formed from the message stored when the corresponding exception was raised, but with a length limited by the capacity of text.
The module EXCEPTIONS provides functions for determining the exception number for the current user-defined excep- tion (CurrentNumber), whether a user-defined exception has been raised by a given source (IsCurrentSource), and whether the execution state is that of exceptional execution (IsExceptionalExecution).
The function CurrentNumber can be used to obtain the exception number for the current user-defined exception that has been raised.
Static Semantics
A call of CurrentNumber shall have one actual parameter which shall be an expression of the exception source type. The type of a call of CurrentNumber shall be the unsigned type.
Dynamic Semantics
If the calling coroutine is in the state of exceptional execution because of the raising of a user-defined exception from source, the value of the call CurrentNumber(source) shall be the number that is associated with the raised exception; otherwise an exception shall be raised.
The function IsCurrentSource can be used to test whether the calling coroutine is in the state of exceptional execution because of the raising of a user-defined exception from a specified source.
Static Semantics
A call of IsCurrentSource shall have one actual parameter which shall be an expression of the exception source type. The type of a call of IsCurrentSource shall be the Boolean type.
Dynamic Semantics
If the calling coroutine is in the state of exceptional execution because of the raising of a user-defined exception from source, the value of the call IsCurrentSource(source) shall be true ; otherwise the value shall be false .
The function IsExceptionalExecution can be used to test whether the calling coroutine is in the state of exceptional execution.
Static Semantics
A call of IsExceptionalExecution shall have no actual parameters. The type of a call of IsExceptionalExecution shall be the Boolean type.
Dynamic Semantics
If the calling coroutine is in the state of exceptional execution, the value of the call IsExceptionalExecution() shall be true ; otherwise the value shall be false .
The example given below shows the use of EXCEPTIONS in the implementation of a separate module that provides facilities to allow a general user-defined exception to be raised and identified.
Example: A general user exception separate module.
DEFINITION MODULE GeneralUserExceptions; (* Provides facilities for general user-defined exceptions *) TYPE GeneralExceptions = (problem, disaster); PROCEDURE RaiseGeneralException (exception: GeneralExceptions; text: ARRAY OF CHAR); (* Raises exception using text as the associated message *) PROCEDURE IsGeneralException (): BOOLEAN; (* Returns TRUE if the current coroutine is in the exceptional execution state because of the raising of an exception from GeneralExceptions; otherwise returns FALSE. *) PROCEDURE GeneralException(): GeneralExceptions; (* If the current coroutine is in the exceptional execution state because of the raising of an exception from GeneralExceptions, returns the corresponding enumeration value, and otherwise raises an exception. *) END GeneralUserExceptions. IMPLEMENTATION MODULE GeneralUserExceptions; IMPORT EXCEPTIONS; VAR generalSource: EXCEPTIONS.ExceptionSource; PROCEDURE RaiseGeneralException (exception: GeneralExceptions; text: ARRAY OF CHAR); BEGIN EXCEPTIONS.RAISE(generalSource, ORD(exception), text) END RaiseGeneralException; PROCEDURE IsGeneralException (): BOOLEAN; BEGIN RETURN EXCEPTIONS.IsCurrentSource(generalSource) END IsGeneralException; PROCEDURE GeneralException(): GeneralExceptions; BEGIN RETURN VAL(GeneralExceptions, EXCEPTIONS.CurrentNumber(generalSource)) END GeneralException; BEGIN EXCEPTIONS.AllocateSource(generalSource) END GeneralUserExceptions.
The system module TERMINATION provides facilities for a program to enquire whether a termination event has occurred --- see Program Termination.
The interface to TERMINATION behaves as if the following were its definition module.
DEFINITION MODULE TERMINATION; (* Provides facilities for enquiries concerning the occurrence of termination events. *) PROCEDURE IsTerminating (): BOOLEAN ; (* Returns TRUE if any coroutine has started program termination and FALSE otherwise. *) PROCEDURE HasHalted (): BOOLEAN ; (* Returns TRUE if a call to HALT has been made and FALSE otherwise. *) END TERMINATION.
Declaration Semantics
The identifiers available for import from the module TERMINATION shall be the procedure identifiers IsTerminating, and HasHalted.
The module TERMINATION provides the function procedures IsTerminating and HasHalted for enquiries concerning the occurrence of termination events.
The function IsTerminating can be used to determine whether any coroutine has started program termination.
Static Semantics
A call of IsTerminating shall have no parameters. The type of a call of IsTerminating shall be the Boolean type.
Dynamic Semantics
The value of the call IsTerminating() shall be true if any coroutine has started program termination and shall be false otherwise.
The function HasHalted can be used to determine whether a call has been made to HALT.
Static Semantics
A call of HasHalted shall have no parameters. The type of a call of HasHalted shall be the Boolean type.
Dynamic Semantics
The value of the call HasHalted() shall be true if a call to HALT has been made and shall be false otherwise.
The system module M2EXCEPTION provides facilities for identifying language exceptions that have been raised.
The language (which includes the system modules) is regarded as one source of exceptions. Similar facilities are defined by library modules that are sources of user-defined exceptions --- see, for example, ???.
The interface to M2EXCEPTION behaves as if the following were its definition module.
DEFINITION MODULE M2EXCEPTION; (* Provides facilities for identifying language exceptions *) TYPE M2Exceptions = (indexException, rangeException, caseSelectException, invalidLocation, functionException, wholeValueException, wholeDivException, realValueException, realDivException, complexValueException, complexDivException, protException, sysException, coException, exException ); PROCEDURE M2Exception (): M2Exceptions; (* If the current coroutine is in the exceptional execution state because of the raising of a language exception, returns the corresponding enumeration value, and otherwise raises an exception. *) PROCEDURE IsM2Exception (): BOOLEAN; (* If the current coroutine is in the exceptional execution state because of the raising of a language exception, returns TRUE, and otherwise returns FALSE. *) END M2EXCEPTION.
Declaration Semantics
The identifiers available for import from the module M2EXCEPTION shall be the enumeration type identifier M2Exceptions, the corresponding enumeration value identifiers, and the procedure identifiers M2Exception and IsM2Exception.
The module M2EXCEPTION provides the m2exceptions enumeration type (denoted by M2Exceptions) in terms of which the language exceptions are raised. The enumeration values represent aggregations of the exceptions detected by the formal model --- see Aggregation and Raising of Language Exceptions.
Declaration Semantics
The type identifier M2Exceptions shall denote the m2exceptions type which shall be an enumeration type correspond- ing to the following enumeration:
(indexException, rangeException, caseSelectException, invalidLocation, functionException, wholeValueException, wholeDivException, realValueException, realDivException, complexValueException, complexDivException, protException, sysException, coException, exException );
annotations Values of the m2exceptions type are represented by values of the type Exception-value in the formal model --- see Exceptions.
The module M2EXCEPTION provides the function procedures M2Exception and IsM2Exception for enquiries concerning language exceptions.
The function M2Exception can be used to determine the language exception that has been raised.
Static Semantics
A call of M2Exception shall have no actual parameters. The type of a call of M2Exception shall be the m2exceptions type.
Dynamic Semantics
If the calling coroutine is in state of exceptional execution because of the raising of a language exeption, the value of the call M2Exception() shall be the value of type M2Exceptions that is associated with the raised exception; otherwise an exception shall be raised.
The function IsM2Exception can be used to test whether the calling coroutine is in the state of exceptional execution because of the raising of a language exception.
Static Semantics
A call of IsM2Exception shall have no parameters. The type of a call of IsM2Exception shall be the Boolean type.
Dynamic Semantics
If the calling coroutine is in the state of exceptional execution because of the raising of a language exception, the value of the call IsM2Exception() shall be true ; otherwise the value shall be false .
The exceptions defined by the dynamic semantics of the language, which includes the system modules, are categorized into those which an implementation is required to detect and those which an implementation is not required to detect. Detected exceptions are raised by the implementation and constitute a termination event (see Program Termination) unless the exception is handled by an exception body (see Block Bodies and Exception Handling). Exceptions that are distinguished in the dynamic semantics are aggregated into a smaller number of identified exceptions for the purposes of exception handling.
An implementation must define which of the exceptions whose detection is not required are in fact detected in some or all circumstances. It need not define the circumstances in which such exceptions are detected. If such an exception occurs, but is not detected, this International Standard gives no meaning to the program --- see ???.
Dynamic Semantics
annotations Construct an appropriate message based on the exception and the current state, and construct an exception context in which to raise the exception.
Dynamic Semantics
annotations If the exception is detected by the implementation, construct an appropriate message based on the exception, the environment and the current state, and construct an exception context in which to raise the exception. Otherwise, the behaviour is implementation-dependent.
annotations The result is true if the exception is actually detected and otherwise false .
Dynamic Semantics
The character string associated with each of the exceptions that may be raised as specified in Chapters The Language and System Modules shall be implementation-defined.
Note: The character string associated with a raised exception may be accessed using the GetMessage procedure --- see The Procedure GetMessage.
annotations Using the exception and the current state, construct an appropriate message for a language exception context.
annotations Build a language exception context from: an enumeration value defined by the mapping exception-value ; and the message. Raise an exception that has the exception context.