# The Language

This section describes the structure and meaning of a Modula-2 program by specifying its components and stating the rules governing their combination. The major components are the compilation modules: program modules, definition modules, and implementation modules. The components of these modules include import and export lists, definitions and declarations of constants, types, variables, procedures and local modules, and statements and expressions which use these entities.

There are some constants, types, and procedures that are predefined. Those with pervasive identifiers are described in this section. Those that must be accessed using import lists (from system modules) are described in section 7.

The meaning of an identifier at the point of its use is specified by the environment that applies at that point --- see Environments. An environment associates an identifier with an entity and with the properties of that entity. An envi- ronment that applies at a point of use of an identifier is constructed from the environment that applies in a textually enclosing module or procedure, from import lists, and from defining occurrences in definitions and declarations. En- vironments that are constructed to express the well-formedness conditions refer only to properties that are relevant to those conditions, such as the types of variables and parameters. Environments that are constructed to express the meaning of a program refer to properties required for execution, including the storage for variables and the blocks of procedures. If an identifier is not visible in a constructed environment, an environment applies in which only the pervasive identifiers are visible.

The meaning of a program is described by the effect that its execution has on the external state (which may include the state of data files). The effect of the executable components of a program is described by the changes to an internal program state which includes the values of variables --- see ???.

- Programs, Program Modules, and Separate Modules
- Definitions and Declarations
- Data Types
- Expression and Assignment Compatibility
- Blocks
- Statements
- Variable Designators
- Expressions
- Parameter Compatibility and Argument Binding
- Predefined Types, Standard Procedures and Standard Functions
- The Environment and Auxiliary Formal Definitions
- The Storage Model and Auxiliary Formal Definitions

## Programs, Program Modules, and Separate Modules

- Programs and Compilation Modules
- Program Modules
- Definition Modules
- Implementation Modules
- Program Module and Separate Module Consistency
- Module Initialization Order
- Program Termination
- Import Lists
- Export Lists
- Implicit Import and Export
- Protected Modules

### Programs and Compilation Modules

The major components of a Modula-2 program are the compilation modules, so-called because they can be treated separately, although not independently, by an implementation. There is, however, no requirement that the treatment of compilation modules involves actual compilation.

A program module is a compilation module that may use entities exported by separate modules, but does not itself export entities for use by other modules. Separate modules may in turn use entities from other separate modules. The entities that are available for use by clients of a separate module are defined in a compilation module called a definition module. The definition module must exist before the well-formedness of client modules can be checked. This also imposes a constraint on the compilation order | the order in which compilation modules may be elaborated. A corresponding compilation module called an implementation module is needed to complete each separate module before the program can be executed. The actions that are taken on program execution are given in initialization and finalization bodies within the program module and within the implementation modules.

A Modula-2 program consists of a program module together with the separate modules it uses (and the separate modules they in turn use).

Concrete Syntax

compilation module=
program module | definition module | implementation module ;

Note: There is no production for a Modula-2 program, or for a separate module, because of the separate treatment of compilation modules.

Static Semantics

For a particular program there shall be a single program module. For each separate module directly or indirectly imported by the program module, there shall be a single definition module and a single consistent corresponding implementation module --- see Definition Module and Implementation Module Consistency.

Note: This International Standard defines the meaning of a program given the implementation modules supplied for the corresponding definition modules. This does not preclude an implementation from allowing prior selection from alternative implementation modules for a given definition module.

The identifier of the program module shall not be the same as the identifier of any separate module that forms part of the program.

Note: The identifier of a separate module is the module identifier of its definition module and its corresponding imple- mentation module.

The identifiers of the program module, and the identifiers of the separate modules, shall not be the same as the identifier of one of the system modules.

The use of separate modules by compilation modules shall be such that there exists at least one complete and valid order for the separate treatment of the compilation modules of the program --- see Module Compilation Order.

Note: If there are many possible orders that satisfy the constraints given in Module Compilation Order, this International Standard does not define which order is chosen, since the choice has no effect on the meaning of the program.

The outermost environment for checking well-formedness shall be constructed from the environments defined by the definition modules that form part of the program, together with the environment defined by the system modules.

Notes:

1. The outermost environment for checking well-formedness may be understood in terms of a procedure within which all declarations are made by export from local modules which correspond to the separate modules and the system modules. The definition modules correspond to qualified export lists in those local modules.

2. The environment defined by the system modules contains the identifiers associated with the constants, types, and procedures available by import from the system modules --- see Chapter System Modules.

annotations The correspondence of definition and implementation modules and the correctness of each of the compilation modules are checked with respect to the definitions of the definition modules and the system modules.

Dynamic Semantics

The program state shall be initialized from the external state as it exists before execution of the program. The initial protection from interrupts shall be implementation-defined.

Notes:

1. No variables are defined in this initial program state, and none exist upon completion of the program.

2. The external state includes the storage locations that a Modula-2 program can have access to via an address that is calculated from the machine address component of a variable declaration --- see Aliasing Machine Addresses.

The outermost environment for program execution shall be constructed from the environments defined by the separate modules that form part of the program, together with the environment defined by the system modules.

Notes:

1. The outermost environment for program execution may be understood in terms of a procedure within which the program module, separate modules, and system modules are local modules. The definition modules correspond to qualified export lists in those local modules.

2. The environment defined by the system modules contains the identifiers associated with the constants, types, and procedures available by import from the system modules --- see Chapter System Modules.

The program shall be executed by first initializing the separate modules, in the order defined by their occurrence in the import lists, and then initializing the program module --- see Module Initialization Order, Implementation Modules, and Program Modules.

Note: In a program with coroutines, this execution is performed by the main coroutine.

If an exception is raised during initialization, and this exception is not handled, the program shall be terminated exceptionally.

On program termination, the program module and the implementation modules shall be finalized in the reverse order of their initialization --- see Program Termination.

annotations stop, cenv , and initial-state are supplied as explicit arguments in the application of execute-program as a function. Corresponding arguments to these are implied in calls of operations.

Auxiliaries

annotations The definition modules of the program are taken to construct an environment corresponding to the definitions of the definition modules and the system modules.

annotations The set of valid orders of compilation is produced and one of these orders is chosen arbitrarily. The operation is modelling the link-edit process in constructing the outer environment for execution and allocating storage.

annotations The declarations of each module are elaborated in order. The order is such that all the definitions of all modules used by a client module have been added to the environment before that client module is processed. Elaboration of the declarations allocates storage and builds an environment, and the resulting outer environment for the execution of the program is constructed.

annotations The implementation modules are initialized in the execution order defined by the imports.

### Program Modules

A program module consists of a sequence of import lists followed by a module block, which comprises a sequence of declarations and an optional module body. Both of these sequences may be empty. The declarations may include the declaration of local modules.

The program module block is executed after the initialization of all implementation modules of the program.

A program module may have an interrupt protection specified in its heading. The statements and procedures of the module are executed under a protection from interrupts as specified by the protection expression --- see Protected Modules.

Concrete Syntax

program module=
"MODULE", module identifier, [ interrupt protection ], ";",
import lists,
module block, module identifier, "." ;

module identifier= identifier ;

The two module identifier components of a program module shall be identical.

Static Semantics

The program module shall not import itself. If present, the import lists of the program module shall be valid given the outermost environment --- see Import Lists. If present, the import lists and the declarations of the program module block shall be consistent with one another --- see Import Consistency in Module Blocks.

Given the identifiers of the system modules and the separate modules that are imported into the program module, and given the identifiers that are imported from those modules:

- the declarations of the module block of the program module shall be well-formed --- see Declarations,

- the bodies of module and procedure declarations of the module block shall be well-formed --- see Ordering of Procedure and Module Declarations,

- if present, the body of the module block shall be a well-formed module body --- see Module Blocks.

If present in the program module heading, the interrupt protection shall be a valid interrupt protection in the context of the pervasive identifier environment only --- see Protected Modules.

Dynamic Semantics

The elaboration of the program module shall elaborate the declarations of the module block, given the meaning of the imported identifiers.

If the program module is a protected module, the protection specified for the module shall be used to protect the protection domain of the program module. The protection shall be evaluated in the context of the pervasive identifier environment only.

annotations The compilation order is such that, when this operation is called, the result of elaboration of all definition modules used by the definition module have been merged in the given environment. The protection expression (if present) is evaluated in an environment consisting of the pervasive identifiers only, and is added to the returned environment for use by the protection mechanism.

The program module shall be initialized by initializing the program module block given the environment resulting from the elaboration of the program module --- see Static Module Initialization.

annotations The environment for initializing the module block of the program module is retrieved from the given environment.

### Definition Modules

A definition module consists of a sequence of import import lists and a sequence of definitions only. Both of these sequences may be empty. The identifiers introduced by the definitions denote entities that are to be available for use in other modules by import from the corresponding separate module --- see Definitions.

In the case of procedure definitions, only the procedure headings are shown. This is sufficient to allow calls of these procedures in other modules to be checked for consistency, and for those modules to be prepared for execution.

In the case of type definitions, a complete declaration may be given, or the definition may specify only the type identifier, resulting in what is called an opaque type. If the type identifier is defined as the identifier of an enumeration type, the enumeration constant identifiers are also available for import from the corresponding separate module.

Clarification: This International Standard adopts the position taken in later editions of Programming in Modula-2 of not allowing export lists in definition modules.

Concrete Syntax

definition module=
"DEFINITION", "MODULE", module identifier, ";",
import lists,
definitions,
"END", module identifier, "." ;

The two module identifier components of a definition module shall be identical.

Declaration Semantics

The export closure of the identifiers introduced by the definitions of a definition module, and the entities they denote, shall be associated with the identifier of the definition module in the outermost environment.

Note: The export closure includes the identifiers implicitly exported when an identifier is explicitly exported --- see Implicit Import and Export.

annotations The given environment is restricted by the import lists, and then used in the construction of the environment from the definitions of the definition module. The constructed module environment associates the name of the module with the export closure of the identifiers and entities defined in the module and is used for import from the module. The constructed local environment associates the name of the module with the identifiers and entities defined in the module, and is used within the corresponding implementation module.

Static Semantics

A definition module shall not import from its own separate module. If present, the import lists of a definition module shall be valid given the outermost environment --- see Import Lists. If present, the import lists and the definitions of a definition module shall be consistent with one another --- see Import Consistency in Definition Modules.

The definitions of the definition module shall be well-formed given the identifiers of the system modules and the separate modules that are imported into the definition module, and given the identifiers that are imported from those modules.

Dynamic Semantics

The elaboration of a definition module shall elaborate the definitions of the definition module, given the meaning of the imported identifiers.

annotations The compilation order is such that, when this operation is called, the result of elaboration of all definition modules used by the definition module have been merged in the given environment.

### Implementation Modules

The formal model in this International Standard provides two ways by which the dynamic semantics of an implemen- tation of a separate module may be determined:

- from the source text of a Modula-2 implementation module for the separate module,

- from a formal specification of the separate module, as given for the standard library modules in sections 8 and 9.

The meaning of a program that uses a standard library module is obtained by producing an abstract implementation module directly from the specification. The formal model of an implementation module for which Modula-2 source is submitted is called a sourced implementation module in this International Standard.

- Sourced Implementation Modules
- Abstract Implementation Modules

#### Sourced Implementation Modules

An implementation module in source form consists of a sequence of import lists followed by a module block, which comprises a sequence of declarations and an optional module body. Both of these sequences may be empty. The source code for an implementation module is only distinguishable from the source code for a program module by the appearance of the keyword `IMPLEMENTATION` as the first token.

The meaning of procedures and opaque types defined in the definition module is expressed by full declarations in the implementation module. The declarations may include the declaration of local modules and other entities hidden from clients of the separate module.

After the initialization of the implementation modules of imported separate modules, any local modules declared in the implementation module are initialized and the initialization body of the implementation module (if any) is executed. This order of initialization allows actions to be taken before exported procedures are called from client modules and is guaranteed, provided that no separate module indirectly imports itself --- see Module Initialization Order.

An implementation module may have an interrupt protection specified in its heading. The statements and procedures of the module are executed under a protection from interrupts as specified by the protection expression --- see Protected Modules.

Concrete Syntax

implementation module=
"IMPLEMENTATION", "MODULE", module identifier, [ interrupt protection ], ";",
import lists,
module block, module identifier, "." ;

The two module identifier components of an implementation module shall be identical.

Static Semantics

An implementation module shall not import from its own separate module. If present, the import lists of an imple- mentation module shall be valid given the outermost environment --- see Import Lists. If present, the import lists and the declarations of an implementation module block shall be consistent with one another --- see Import Consistency in Module Blocks.

Note: An implementation module and it corresponding definition module must also be consistent (for example the exported procedures must be declared) --- see Programs and Compilation Modules and Definition Module and Implementation Module Consistency.

Given the identifiers of the system modules and the separate modules that are imported into an implementation module, given the identifiers that are imported from those modules, and given the identifiers introduced by the definitions of the corresponding definition module:

- the declarations of the module block of the implementation module shall be well-formed --- see Declarations,

- the bodies of module and procedure declarations of the module block shall be well-formed --- see Ordering of Procedure and Module Declarations,

- if present, the body of the module block shall be a well-formed module body --- see Module Blocks.

If present in an implementation module heading, the interrupt protection shall be a valid interrupt protection in the context of the pervasive identifier environment only --- see Protected Modules.

Dynamic Semantics

The elaboration of an implementation module shall elaborate the declarations of the module block, given the meaning of the imported identifiers and the meaning of the identifiers that are introduced by the definitions of the definition module.

If an implmentation module is a protected module, the protection specified for the module shall be used to protect the protection domain of the implementation module. The protection shall be evaluated in the context of the pervasive identifier environment only.

annotations The compilation order is such that, when this operation is called, the result of elaboration of all definition modules used by the implementation module have been merged in the given environment. The protection expression (if present) is evaluated in an environment consisting of the pervasive identifiers only, and is added to the returned environment for use by the protection procedures.

The implementation module shall be initialized by initializing the implementation module block given the environment resulting from the elaboration of the implementation module --- see Static Module Initialization.

annotations The environment for initializing the module block of the implementation module is retrieved from the given envi- ronment.

#### Abstract Implementation Modules

Abstract implementation modules are derived from the formal specification of a separate module and not from Modula-2 source text. The method of producing an abstract implementation module is given in normative annex B.

### Program Module and Separate Module Consistency

Consistency between the compilation modules of a program is achieved if there is consistency between the correspond- ingly named definition and implementation modules, and if there is at least one valid compilation order.

- Definition Module and Implementation Module Consistency
- Module Compilation Order
- Module Dependencies

#### Definition Module and Implementation Module Consistency

The definition module and implementation module of a separate module are consistent if their definitions and decla- rations are consistent.

Static Semantics

The identifiers imported into the implementation module by the import lists of the implementation module shall be distinct from the the identifiers defined in the definitions of the corresponding definition module.

Except for opaque types and procedures, no identifier defined in the definition module of a separate module shall be declared in the corresponding implementation module.

Each opaque type defined in the definition module of a separate module shall be declared in its corresponding imple- mentation module as a pointer type or as identical to another opaque type.

Notes:

1. The defining instance of the type corresponding to an opaque type identifier defined in a definition module need not be within the declarations of the corresponding implementation module --- the opaque type identifier may be exported from a local module of the implementation module or the opaque type may be declared as identical to that denoted by an imported identifier.

2. An opaque type may be redeclared as the address type, since the address type is also a pointer type.

Change: In the third edition of Programming in Modula-2 , opaque types must be declared as pointer types. This International Standard allows an opaque type to be declared as another opaque type, since that other opaque type must directly or indirectly be implemented as a pointer type.

Clarification: An opaque type cannot be declared as a scalar type.

Each procedure heading in the definition module of a separate module shall have a matching procedure declaration in the corresponding implementation module.

Note: A procedure declaration matching a procedure heading need not be within the declarations of the corresponding implementation module --- the procedure identifier may be exported from a local module of the implementation module.

The formal parameter list of the procedure heading in the definition module shall match the formal parameter list of the procedure heading of the procedure declaration in the implementation module. The formal parameter lists of procedure headings shall match if the formal types of each of the value parameter specifications or variable parameter specifications of corresponding formal parameters are identical.

Clarification: The definition of a procedure in a definition module and the corresponding declaration of that proce- dure in the implementation module must match in the sense that corresponding parameters must have the identical type. The identifiers used to denote the parameters need not be the same, and the identifiers used to denote the types of these parameters need not be the same.

Note: Even if a definition module does not contain any procedure definitions or opaque type definitions there must still be a corresponding implementation module. Likewise, even if there are no exports from a module and the implementation module is used solely for initialization, there must still be a corresponding definition module.

annotations Retrieve an environment for a definition module.

annotations Remove any components of given environment that are derived from declaration of procedure headings or opaque types.

annotations Construct an environment for any imported entities.

annotations Construct an environment for an implementation module.

annotations Construct a set of identifiers that contains the identifiers defined in the definitions component of a definition module and construct a set containing the identifiers contained in the import lists component of an implementation module. The result is true if and only if the intersection of these two sets is empty.

annotations Check that each of the opaque types defined in a definition module is declared as a pointer type (which may be the address type) or as an opaque type in the corresponding implementation module.

annotations Extract the procedure headings from the two environments and check that they are identical. This function is used to check definition modules against implementation modules and forward procedure declarations against full procedure declarations.

annotations An abstract implementation module is consistent with its corresponding definition module by virtue of the method of its construction from the specification of an abstract implementation module.

#### Module Compilation Order

A compilation module may only be elaborated if the definition modules that define the entities imported by that compilation module have been elaborated. This restriction may always be satisfied provided no definition module indirectly imports itself. (A module S directly imports a module T if T occurs in the import list of S. A module S indirectly imports another module U if module S directly imports U, or if module S directly imports a module T and T indirectly imports module U.)

Static Semantics

A valid compilation order shall be such that

- all compilation modules of the program are included exactly once,

- a definition module is included before the corresponding implementation module,

- a definition module is included before any other compilation module that imports from the corresponding separate module.

Auxiliaries

annotations Construct the set of the identifiers of the definition modules that appear in a sequence of program, definition, and implementation modules.

#### Module Dependencies

The compilation modules that depend upon a definition module of a program are those compilation modules that must be elaborated after the definition module is itself elaborated in a valid compilation order --- see Module Compilation Order.

If a definition module of a program is modified, any record of a previous elaboration (or partial elaboration) of that definition module, and of a previous elaboration (or partial elaboration) of a dependent module, is potentially inconsistent with the modification. In this case, all affected modules must be elaborated again, in the same order as their elaboration in a valid compilation order.

annotations The result of this operation is a set of compilation orders for the compilation modules that must be recompiled if the compilation module that is the first parameter is recompiled.

### Module Initialization Order

The order in which the implementation modules of the program are initialized is determined by the order in which the corresponding separate module identifiers appear in the import lists of the program module and the import lists of the other compilation modules --- see Import Lists.

The order is such that, unless a separate module indirectly imports itself, an implementation module is initialized before the initialization of any client modules.

A separate module C is a `client' of a separate module M if the definition module of C, or the implementation module of C, imports from the separate module M and thus is a compilation module that depends upon the definition module of M.

A program module is a client of a separate module M if it imports from the separate module M and thus is a compilation module that depends upon the definition module of M.

A separate module indirectly imports from itself if it is part of a circle of references in the import lists. For example, if an implementation module A imports from a separate module B whose definition or implementation module imports from separate module A, then modules A and B both indirectly import from themselves. The relative order of initialization of such modules is related to the order of their occurrence in the import lists of the program.

Dynamic Semantics

The initialization order shall be determined by first processing the import lists of the program module. The import lists of the program module shall be processed by processing the import lists of each separate module whose identifier appears in the import lists of the program module, in order of occurrence in those import lists.

If an import list is an unqualified import, the import list shall be processed by processing the import lists of the separate module whose module identifier appears in the import list. If an import list is a simple import, the import list shall be processed by processing in turn the import lists of each separate module whose identifier appears in the import list identifiers.

If the import lists of a separate module have finished being processed, or have started to be processed, the import lists of that module shall not be processed again. Otherwise, the import lists of the definition module shall be processed, and then the import lists of the implementation module shall be processed.

The initialization order shall be the order in which the corresponding separate modules finish the processing of their import lists.

Change: The second edition of Programming in Modula-2 does not deal with the effects of import lists on the order of the initialization of modules. The third edition states how import lists appearing in the implementation modules are used in the definition of the initialization order. The rule for import lists in implementation modules has been extended to cover the program module and definition modules. This International Standard defines an order for the initialization of modules when there is a circular reference in the import lists. The third edition of Programming in Modula-2 states that the order of initialization is undefined in such a case.

Auxiliaries

annotations Construct a sequence that contains the identifiers of those modules that are directly imported by the definition module.

annotations Construct a sequence of identifiers that contains the identifiers of those modules that are directly imported by the implementation module.

### Program Termination

During program termination, the finalization bodies of those static modules that have started initialization are executed in the reverse order of their initialization. The static modules are the program module, the implementation modules, and any local modules declared in the module blocks of these compilation modules.

Program termination starts on the first occurrence of one of the following termination events:

a) the end of the normal part of the program module initialization body is reached,

b) a `RETURN` statement is executed in the program module initialization body,

c) the standard procedure `HALT` is called,

d) an exception is raised and this exception is not handled.

Cases a) and b) constitute normal termination. Case c) does not change the execution state, but no exit is made from protection domains --- see Protected Modules and Programs and Compilation Modules. Case d) constitutes exceptional termination. (During exceptional termi- nation an implementation, where appropriate, is required to propagate a report of the exception to the environment from which the program was invoked --- see ???.)

In a program with coroutines, cases a) and b) can only occur during execution of the main coroutine. It is possible for cases c) and d) to occur during the execution of any coroutine.

Further termination events might occur during finalization of the static modules. Firstly, the finalization body of a static module block may itself call `HALT` or may raise an exception that is not handled. Secondly, since coroutine activity continues during the finalization of the static modules, there might be a further termination event during execution of a coroutine.

In order to guarantee that the finalization bodies of static modules are always executed in the reverse order of their initialization, and that all static modules that have started their initialization are finalized, the first occurrence of a termination event in a coroutine causes static module finalization to be executed by that coroutine. This is true whether or not a termination event has already occurred during execution of another coroutine.

On the second and subsequent occurrences of a termination event in a coroutine, during static module finalization by that coroutine, the execution of the finalization body ceases and execution in that coroutine continues with the next finalization body that is to be executed by that coroutine.

As soon as the execution of the last static module to be finalized is completed, or is ceased, execution of the entire program is completed.

Since a coroutine may be started during the initialization of static modules, a coroutine may start finalizing before further static modules have started their initialization. In that case, no further static modules are initialized --- see Static Module Initialization.

The system module `TERMINATION` exports enquiry procedures that allow the program to determine if program termi- nation is in progress and if there has been a call of `HALT` --- see The Module TERMINATION.

Dynamic Semantics

On the first occurrence of a termination event during the execution of a coroutine, if there is at least one static module of the program that has a finalization body and that has completed or started its initialization, static module finalization shall be started by that coroutine. The finalization bodies shall be executed for all static modules that have finalization bodies, and that have completed or started initialization. The finalization order shall be the reverse of the order in which these modules were initialized.

If there is a subsequent occurrence of a termination event, while the coroutine is executing the finalization body of a static module, the coroutine shall execute the next finalization body in the finalization order.

If there are no static modules to be finalized, or no further static modules to be finalized, the execution of the program shall be complete.

Notes:

1. In a program with coroutines other than the main coroutine, the finalization body of a static module should be written so that it will behave correctly if called more than once or if reentered.

2. Modules that are dynamically initialized (on calls to procedures in which they are declared as local modules) are not finalized on program termination.

Change: Programming in Modula-2 makes no provision for the finalization of static modules on program termination.

annotations The formal model keeps a stack of static modules to be finalized in the global state. This stack is built during static module initialization. The operations is-terminating and set-terminating are per-coroutine operations. set-terminating makes a copy of the stack in the per-coroutine state.

annotations The operation next-module is a per-coroutine operation. It pops the next module off the per-coroutine copy of the termination stack.

### Import Lists

Following the module heading, a module may have a sequence of import lists. An import list includes a list of the identifiers that are to be explicitly imported into the module. Explicit import of an enumeration type identifier implicitly imports the enumeration constant identifiers of the enumeration type.

Imported identifiers are introduced into the module, thus extending their scope, but they have a defining occurrence that appears elsewhere.

Every kind of module may include a sequence of import lists, whether it is a program module, a definition module, an implementation module, or a local module. In the case of a definition module, the imported identifiers may be used in the definitions of that module. In the case of any other kind of module, the imported identifiers may be used in the block of the module.

Concrete Syntax

import lists= { import list } ;

Declaration Semantics

The identifiers imported by a sequence of import lists of a module shall be all of the identifiers imported separately by the individual import lists. The import of an identifier shall also import the entity denoted by that identifier.

Static Semantics

Each import list in a sequence of import lists shall be valid in the given environment.

Note: In the case of an import list appearing in a local module, the given environment is the environment that applies at the point of the local module declaration --- see Local Module Declarations. In the case of an import list appearing in a program module, definition module, or implementation module, the given environment is the outermost environment which includes the identifiers of the system modules and the separate modules of the program --- see Programs and Compilation Modules.

An identifier shall not be imported (explicitly or implicitly) by more than one import list in the import lists of a module.

Auxiliaries

annotations Construct a sequence of identifiers containing the identifiers of all the modules whose identifiers occur in the import lists of a module.

annotations Construct a sequence of identifiers containing the identifiers of all the modules that occur in an import list of a module.

annotations Construct a set of identifiers from the import lists of a module.

annotations Construct a set of identifiers from the import list of a module. The identifiers in the set represent entities that are imported into a module. Note that the identifier in the `FROM` component (i.e. the name of the module) of an unqualified import is not in the set.

- Import List
- Simple Imports
- Unqualified Import
- Import Consistency in Definition Modules
- Import Consistency in Module Blocks

#### Import List

An import list may either be a simple import or an unqualified import.

Concrete Syntax

import list= simple import | unqualified import ;

#### Simple Imports

A simple import includes a list of the identifiers that are to be explicitly imported. Explicit import of an enumeration type identifier implicitly imports the enumeration constant identifiers of the enumeration type.

The identifiers imported by a simple import are introduced into the module in which the simple import appears. In the case of a simple import appearing in a local module, the scope of the imported identifiers is extended from the block in which the local module is declared. In the case of a simple import in a program module, definition module, or implementation module, the scope is extended from the outermost environment which includes the identifiers of the system modules and the separate modules of the program.

Concrete Syntax

simple import= "IMPORT", identifier list, ";" ;

Declaration Semantics

The identifiers that are imported by a simple import shall be the identifiers in the identifier list of the simple import, together with any identifiers that are implicitly imported with those identifiers --- see Implicit Import and Export.

Static Semantics

The identifiers imported (explicitly or implicitly) by a simple import shall be distinct from each other. Each of the identifiers in the identifier list shall be visible in the given environment.

Note: The given environment does not include the pervasive identifiers, and so the pervasive identifiers may not be included in a simple import.

#### Unqualified Import

An unqualified import specifies a module identifier and a list of the identifiers that are to be explicitly imported from that module. Explicit import of an enumeration type identifier implicitly imports the enumeration constant identifiers of the enumeration type.

The identifiers imported by an unqualified import are introduced into the module in which the unqualified import appears. The scope of the imported identifiers is extended from the module specified by the unqualified import.

In the case of an unqualified import appearing in a local module, the module identifier refers to the module it denotes in the block in which the local module is declared. In the case of an unqualified import in a program module, definition module, or implementation module, the module identifier refers to one of the system modules or one of the separate modules of the program.

Concrete Syntax

unqualified import= "FROM", module identifier, "IMPORT", identifier list, ";" ;

Note: The identifier list of the unqualified import contains identifiers that are distinct from each other.

Abstract Syntax

annotations The number of elements in the set of identifiers of the abstract syntax of an unqualified import is equal to the number of identifiers in the identifier list of the concrete syntax.

Declaration Semantics

The identifiers that are imported by an unqualified import shall be the identifiers in the identifier list of the unqualified import that are exported by the module denoted by the module identifier, together with any identifiers that are implicitly imported with those identifiers --- see Implicit Import and Export.

Static Semantics

The identifiers imported by an unqualified import shall be distinct from each other. The module identifier shall be the identifier of a module that is visible in the given environment, and each of the identifiers in the identifier list shall be exported from the identified module.

Auxiliaries

annotations The identifiers that are imported from a module must be exported by that module; thus they must be in the domain of the environment associated with the module from which they were exported.

#### Import Consistency in Definition Modules

Static Semantics

In the case of a definition module containing an import list, none of the implicitly or explicitly imported identifiers may be the same as an identifier defined in the definition module.

#### Import Consistency in Module Blocks

Static Semantics

In the case of a module other than a definition module containing an import list, none of the explicitly or implicitly imported identifiers may be the same as an identifier declared in the module block of the importing module.

### Export Lists

Following the import lists, if any, a local module may have a single export list --- see Local Module Declarations. An export list includes a list of the identifiers that are explicitly exported from a local module. Explicit export of an enumeration type identifier implicitly exports the enumeration constant identifiers of the enumeration type.

An export list may either be an unqualified export or a qualified export.

Concrete Syntax

export list= unqualified export | qualified export ;

Declaration Semantics

The export of an identifier shall also export the entity denoted by that identifier.

- Unqualified Exports
- Qualified Exports

#### Unqualified Exports

The identifiers exported by an unqualified export of a local module are introduced into the procedure or module in which the local module declaration appears. In the block of that procedure or module, the exported identifiers can be used with or without being qualified by the identifier of the local module.

Concrete Syntax

unqualified export= "EXPORT", identifier list, ";" ;

Note: The identifier list of the unqualified export contains identifiers that are distinct from each other.

Abstract Syntax

annotations The number of elements in the set of identifiers of the abstract syntax of an unqualified export is equal to the number of identifiers in the identifier list of the concrete syntax.

Declaration Semantics

The identifiers that are exported by an unqualified export shall be the identifiers in the identifier list of that unqualified export, together with any identifiers that are implicitly exported with those identifiers --- see Implicit Import and Export.

Static Semantics

The identifiers in the identifier list of an unqualified export shall be distinct from each other.

The identifiers in the identifier list of an unqualified export shall be declared in the declarations of the local module that contains the unqualified export.

Notes:

1. The identifiers in the identifier list of an unqualified export are explicitly exported. Identifiers implicitly exported from a local module need not be declared in declarations of the local module since export of an enumeration type identifier implicitly exports the enumeration constant identifiers of the enumeration type whether or not the type identifier and the enumeration constant identifiers are introduced by the same declaration --- see Implicit Import and Export.

2. The identifiers in the identifier list of an unqualified export may not be otherwise introduced into the procedure block or module block in which the local module is declared. This follows from the rules that declarations of a block may include only one defining occurrence of a particular identifier and, in the case of a module block, that none of the imported identifiers may be the same as an identifier declared in that block --- see Declarations and Import Consistency in Module Blocks.

#### Qualified Exports

The identifiers exported by a qualified export of a local module are introduced for use in the procedure or module in which the local module declaration appears. In the block of that procedure or module, the exported identifiers can be used only if qualified by the identifier of the local module.

Concrete Syntax

qualified export= "EXPORT", "QUALIFIED", identifier list, ";" ;

Note: The identifier list of the qualified export contains identifiers that are distinct from each other.

Abstract Syntax

annotations The number of elements in the set of identifiers of the abstract syntax of a qualified export is equal to the number of identifiers in the identifier list of the concrete syntax.

Declaration Semantics

The identifiers that are exported by a qualified export shall be the identifiers in the identifier list of that qualified export, together with any identifiers that are implicitly exported with those identifiers --- see Implicit Import and Export.

Static Semantics

The identifiers in the identifier list of a qualified export shall be distinct from each other.

The identifiers in the identifier list of a qualified export shall be declared in the declarations of the local module that contains the qualified export.

Note: The identifiers in the identifier list of a qualified export are explicitly exported. Identifiers implicitly exported from a local module need not be declared in declarations of the local module since export of an enumeration type identifier implicitly exports the enumeration constant identifiers of the enumeration type whether or not the type identifier and the enumeration constant identifiers are introduced by the same declaration --- see Implicit Import and Export.

### Implicit Import and Export

The set of identifiers that is imported or exported if an identifier is explicitly imported or exported is called the (import and export) closure of that identifier. Normally, the closure includes only the explicitly imported or exported identifier. However, in the case of the explicit import or export of an identifier of an enumeration type, the closure also includes the identifiers of the values of that type.

Implicit export applies to the identifiers that are exported (qualified) from separate modules, by virtue of their being the subject of a definition in a definition module, as well as to export from a local module that uses an export list.

Declaration Semantics

The closure of an identifier shall be a set consisting of that identifier, together with the closure of the type if the identifier is a type identifier.

The closure of a type shall be the empty set, except in the case that the type is an enumeration type, when the closure shall be the set of identifiers associated with the values of the enumeration type.

Note: Thus if an identifier denoting an enumeration type is imported (exported), then the occurrence of that identifier in the import list (export list) is an abbreviation for the occurrence of that identifier, together with all of the identifiers associated with the constant values of the enumeration type.

Clarifications:

1. If an identifier associated with a module that contains an unqualified export list is imported (exported), then the identifiers occurring in the export list of the module shall not be automatically imported (exported).

2. If an entity of a record type is imported or exported, the field identifiers of that record type are automatically available to be used as selectors. This does not constitute implicit import or export since, unlike the identifiers of enumeration values, field identifiers cannot be the subject of explicit import or export.

annotations The closure of a type is the empty set, except in the case that the type is an enumeration type, when it is the set of identifiers associated with the values of the enumeration type.

Note: Identifiers implicitly exported from a module need not be declared in definitions or declarations of the module since export of an enumeration type identifier implicitly exports the enumeration constant identifiers of the enumeration type. This is true whether or not the type identifier and the enumeration constant identifiers are introduced by the same definition or declaration --- see Export Lists and Definition Modules. This situation is illustrated by the following example which uses unqualified export from a local module although similar comments apply to export from a separate module (through definitions), and to qualified export from a local module. There is only a single defining occurrence of the enumeration constant identifiers in the declarations of M, as is required for well-formed declarations --- see Declarations.

Example: Implicit export of enumeration constant identifiers.

        MODULE M;

        MODULE M1;
        EXPORT T1; (* implicitly exports red, green, and blue *)
        TYPE T1 = (red, green, blue);
        END M1;

        MODULE M2;
        IMPORT T1;
        EXPORT T2; (* implicitly exports red, green, and blue *)
        TYPE T2 = T1;
        END M2;

        CONST shade = M2.red;

        END M;

### Protected Modules

An interrupt request may be generated by the system underlying a Modula-2 implementation to indicate that an external condition has arisen that requires the attention of the program. Depending on the run-time environment of an implementation, interrupt requests may originate from hardware device controllers, or may be generated by an underlying operating system.

The acceptance of such a request involves the interruption of the normal sequence of execution (see The Module COROUTINES) and may need to be postponed if the program is not prepared to handle the request, if it is a condition of relatively low priority, or if acceptance would lead to interference with the section of program that is under execution.

A program module, implementation module, or local module may specify, by including an interrupt protection in its heading, the extent to which the execution of enclosed statement sequences is to be protected from interrupts.

Protection from interrupts is provided by setting the current protection to the value specified in the module heading during initialization and finalization of the module and on activation of procedures exported from the module.

The pervasive identifiers `UNINTERRUPTIBLE` and `INTERRUPTIBLE` are provided to denote protection values. All mask- able interrupts are disabled if the current protection is specified as `UNINTERRUPTIBLE`. All interrupts are enabled if the current protection is specified as `INTERRUPTIBLE` --- see The Protection Type. The current protection is initialized to an implementation-defined value --- see Operations to Initialize and Terminate the Program State.

A module with a protection in its heading is called a protected module. Procedures exported from a protected module are called protected procedures.

Procedures that are not exported, and therefore not directly protected, are indirectly protected if called from a protected block body. However, such procedures may be made available, unprotected, for use outside a protected module if their values are returned as a result of a procedure call.

The declaration of a protected local module might occur within the declarations of another protected module. In all cases, the protection that is applied to the protection domain of a protected module is the protection specified for that module. Only a single protection is applied on entry to a protection domain.

Concrete Syntax

interrupt protection= "[", protection expression, "]" ;

protection expression= constant expression ;

Static Semantics

The protection expression of a program module or implementation module shall be a constant expression of the protection type in the context of the pervasive identifier environment --- see The Protection Type.

The protection expression of a local module that is protected from interrupts shall be a constant expression of the protection type given the environment that applies at the point of the local module declaration.

Change: In Programming in Modula-2 , the identifiers that have meaning in a protection expression of a separate module or a local module are not explicitly discussed, and the only examples given of protection expressions are single literal values. It is necessary to liberalize this, at least to the pervasive identifiers, in order to handle the definition of protection (for which, in general, literal values may vary between implementations) --- see Protected Modules.

Dynamic Semantics

For a module with interrupt protection, the value of the protection expression shall be used as the protection value during execution within the protection domain of the module.

Provided the protection of the new protection domain does not allow interrupts from any source that is not allowed by the current protection, entering an interrupt protection domain shall cause the current interrupt protection to be saved and then set to the value specified by the protection expression of the protected module; otherwise an exception shall be raised.

Note: In cases where a local static module with interrupt protection is declared within the declarations of another static module with interrupt protection, the raising of this exception is inevitable if the protection of the inner module allows interrupts from a source not allowed by the protection of the outer module. Implementations are free to detect such situations prior to execution --- see ???.

Leaving an interrupt protection domain shall cause the current interrupt protection to be restored to the value saved on the corresponding entry to the protection domain.

## Definitions and Declarations

Definitions and declarations serve to introduce the identifiers of a module or procedure into their scope. Definitions appear in definition modules; declarations appear in program modules, implementation modules, local modules and procedures.

With the exception of the predefined pervasive identifiers, each identifier that is used in a module must either be introduced by a definition or a declaration in that module or must be introduced by import from another module.

With the exception of the predefined pervasive identifiers, each identifier that is used in a procedure must either be introduced by a declaration in that procedure or must have a scope that includes the block in which the procedure is declared.

The scope of an identifier comprises the entirety of the definitions, blocks, or statement sequences within which the identifier may be used. Within its scope, an identifier has a unique meaning. However, it is not always the case that the meaning of an identifier is known throughout its scope. For example, the meaning of an identifier that is used in a declaration is not known if that identifier is introduced into its scope by a subsequent declaration in the same sequence of declarations. The static semantics require that, where the meaning of an identifier needs to be known for a declaration to be elaborated, uses of that identifier in a declaration must not precede any declaration of that identifier.

If a point where identifiers may be used is included in the scope of a particular identifier, that identifier is said to be visible at that point of use, whether or not its meaning is known. In this International Standard, the visibility and meaning of an identifier at the point of its use is determined by the environment that applies at that point --- see Environments.

The declarations of procedures and of local modules may include statements within the blocks of those procedures and local modules. This International Standard defines a meaning for programs in which the statements of such declarations use identifiers whose scope includes those statements but whose introduction to that scope is given in a subsequent declaration in the same sequence of declarations. However, a conforming implementation may reject programs that use identifiers in statements that precede the declaration of those identifiers --- see ???. The alternative static semantic rules that may be applied are given in Ordering of Procedure and Module Declarations.

- Identifiers
- Qualified Identifiers
- Definitions
- Type Definitions
- Procedure Headings
- Declarations
- Ordering of Procedure and Module Declarations
- Constant Declarations
- Type Declarations
- Variable Declarations
- Procedure Declarations
- Local Module Declarations
- Auxiliary Formal Model Definitions

### Identifiers

An identifier denotes a constant, type, variable, procedure, or module.

Note: The syntactic class identifier is an element of the lexis --- see Chapter ???.

Abstract Syntax

annotations A set of tokens that are in a 1-1

The elements of Identifier are denoted by identifiers in the type style used for Modula-2 source text in this International Standard.

### Qualified Identifiers

The term qualified identifier is used in situations where the Modula-2 concrete syntax permits a single identifier to be qualified by the identifier of the module that exports it. Since module identifiers may be exported from local modules, identifiers may be qualified by more than one module identifier.

Concrete Syntax

qualified identifier= { qualifying identifier, "." }, identifier ;

qualifying identifier= module identifier ;

Abstract Syntax

annotations It is the responsibility of the translation process from concrete to abstract syntax to distinguish between the use of the period for module qualification and the use of the period for field selection.

Static Semantics

An identifier that is not qualified by a module identifier shall be visible in the environment that applies at the point of use of that identifier or else shall be a pervasive identifier --- see Predefined Types, Standard Procedures and Standard Functions.

Each qualifying identifier of a qualified identifier shall be the name of a module from which the succeeding identifier is exported.

Auxiliaries

annotations The result is the environment of the module containing the declaration of the identifier component of the qualified identifier, together with that identifier.

### Definitions

Definitions declare the identifiers that are to be exported from a separate module and introduce those identifiers into their scope. Definitions also specify certain permanent properties of the associated entities denoted by the identifiers, such as:

- whether the entity is a constant and, if so, its associated type and value;

- whether the entity is a type and, if so, possibly its structure and in the case of a new ordinal type, its set of permitted values;

- whether the entity is a variable and, if so, its type and possibly its address;

- whether the entity is a procedure and, if so, the structure of its heading.

The identifier is used to denote the associated entity, but only in those parts of the program that are within the scope of the identifier.

Note: The scope of an identifier introduced in a definition includes the definition module in which the definition appears, the module block of the corresponding implementation module, the definitions of definition modules that import the identifier, and the module blocks of other modules that import the identifier.

Concrete Syntax

definitions= { definition } ;

definition=
"CONST", { constant declaration, ";" } |
"TYPE", { type definition, ";" } |
"VAR", { variable declaration, ";" } |
procedure heading, ";" ;

Declaration Semantics

The identifiers and entities defined by the definitions of a definition module shall be the identifiers and entities defined by each definition in the context of any preceding definition of the definition module.

annotations The environment constructed from each definition is used in the construction of the environment from any following definitions

Static Semantics

The identifiers that are used in the definitions of a definition module shall be identifiers whose scope includes those definitions.

An identifier that is used in a definition may not be one whose defining occurrence is given in a following definition, unless its use is within a new pointer type or a new procedure type and it is subsequently defined as a type identifier.

Note: The use of an identifier within a new pointer type or a new procedure type follows the keywords `POINTER TO` or `PROCEDURE` and is `shielded' from the declare-before-use-in-declarations rule that otherwise applies.

The definitions of a definition module may include only one defining occurrence of a particular identifier.

annotations p defonly once, that shielded identifiers are visible, and that the define before use in definitions rule is satisfied.

annotations Check that no identifier is defined twice in a sequence of definitions.

annotations Check that all identifiers shielded by POINTER TO or PROCEDURE in new types in a sequence of definitions are visible to those definitions as type identifiers.

Dynamic Semantics

The elaboration of the definitions of a definition module shall associate, in the resulting execution environment, the identifiers and entities defined by each definition.

annotations Resolve all definitions and then allocate storage.

### Type Definitions

Type definitions serve to introduce an identifier that denotes a type and to specify that type and possibly its structure and set of permitted values. If the structure is omitted, the type definition defines an opaque type.

Concrete Syntax

type definition= type declaration | opaque type definition ;

opaque type definition= identifier ;

Declaration Semantics

The identifier of an opaque type definition shall be defined as the identifier of a unique opaque type; otherwise the identifiers and entities defined by a type definition shall be the identifiers and entities defined by a type declaration --- see Type Declarations.

annotations A unique type name is generated for the opaque type, and the type identifier is associated with that type name; the environment contains a record of the new type and the structure of the type as being opaque.

Static Semantics

If a type definition is a type declaration it shall have the static semantics of a type declaration | see 6.2.9.

Dynamic Semantics

The elaboration of a type definition that is a type declaration shall associate the identifiers and entities of the type declaration in the resulting execution environment.

Note: No dynamic semantics need to be given for the elaboration of opaque type definitions since, during program execution, a corresponding pointer type declaration is elaborated.

annotations Opaque type definitions have no dynamic semantics.

### Procedure Headings

There are two kinds of procedure heading, namely proper procedure headings and function procedure headings. A proper procedure heading is the heading of a proper procedure. A proper procedure is activated by a procedure call statement. A function procedure heading is the heading of a function procedure. A function procedure is activated by a function call as a factor of an expression, and yields a result that is used as an operand in the expression. A function procedure heading is distinguished from a proper procedure heading by the specification of the function result type.

Procedure headings occur in definitions, within a definition module, and also occur in declarations, within a module or procedure block. Within declarations, a procedure heading has its own associated procedure block --- see Procedure Declarations. One of the properties of a procedure heading, and its associated procedure block, is its `declaration level'. This is taken from the declaration level of the definitions or declarations in which the procedure heading occurs. Definitions, and the blocks of static modules, have a declaration level of 0. The declaration level of a procedure block is one more than the declaration level of the block in which the procedure is declared. The declaration level is required for static semantic rules governing the assignment of procedure values to procedure variables --- see Assignment Compatibility.

Concrete Syntax

procedure heading= proper procedure heading | function procedure heading ;

- Proper Procedure Headings
- Function Procedure Headings
- Formal Parameters

#### Proper Procedure Headings

A proper procedure heading declares the name (and, if present, the formal parameters) of a proper procedure.

Concrete Syntax

proper procedure heading=
"PROCEDURE", procedure identifier, [ formal parameters ] ;

formal parameters= "(", [ formal parameter list ], ")" ;

formal parameter list= formal parameter, { ";", formal parameter } ;

Declaration Semantics

A proper procedure heading shall define the procedure identifier as a procedure identifier of a proper procedure, with a structure given by the declared number, positions, and formal types of parameters, and with the declaration level of the definitions or declarations in which it appears.

Static Semantics

The identifiers declared as formal parameters in the formal parameter list of a proper procedure heading shall be distinct from each other, and distinct from the formal type identifiers.

Auxiliaries

annotations Convert a proper procedure heading into a proper procedure structure.

annotations Convert a formal parameter list into a formal parameter type list.

annotations Convert a value or variable parameter specification into a value or variable formal type.

annotations Check that the identifiers declared in a formal parameter list are all distinct.

#### Function Procedure Headings

A function procedure heading declares the name (and, if present, the formal parameters) of a function procedure and declares the type of the result to be associated with the procedure identifier.

Concrete Syntax

function procedure heading=
"PROCEDURE", procedure identifier, formal parameters, ":", function result type ;

function result type= type identifier ;

Declaration Semantics

A function procedure heading shall define the procedure identifier as a procedure identifier of a function procedure, with a structure given by the declared number, positions, formal types of parameters, and result type, and with the declaration level of the definitions or declarations in which it appears.

Static Semantics

The identifiers declared as formal parameters in the formal parameter list of a function procedure heading shall be distinct from each other and distinct from the formal type identifiers. The qualified identifier that defines the return type of the function procedure shall denote a type.

Auxiliaries

annotations Convert a function procedure heading into a function procedure structure.

#### Formal Parameters

As an optional part of a procedure heading, a formal parameter provides an explicit interface between a block body that calls the procedure and the block body of the procedure. Calls of a procedure that has formal parameters must supply corresponding actual parameters. These are evaluated, and the resulting arguments are accessed in the procedure through the identifiers of the formal parameters.

Note: There may also be an implicit interface between the block bodies through variable identifiers whose scope includes both block bodies.

There are two kinds of formal parameter: value parameters and variable parameters. In each case, the type of a formal parameter is specified by a formal type --- see Formal Types.

The declaration semantics and static semantics of formal parameters are given in this clause. The dynamic semantics of formal parameters are given by procedure activation --- see Argument Binding.

Concrete Syntax

formal parameter=
value parameter specification | variable parameter specification ;

##### Value Parameters

Value parameters provide a means of explicitly passing a value into a procedure block body. Corresponding actual parameters must be expressions. In the procedure block body, a value parameter acts like a local variable to which the result of the evaluation of the actual parameter is assigned as an initial value.

Concrete Syntax

value parameter specification= identifier list, ":", formal type ;

Abstract Syntax

annotations In the translation from concrete to abstract syntax, each identifier in the identifier list is associated with its formal type.

Declaration Semantics

A value parameter specification shall define each identifier in the identifier list to be a value formal parameter having the declared formal type --- see Formal Types.

##### Variable Parameters

Variable parameters provide a means of explicitly passing a variable into a procedure block body. Corresponding actual parameters must designate variables. In the procedure block body, the variable parameter identifier stands as an alias for the designated variable.

Concrete Syntax

variable parameter specification= "VAR", identifier list, ":", formal type ;

Abstract Syntax

annotations In the translation from concrete to abstract syntax, each identifier in the identifier list is associated with its formal type.

Declaration Semantics

A variable parameter specification shall define each identifier in the identifier list to be a variable formal parameter having the declared formal type | see 6.3.10.

### Declarations

Declarations introduce identifiers into their scope in a procedure or module (other than a definition module). Decla- rations also specify certain permanent properties of the associated entities denoted by the identifiers, such as:

- whether the entity is a constant and, if so, its associated type and value;

- whether the entity is a type and, if so, its structure and, in the case of a new ordinal type, its set of permitted values;

- whether the entity is a variable and, if so, its type and possibly its address;

- whether the entity is a procedure and, if so, the structure of its heading and the associated block;

- whether the entity is a local module and, if so, its exported identifiers and its associated block.

The identifier is used to denote the associated entity, but only in those parts of the program that are within the scope of the identifier.

Note: The scope of an identifier declared in a procedure is the procedure block, but this can be restricted by redeclaring it within a nested procedure or by not importing it into a (nested) local module. The scope of an identifier declared in a local module is the module block plus enclosing blocks to which it is exported, but this can be restricted by redeclaring it within a nested procedure or by not importing it into a (nested) local module.

Concrete Syntax

declarations= { declaration } ;

declaration=
"CONST", { constant declaration, ";" } |
"TYPE", { type declaration, ";" } |
"VAR", { variable declaration, ";" } |
procedure declaration, ";" |
local module declaration, ";" ;

Declaration Semantics

The identifiers and entities defined by a sequence of declarations shall be the identifiers and entities defined by each declaration in the context of any preceding declaration in the sequence.

annotations The environment constructed from each declaration is used in the construction of the environment from any following declarations

Static Semantics

The identifiers that are used in the declarations of a module block or procedure block shall be identifiers whose scope includes those declarations.

An identifier that is used in a declaration may not be one whose defining occurrence is given in a following declaration, unless its use is within a new pointer type or a new procedure type and it is subsequently declared as a type identifier.

Note: The use of an identifier within a new pointer type or a new procedure type follows the keywords `POINTER TO` or `PROCEDURE` and is `shielded' from the declare-before-use-in-declarations rule that otherwise applies.

The declarations of a block may include only one defining occurrence of a particular identifier.

Notes:

1. Identifiers declared in a local module declaration, and exported from that module by an unqualified export, are effectively declared in the block that contains the module declaration --- their scope includes that block and they are not imported into that block.

2. Identifiers declared in a local module declaration, and exported from that module by a qualified export, may have the same spelling as identifiers whose scope includes the block that contains the module declaration. Uses of such identifiers must be qualified by the identifier of the local module.

annotations p dclonly once, that shielded identifiers are visible, that the declare before use in declarations rule is satisfied, that all procedures that have been declared as `FORWARD` are fully declared, and that the bodies of modules and procedures are well-formed.

annotations Check that no identifier is declared twice in a sequence of declarations. Identifiers exported from local modules will be included in the check. Identical enumeration constants may be exported from more than one local module because of implicit export.

annotations Check that all identifiers shielded by POINTER TO or PROCEDURE in new types in a sequence of declarations are visible to those definitions as type identifiers.

Dynamic Semantics

The elaboration of the declarations of a block shall associate, in the resulting execution environment, the identifiers and entities defined by each declaration.

annotations Resolve all declarations and then allocate storage.

### Ordering of Procedure and Module Declarations

This International Standard gives meaning to programs that conform to either or both of the alternative static semantic rules for the ordering of procedure and module declarations given below.

Note: Modula-2 implementations are required to choose one of the alternative rules for the ordering of procedure and module declarations according to the criteria of 4.3.

Declare Before Use in Declarations Model

The bodies of procedures and local modules declared within a sequence of declarations shall be well-formed given an environment in which all identifiers declared in that sequence are visible and in which the meaning of identifiers introduced in all declarations of that sequence is known. Thus, the identifiers used in the statements of a procedure declaration or the statements of a local module declaration of a block may be identifiers whose defining occurrence is given in a subsequent declaration of that block.

Declare Before Use Model

The bodies of procedures and local modules declared within a sequence of declarations shall be well-formed given an environment in which all identifiers declared in that sequence are visible but in which the meaning of identifiers introduced in subsequent declarations of that sequence is unknown. Thus, the identifiers used in the statements of a procedure declaration or the statements of a local module declaration of a block may not be identifiers whose defining occurrence is given in a subsequent declaration of that block.

### Constant Declarations

A constant declaration introduces an identifier as a synonym for a value. The value is specified by a constant expression. Each occurrence of the identifier is equivalent to an explicit occurrence of the value itself.

Concrete Syntax

constant declaration= identifier, "=", constant expression ;

Declaration Semantics

The identifier of a constant declaration shall be defined as a constant identifier that is associated with the type and value given by the evaluation of the constant expression at the point of the constant declaration.

annotations The identifier is associated with the constant value, and its type, in the consts component of the constructed environment.

Static Semantics

The expression component of a constant declaration shall be a constant expression. The identifier of a constant declaration shall not be used in the constant expression.

Note: The value of a constant expression can be determined statically since a constant expression can be completely evaluated by an analysis of the source code without executing the program --- see Constant Expressions.

Dynamic Semantics

The elaboration of a constant declaration shall associate, in the resulting execution environment, the identifier of the declaration, the value obtained from the evaluation of the constant expression, and the type of that value.

### Type Declarations

Every value and every variable has a type --- see Data Types and Predefined Types. The type of a value determines the operations that may be applied to that value --- see Expression Compatibility and Value Parameter Compatibility. The type of a variable determines the set of values that may be assigned to that variable and determines the other operations that may be applied to that variable --- see Assignment Compatibility and Variable Parameter Compatibility.

Type declarations are used to introduce new identifiers for existing identified types and to introduce identifiers for new types. Type identifiers may be used in variable declarations to specify the type of declared variables and are needed in procedure headings to specify the types of formal parameters and the return type of function procedures.

Notes:

1. Type identifiers are not always needed in variable declarations since variables can be declared to be of a new type. In that case, the new type is an anonymous type since no type identifier is associated with that type.

2. Each occurrence of a new type defines a type that is different from any other type.

Concrete Syntax

type declaration= identifier, "=", type denoter ;

Declaration Semantics

The identifier of a type declaration shall be defined as a type identifier that is associated with the unique type denoted by the type denoter.

Note: If the type denoter of a type declaration denotes a new enumeration type, the identifiers of the identifier list of the enumeration type are declared as constant identifiers of values of the enumeration type --- see Enumeration Types.

annotations The identifier is associated with a unique name for the type in the types component of the constructed environment, and the unique name for the type is associated with its structure in the strucs component of that environment.

Static Semantics

The identifier of a type declaration shall not be used in the type denoter unless its use is within a new pointer type or a new procedure type.

Example: Use of the identifier of a type declaration in the type denoter.

        ScanState = (* The type of lexical scanning control procedures *)
         PROCEDURE (CHAR, VAR ScanClass, VAR ScanState);

This type declaration is taken from the standard strings conversion library --- see ???.

Dynamic Semantics

The elaboration of a type declaration shall associate, in the resulting execution environment, the identifier of the declaration and the unique type that is the result of the elaboration of the type denoter

### Variable Declarations

A variable declaration serves to declare one or more variables of a specified type and to introduce an identifier for each variable. Each variable declared in a variable declaration can be associated with a specified address.

Concrete Syntax

variable declaration= variable identifier list, ":", type denoter ;

variable identifier list=
identifier, [ machine address ], { ",", identifier, [ machine address ] } ;

machine address= "[", value of address type, "]" ;

value of address type= constant expression ;

Abstract Syntax

annotations Identifiers may only occur once in a variable identifier list, and thus the cardinality of the set of identifiers of a Variable-declaration is the same as the number of identifiers in the variable identifier list.

Declaration Semantics

The identifiers of a variable declaration shall be defined as variable identifiers of variables that are of the unique type denoted by the type denoter.

Notes:

1. If the type denoter of a type declaration denotes a new type, the new type is an anonymous type since no type identifier is associated with that type.

2. If the type denoter of a type declaration denotes a new enumeration type, the identifiers of the identifier list of the enumeration type are declared as constant identifiers of values of the enumeration type --- see Enumeration Types.

annotations The identifiers are associated with a unique name for the type in the vars component of the constructed environment, and the unique name for the type is associated with its structure in the strucs component of that environment.

Static Semantics

The identifiers occurring in the variable identifier list of a variable declaration shall not be used in the type denoter.

Each machine address appearing in a variable declaration shall be a constant expression of the address type.

Notes:

1. Since the declarations of a block may include only one defining occurrence of a particular identifier, the identifiers occurring in the variable identifier list of a variable declaration must be distinct from each other --- see Declarations.

2. Constant values of the address type may only be formed by application of the predefined function procedures `MAKEADR` or `CAST` from the system module `SYSTEM`. The use of a machine address to fix the address of a variable thus requires a direct or indirect import from `SYSTEM`.

Dynamic Semantics

The elaboration of a variable declaration shall associate, in the resulting execution environment, the identifiers of the declaration with variables of the unique type denoted by the type denoter.

Storage shall be allocated for each variable as appropriate for the type of the variables. If a machine address is used in declaring a variable, the storage shall be allocated at the given address.

annotations The elaboration of a variable declaration involves the elaboration of the type information to give the structure of the storage associated with the type, followed by the allocation of that storage. The variable identifier is associated with the storage by using a mapping in the environment.

Auxiliaries

annotations Storage is allocated for each of the variables declared in the variable declaration.

annotations If the variable is of an elementary type, storage is allocated for it and information about the storage is added to the environment. If the variable is structured, then storage is allocated for each of its components, and the storage information is added to the environment. The result of this operation is the updated environment.

### Procedure Declarations

There are two kinds of procedures, namely proper procedures and function procedures. A proper procedure is activated by a procedure call statement. A function procedure is activated by a function call as a factor of an expression, and yields a result that is used as an operand in the expression. A function procedure declaration is distinguished from a proper procedure declaration by its heading --- see Procedure Headings.

A full procedure declaration consists of a procedure heading followed by a procedure block. The procedure block gives the declarations that are to be elaborated when the procedure is activated and the procedure body that is to be executed on that activation.

A forward procedure declaration consists of a procedure heading followed by the keyword `FORWARD`. A forward dec- laration may be used to avoid the forward references that would otherwise occur when two or more full procedure declarations contain mutually recursive references, and which will not be accepted by an implementation choosing the `declare before use model' --- see Ordering of Procedure and Module Declarations.

Concrete Syntax

procedure declaration=
proper procedure declaration | function procedure declaration ;

Static Semantics

If a forward declaration of a procedure is made, it shall precede a corresponding full declaration of that procedure. The full declaration shall be made in the same block or in a nested local module from which it is exported unqualified.

A procedure that is exported from a separate module, having a corresponding procedure heading in the definition module, shall not be given a forward procedure declaration in the implementation module.

The parameter lists of the headings of the forward declaration of the procedure and full declaration of that procedure shall match. The formal parameter lists of procedure headings shall match if the formal types of each of the value parameter specifications or variable parameter specifications of corresponding formal parameters are the same.

Note: The rule for matching the procedure headings of forward and full procedure declarations is the same as the rule for matching the definition of a procedure in a definition module and the corresponding declaration of that procedure in the implementation module --- see Program Module and Separate Module Consistency. The identifiers used to denote the parameters need not be the same, and the identifiers used to denote the types of these parameters need not be the same.

- Proper Procedure Declarations
- Function Procedure Declarations

#### Proper Procedure Declarations

A proper procedure declaration consists of a proper procedure heading, which declares the procedure identifier and the formal parameters, followed by the keyword `FORWARD` in the case of a forward procedure declaration, or followed by a proper procedure block in the case of a full procedure declaration. The proper procedure block contains the local declarations and the procedure body that is executed when the procedure is called.

Concrete Syntax

proper procedure declaration=
proper procedure heading, ";",
( proper procedure block, procedure identifier | "FORWARD" ) ;

procedure identifier= identifier ;

In a full proper procedure declaration the procedure identifier of the proper procedure heading shall be identical to the procedure identifier following the proper procedure block of that declaration.

Change: The keyword `FORWARD` is not in early editions of Programming in Modula-2 .

Declaration Semantics

A proper procedure declaration shall, through its heading, declare its identifier as a procedure identifier of a proper procedure structure, with the declared number, positions, and types of parameters, and with the declaration level of the block in which it is declared.

Note: The blocks of static modules are at the declaration level of 0. The declaration level of a procedure block is one more than the declaration level of the block in which the procedure is declared.

Within the block of a full proper procedure declaration, the proper procedure heading shall declare the identifiers of any formal parameters to be variable identifiers of variables that are of the type denoted by the corresponding formal type.

Static Semantics

The identifiers declared as formal parameters in the formal parameter list of the proper procedure heading of a proper procedure declaration shall be distinct from each other, and distinct from the formal type identifiers.

The identifiers declared in the declarations of a full proper procedure declaration shall be distinct from the identifiers declared as formal parameters in the formal parameter list of the proper procedure heading, and the declarations shall be well-formed given the environment that applies at the point of the procedure declaration, as overwritten by the parameters declared in the procedure heading.

Given a declaration level greater by one than the declaration level of the block in which the procedure is declared, and given the environment that applies at the point of the procedure declaration, as overwritten by the parameters declared in the procedure heading:

- the bodies of module and procedure declarations of a full proper procedure declaration shall be well-formed --- see Ordering of Procedure and Module Declarations,

- if present, the body of the procedure block shall be a well-formed proper procedure body --- see Proper Procedure Blocks.

Note: The environment that applies at the point of the procedure declaration depends upon the `declare before use' rule that is applied --- see Ordering of Procedure and Module Declarations.

Dynamic Semantics

The elaboration of a full proper procedure declaration shall associate, in the resulting execution environment, the procedure identifier with a procedure value corresponding to the proper procedure block. The associated procedure value shall be such that, on activation, the actual parameters will be bound to the formal parameters and the proper procedure block will be executed.

Notes:

1. The binding of the actual parameters to the formal parameters includes the allocation of storage for the parameters --- see Argument Binding.

2. The elaboration of the declarations of the procedure block, including the allocation of storage for the local variables of the procedure block, occurs on the execution of the block.

3. Conforming implementations are required to document rules for the calculation of the amount of workspace that will be needed by a single activation of a particular proper procedure (without taking into account the workspace needed by any procedure that it calls) --- see ???.

The associated procedure value shall also be such that, on normal or exceptional completion of the execution of the proper procedure block, the storage associated with the parameters will be freed.

annotations The elaboration of a proper procedure declaration is a proper procedure denotation that is the meaning of the parameters followed by the meaning of the block of the procedure.

Auxiliaries

annotations Check that the identifiers declared in a proper procedure heading are not re-declared in the associated proper procedure block.

annotations The result is an identifier that is the name of a formal parameter.

#### Function Procedure Declarations

A function procedure declaration consists of a function procedure heading, which declares the procedure identifier, the formal parameters and the result type of the function procedure, followed by the keyword `FORWARD` in the case of a forward procedure declaration, or followed by a function procedure block in the case of a full procedure declaration. The function procedure block contains the local declarations and the procedure body that evaluates the result of the procedure.

Concrete Syntax

function procedure declaration=
function procedure heading, ";",
( function procedure block, procedure identifier | "FORWARD" ) ;

In a full function procedure declaration the procedure identifier of the function procedure heading shall be identical to the procedure identifier following the function procedure block of that declaration.

Change: The keyword `FORWARD` is not in early editions of Programming in Modula-2 .

Declaration Semantics

A function procedure declaration shall, through its heading, declare its identifier as a procedure identifier of a function procedure structure, with the declared number, positions, and types of parameters, with the declared result type, and with the declaration level of the block in which it is declared.

Note: The blocks of static modules are at the declaration level of 0. The declaration level of a procedure block is one more than the declaration level of the block in which the procedure is declared.

Within the block of a full function procedure declaration, the function procedure heading shall declare the identifiers of any formal parameters to be variable identifiers of variables that are of the type denoted by the corresponding formal type.

Static Semantics

The identifiers declared as formal parameters in the formal parameter list of the proper procedure heading of a proper procedure declaration shall be distinct from each other, and distinct from the formal type identifiers.

The identifiers declared in the declarations of a full function procedure declaration shall be distinct from the identifiers declared as formal parameters in the formal parameter list of the function procedure heading, and the declarations shall be well-formed given the environment that applies at the point of the procedure declaration, as overwritten by the parameters declared in the procedure heading.

Given a declaration level greater by one than the declaration level of the block in which the procedure is declared, and given the environment that applies at the point of the procedure declaration, as overwritten by the parameters declared in the procedure heading:

- the bodies of module and procedure declarations of a full function procedure declaration shall be well-formed --- see Ordering of Procedure and Module Declarations,

- given the type denoted by the function result type, the body of the procedure block shall be a well-formed function procedure body --- see Function Procedure Blocks.

Note: The environment that applies at the point of the procedure declaration depends upon the `declare before use' rule that is applied --- see Ordering of Procedure and Module Declarations.

Dynamic Semantics

The elaboration of a full function procedure declaration shall associate, in the resulting execution environment, the procedure identifier with a procedure value corresponding to the function procedure block. The associated procedure value shall be such that, on activation, the actual parameters will be bound to the formal parameters, and the function procedure block will be executed.

Notes:

1. The binding of the actual parameters to the formal parameters includes the allocation of storage for the parameters --- see Argument Binding.

2. The elaboration of the declarations of the procedure block, including the allocation of storage for the local variables of the procedure, occurs on the execution of the block.

3. Conforming implementations are required to document rules for the calculation of the amount of workspace that will be needed by a single activation of a particular function procedure (without taking into account the workspace needed by any procedure that it calls) --- see ???.

The associated procedure value shall also be such that, on normal or exceptional completion of the execution of the function procedure block, the storage associated with the parameters will be freed, and, on normal completion, the result value will be returned to the caller of the function procedure.

Note: Normal completion of a function procedure block occurs on the execution of a return statement of that block.

annotations The elaboration of a function procedure declaration is a function procedure denotation that is the meaning of the parameters followed by the meaning of the block of the procedure.

Auxiliaries

annotations Check that the identifiers declared in a function procedure heading are not redeclared in the associated function procedure block.

### Local Module Declarations

A local module consists of a sequence of import lists, an optional export list, a sequence of declarations, and an optional module body. Both of these sequences may be empty. The import lists, if present, control the visibility of identifiers declared outside the module but usable within it. The export list, if present, controls the visibility of identifiers declared inside the module and usable outside it.

A local module may have a protection specified in its heading. The statements and procedures in the domain of protection are then executed under a protection as specified by the protection expression and the optional access- control procedures --- see Protected Modules.

Concrete Syntax

local module declaration=
"MODULE", module identifier, [ interrupt protection ], ";",
import lists, [ export list ],
module block, module identifier ;

The two module identifier components of a module declaration shall be identical.

Declaration Semantics

A local module declaration shall declare its identifier as a module identifier that may be used to qualify the identifiers exported from that module. In the case of unqualified export, the scope of the exported identifiers shall include the block in which the module is declared.

If the module is a protected module, or if the module is exported from an enclosing protected module, any exported procedures shall be protected procedures; otherwise, any exported procedures of the module that are also exported from an enclosing protected module shall be protected procedures.

Static Semantics

A local module shall not import itself. If present, the import lists and the declarations of a local module block shall be consistent with one another --- see Import Consistency in Module Blocks. If present, the import lists of a local module shall be valid given the environment that applies at the point of the local module declaration --- see Import Lists.

If present, an export list of a local module shall be valid given the environment that is constructed from the declarations of the local module block --- see Export Lists.

Any identifiers that are explicitly exported from a local module shall not be the identifiers of control variables of for statements of the module block.

The declarations of the local module shall be well-formed given the identifiers that are imported into the module.

If present in the local module heading, the interrupt protection shall be a valid interrupt protection in the context of the environment that applies at the point of the module declaration --- see Protected Modules.

Given the environment that applies at the point of the local module declaration, restricted to the identifiers that are imported into the module:

- the bodies of module and procedure declarations of the module block shall be well-formed --- see Ordering of Procedure and Module Declarations,

- if present, the body of the module block shall be a well-formed module body --- see Module Blocks.

Note: The environment that applies at the point of the local module declaration depends upon the `declare before use' rule that is applied --- see Ordering of Procedure and Module Declarations.

Dynamic Semantics

The elaboration of a local module declaration shall elaborate the declarations of the module block, given the meaning of the imported identifiers, and shall associate, in the resulting execution environment, the module identifier with the identifiers that are exported by the local module, and the identifiers that are exported unqualified with their associated entities.

If the local module is a protected module, the protection specified for that local module shall be used to protect the protection domain of the local module, instead of the protection of any enclosing protected module.

Note: Only the innermost protection domain applies to procedures exported through more than one enclosing protected module.

Note: The local module is executed on static or dynamic module initialization --- see Static Module Initialization and Dynamic Module Initialization.

### Auxiliary Formal Model Definitions

- Identifiers Defined in Definitions
- Identifiers Declared in Declarations
- Identifiers Defined in New Types
- Qualified Identifiers Used in Declarations
- Qualified Identifiers used in Expressions
- Qualified Identifiers Used in Types
- Qualified Identifiers Used in Parameters
- Shielded Environments and Shielded Identifiers

#### Identifiers Defined in Definitions

annotations The result of this operation is a set containing those identifiers that have been defined in a sequence of definitions.

annotations Return a set containing those identifiers that have been explicitly defined by a definition.

annotations Return a set containing those identifiers that have been implicitly defined in a definition - namely enumeration constants.

#### Identifiers Declared in Declarations

annotations The result of this function is a set containing those identifiers that have been declared in a sequence of declarations.

annotations Return a set containing those identifiers that have been declared in a declaration.

annotations Return a set containing those identifiers that have been implicitly declared in a declaration --- namely enumeration constants.

#### Identifiers Defined in New Types

annotations Return a set of identifiers containing all the identifiers defined in a type component of a definition. These are the enumeration type constants (identifiers).

annotations Return a set of the identifiers defined in a fields list.

annotations Return a set of the identifiers defined in fields. These are the enumeration type constants (identifiers) defined in any type components of the components of the fields.

annotations Return a set of the identifiers defined in a variant. These are the enumeration type constants (identifiers) defined in the components of the variant.

#### Qualified Identifiers Used in Declarations

annotations The result is a set containing those qualified identifiers that have been used in a sequence of declarations.

annotations The result is a set containing those qualified identifiers that have been used in the declaration of an identifier.

#### Qualified Identifiers used in Expressions

annotations The result is a set of qualified identifiers used in an expression; this is the set containing all the qualified identifiers used in the components of the expression.

annotations The result is the set of qualified identifiers used in an infix expression; this is the set that is the union of the sets of qualified identifiers used in both of the expression components of the infix expression.

annotations The result is the set of qualified identifiers used in a prefix expression; this is the set of qualified identifiers used in the expression component of the prefix expression.

annotations The result is the set of qualified identifiers used in a value designator; this is the set of qualified identifiers used in either an entire value, an indexed value, a selected value, or a dereferenced value. The set of qualified identifiers used in an entire value consists of the qualified identifier used to denote the entire value. The set of qualified identifiers used in an indexed value consists of the qualified identifiers used in the value designator component together with the qualified identifiers used in the expression component. The set of qualified identifiers used in a selected value consists of the qualified identifiers used in the value designator component. The set of qualified identifiers used in a dereferenced value consists of the qualified identifiers used in the value designator component.

annotations The result is the set of qualified identifiers used in a function call; this is the set of qualified identifiers used in the function designator component, together with the qualified identifiers used in the actual parameters of the function call.

annotations The result is the set of qualified identifiers used in the actual parameters of a function call; this set consists of all the qualified identifiers used in each of the actual parameters.

annotations The result is a set of qualified identifiers used in an actual parameter to a procedure or function call; this set consists of the qualified identifiers used in the actual parameter.

annotations The result is the set of qualified identifiers used in a variable designator; this is the set of qualified identifiers used in either an entire designator, an indexed designator, a selected designator, or a dereferenced designator. The set of qualified identifiers used in an entire designator consists of the qualified identifier used to denote the entire variable. The set of qualified identifiers used in an indexed designator consists of the qualified identifiers used in the variable designator component together with the qualified identifiers used in the expression component. The set of qualified identifiers used in a selected designator consists of the qualified identifiers used in the variable designator component. The set of qualified identifiers used in a dereferenced designator consists of the qualified identifiers used in the variable designator component.

annotations The result is the set of qualified identifiers used in a value constructor; this set consists of the qualified identifiers used either in an array constructor, a record constructor, or a set constructor.

annotations The result is the qualified identifiers used in an array constructor; this set consists of the union of the qualified identifiers used in all the expression components of the array constructor together with the qualified identifier used to denote the array.

annotations The result is the set of qualified identifiers used in a record constructor; this set consists of the union of the qualified identifiers used in all the expression components of the record constructor, together with the qualified identifier used to denote the record.

annotations The result is the set of qualified identifiers used in an element of a value constructor.

annotations The result is the set of qualified identifiers used in a set constructor; this set consists of the union of the qualified identifiers used in all the members of the set constructor together with the qualified identifier used to denote the set.

annotations The result is the set of qualified identifiers used in a member; this set consists of the union of the qualified identifiers used in the expression component(s) of the member.

#### Qualified Identifiers Used in Types

annotations The result is the set of qualified identifiers used in a type; the members of this set are the qualified identifiers used to denote type names and any qualified identifiers that appear in any constant expressions. The set does not include those type identifiers that are shielded either by `POINTER TO` or by `PROCEDURE`.

annotations The result is the set of qualified identifiers used in a fields list; these are the qualified identifiers used to denote type names in each of the components of the fields list.

annotations The result is the set of qualified identifiers used in fields; these are the qualified identifiers used to denote type names in each of the components of the fields.

annotations The result is the set of qualified identifiers used in variants; these are the qualified identifiers used in each of the components of the variants.

annotations The result is the set of qualified identifiers used in a variant; these are the qualified identifiers used in the labels component and fields component of the variant.

#### Qualified Identifiers Used in Parameters

annotations The result is the set of qualified identifiers used in parameters; these are the qualified identifiers used in each of the components of the parameters.

annotations The result is the set of qualified identifiers used in a parameter; these are the qualified identifiers used to denote type names in the formal type of the parameter.

annotations The result is the set of qualified identifiers used in a formal type; these are the qualified identifiers used to denote type names in either a parameter formal type or an array formal type.

annotations The result is the set of qualified identifiers used in a formal type; these are the qualified identifiers used to denote type names in an array formal type.

#### Shielded Environments and Shielded Identifiers

annotations The result of this operation is a set consisting of those qualified identifiers that are shielded in a declaration. An identifier is shielded if it is used within a new pointer type or a new procedure type.

annotations Return a set of qualified identifiers consisting of all the identifiers that are shielded in a type component of a definition.

annotations Return the set of qualified identifiers shielded in a fields list; these are the identifiers that are shielded in each of the components of the field list.

annotations Return the set of qualified identifiers shielded in fields.

annotations Return the set of qualified identifiers shielded in variants.

annotations Return the set of qualified identifiers shielded in a variant.

## Data Types

Every value and every variable has a type. The type of a value determines the operations that may be applied to that value --- see Expression Compatibility and Value Parameter Compatibility. The type of a variable determines the set of values that may be assigned to that variable and determines the other operations that may be applied to that variable --- see Assignment Compatibility and Variable Parameter Compatibility.

Some types, such as the number types, are basic to the language. For every basic type, the language provides a set of fundamental operations that may be performed on values of the type. Other types are constructed, using mechanisms provided by the language, as enumeration, subrange, opaque, set, pointer, procedure, array, and record types.

A distinction is made between elementary types and structured (composite) types. Array types and record types are structured types in the sense that values or variables of such types are compositions of other constituent values or variables which may be denoted as such. Values or variables of an elementary type have no constituents that may be denoted as components.

Note: The term structured type has been adopted from Programming in Modula-2 . However, constructed types other than array types and record types also have a structure. For example, procedure types have a specified number of parameters of specified types. Where there might be ambiguity, array and record types are also referred to as composite types in this International Standard.

Ordinal types are types for which the permitted values form a discrete set for which there is a complete ordering; ordinal types are therefore elementary types. Of the basic types, the Boolean, character, unsigned, signed, and Ztypes are all ordinal types. Of the constructed types, enumeration types and subrange types are ordinal types. The ordinal number of a value of an ordinal type may be ascertained using the standard function procedure `ORD` --- see The Function ORD.

- Type Denoters and Ordinal Type Denoters
- Type Identifiers
- New Types
- Enumeration Types
- Subrange Types
- Set Types
- Packedset Types
- Pointer Types
- Procedure Types
- Formal Types
- Array Types
- Record Types
- Storage Allocation

### Type Denoters and Ordinal Type Denoters

Type denoters are used to refer to existing identified types or to new types. The form of type denoter that is used to refer to an identified type is a type identifier. The identified type must either have a predefined identifier or an identifier must be introduced in a type definition or a type declaration --- see Predefined Types, Chapter System Modules, Type Definitions and Type Declarations.

The form of type denoter that is used to refer to a new type has the effect of establishing a programmer-defined type that is distinct from any other type. This unique type will only become an identified type if the new type is being used as the type denoter in a type definition or a type declaration; otherwise the unique type is an anonymous type.

Apart from their use as type denoters in type declarations, new types may be used as type denoters in variable declarations. In addition to their use as type denoters in type declarations and variable declarations, type identifiers may be used to denote formal parameter types in procedure headings and in procedure types --- see Procedure Headings and Procedure Types.

There are constructs in the language which require an ordinal type to be denoted rather than a general type. For example, the base type of a set type and the index type of an array type must be ordinal types. The concrete syntax uses the category `ordinal type denoter' to indicate that a denoter of some ordinal type is expected. The form of ordinal type denoter that is used to refer to an identified ordinal type is an ordinal type identifier. The form of ordinal type denoter that is used to establish an ordinal type that is distinct from any other type is a new ordinal type. Enumeration types and subrange types are the two forms of new ordinal type.

Concrete Syntax

type denoter= type identifier | new type ;

ordinal type denoter= ordinal type identifier | new ordinal type ;

Abstract Syntax

annotations In the translation from concrete to abstract syntax a value of type Type-identifier is used if the concrete syntax contains an ordinal type identifier, and a value of type New-type is used if the concrete syntax contains a new ordinal type.

Declaration Semantics

annotations The functions specifying the declaration semantics translate a new type into a type structure in which any new type component of the new type has been replaced by a unique type name (a `hidden' name that cannot be generated in source code). Thus the `new types' defined by some type declarations and variable declarations are each denoted by a name that is unique with respect to the complete program. Any type identifier occurring within a new type is replaced by its corresponding unique type name. The unique type name is associated with its structure by a mapping that is a component of the environment. Type identifiers are associated with their unique type names by a mapping that is another component of the environment. Thus an identifier denoting a type is mapped by a component of the environment into a unique type name, and that type name is mapped by a component of the environment into the structure of that type.

### Type Identifiers

A type identifier denotes an identified type that is predefined or is defined elsewhere in a type definition or a type declaration --- see Type Definitions and Type Declarations. There are some predefined types for which there are predefined type identifiers that are are pervasive --- see Predefined Types. The pervasive identifiers for the basic types are `BOOLEAN`, for the Boolean type; `CARDINAL`, for the unsigned type; `CHAR`, for the character type; `COMPLEX`, for the complex type; `INTEGER`, for the signed type; `LONGCOMPLEX`, for the long complex type; `LONGREAL`, for the long real type; and `REAL`, for the real type. The pervasive identifiers for the predefined constructed types are `BITSET`, for the bitset type (which is a packedset type); and `PROC`, for the proc type (which is a procedure type). `PROTECTION` is a pervasive identifier for the implementation- defined protection type --- see The Protection Type.

All of the types with pervasive identifiers are elementary types.

Concrete Syntax

type identifier= qualified identifier ;

ordinal type identifier= type identifier ;

Declaration Semantics

A type identifier shall denote the unique type that is associated with the qualified identifier.

Static Semantics

The qualified identifier shall denote a type that is predefined or is defined elsewhere in a type definition or a type declaration --- see Type Definitions and Type Declarations.

### New Types

A new type denotes a unique programmer-defined type and specifies the structure of values and variables of that type.

Concrete Syntax

new type=
new ordinal type | set type |
packedset type | pointer type |
procedure type | array type |
record type ;

new ordinal type= enumeration type | subrange type ;

Declaration Semantics

Each use of a new type shall be a defining occurrence for a type that is distinct from any other type and that has the structure specified by the new type.

### Enumeration Types

An enumeration type defines a new ordinal type, whose sequence of values is denoted by the sequence of identifiers contained in its identifier list. The identifiers of an enumeration type are introduced into their scope as constant identifiers of the values of the new type.

Concrete Syntax

enumeration type= "(", identifier list, ")" ;

identifier list= identifier, { ",", identifier } ;

Declaration Semantics

Each identifier occurring in the identifier list of an enumeration type shall be defined as a constant identifier that is associated with the corresponding value of the unique type established for the new type.

The type established by an enumeration type shall be an ordinal type. The ordering of the values of an enumeration type shall be determined by the textual order in which the identifiers of the identifier list are written. The ordinal number of the value associated with the ith identifier of the list shall be the value (i - 1)

annotations A unique type name is generated to denote the new type that is being defined. The identifiers occurring in the identifier list are added to the environment as constants, each constant being associated with the value it denotes. The structure of the new type is also added to the environment.

Static Semantics

The identifiers occurring in the identifier list of an enumeration type shall be distinct from each other.

### Subrange Types

A subrange type defines a new ordinal type, whose sequence of values is a subsequence of those defined for an associated ordinal type, called the `host type' of the subrange type. A subrange type specifies the smallest and the largest values of the ordinal type; a value to be assigned to a variable of a subrange type must lie within the closed interval defined by these two values. The operations that are applicable to operands of a subrange type are those that are applicable to operands of its host type.

The host type of a subrange type is determined by the type associated with the range of values from the smallest to the largest value. There are rules for choosing a default type for this range in cases where there are alternatives. For example, if the smallest and largest values are both specified by positive whole number literals, the type of the range is assumed to be the unsigned type and not the signed type. Alternatively, a range type may be explicitly specified with the subrange type.

Change: In Programming in Modula-2 the term `base type' is used for the associated ordinal type of both subrange types and set types. In this International Standard, the term `base type' is only used for set types, and the term `host type' is used for subrange types.

Concrete Syntax

subrange type=
[0 pt] [ range type ], "[", constant expression, "..", constant expression, "]" ;

range type= ordinal type identifier ;

Clarification: A range type may be specified in the definition of a subrange by providing an identifier denoting a previously defined ordinal type.

Abstract Syntax

annotations If the range type of a subrange type is not explicitly specified, the translation process (from concrete to abstract syntax) supplies a range type according to the table given under Static Semantics below.

Declaration Semantics

The values of a subrange type shall be the values of the range type that are in the closed interval defined by the `lower bound' and `upper bound' of the subrange type. These values shall be specified by the values of the first and second constant expressions, respectively.

If a type `X` is a subrange type, then its host type shall be the type that is the host type of the range type of the type `X`; otherwise the host type shall be the type `X`.

The type established by a subrange type shall be an ordinal type. The ordering of the values of a subrange type shall be determined by the ordering of the values of the host type. The ordinal number of a value of a subrange type shall be the same as the ordinal number which the value has in the host type.

annotations The range type of the subrange is determined, and the range is evaluated. A unique type name is generated to denote the new type that is being defined, and the structure of the new type is added to the environment.

Static Semantics

The range type of a subrange type shall be an ordinal type. If the range type is explicitly specified by an ordinal type identifier then this type identifier shall be predefined or have a defining occurrence that appears elsewhere; otherwise the range type of the subrange type `[M..N]` shall be determined according to the following table. In the table the type `T` denotes any ordinal type other than a whole number type.

N unsigned type signed type Z-type the type T unsigned type unsigned type error unsigned type error signed type error signed type signed type error M Z-type unsigned type signed type M<0 signed type error M?0 unsigned type the type T error error error the type T

Both the type of the first constant expression and the type of the second constant expression shall be expression- compatible with the range type. The lower bound shall be less than or equal to the upper bound, and the bounds shall both be values of the range type.

### Set Types

A set type defines a new elementary type whose set of values is the power set of an associated ordinal type, called the `base type' of the set type. Thus each value of a set type is a set whose elements are values of the base type of the set type.

Changes:

1. In Programming in Modula-2 the base type cannot have values that are less than zero.

2. This International Standard does not require a specific representation for set types. In Programming in Modula-2 there is some advice to the implementor to restrict the number of values of the base type, so that a value of a set type can be fitted into a small number of words of memory. In this International Standard, this advice is appropriate for packedset types rather than for set types.

3. In Programming in Modula-2 the pervasive identifier `BITSET` is the type identifier of a predefined set type, whereas in this International Standard, it is the type identifier of a predefined packedset type.

Concrete Syntax

set type= "SET", "OF", base type ;

base type= ordinal type denoter ;

Declaration Semantics

A new type that is a set type shall define the denoted base type as the base type of the unique set type that is established by the new type. The values of the set type shall be the elements of the power set of the base type of the set type.

annotations The base type of the set type is elaborated; a unique type name is generated to denote the new type that is being defined; and the structure of the new type is added to the environment.

Static Semantics

The type denoted by the base type of a set type shall be an ordinal type. If the base type is denoted by an ordinal type identifier, then this type identifier shall be predefined or have a defining occurrence that appears elsewhere; otherwise the base type shall be denoted by a new ordinal type.

Note: An implementation may place a restriction on the number of values of the base type of a set type --- see ???

Example: Declaration of set types. All of the following are valid declarations of set types provided that both of the bounds of each subrange type lie within the range of values of the signed type:

        TYPE
          s1 = SET OF INTEGER [0 .. N - 1] ;
          s2 = SET OF INTEGER [1 .. N] ;
          s3 = SET OF INTEGER [N + 1 .. 2*N] ;
          s4 = SET OF INTEGER [-2*N + 1 .. -N] ;

### Packedset Types

A packedset type defines a new elementary type whose set of values is the power set of an associated ordinal type, called the `base type' of the packedset type. Thus each value of a packedset type is a set whose elements are values of the base type of the packedset type.

Packedset types have a representation that can be mapped, in a known way, to the individual bits of a machine register for a particular underlying architecture --- see Packedset mapping. This leads to the ability to implement operations on values of a packedset type in a very efficient manner.

Note: The pervasive identifier `BITSET` is the type identifier of a predefined packedset type --- see The Bitset Type.

Change: Packedset types are not explicitly described in Programming in Modula-2 , where all set types are implicitly packedset types.

Concrete Syntax

packedset type= "PACKEDSET", "OF", base type ;

Declaration Semantics

A new type that is a packedset type shall define the denoted base type as the base type of the unique packedset type that is established by the new type. The values of the packedset type shall be the elements of the power set of the base type of the packedset type.

annotations The base type of the packedset type is elaborated; a unique type name is generated to denote the new type that is being defined; and the structure of the new type is added to the environment.

Static Semantics

The type denoted by the base type of a packedset type shall be an ordinal type. If the base type is denoted by an ordinal type identifier, then this type identifier shall be predefined or have a defining occurrence that appears elsewhere; otherwise the base type shall be denoted by a new ordinal type.

Notes:

1. Since packedset types are intended to mirror the underlying architecture, an implementation may impose narrow restrictions on the range of values of the base type of a packedset type --- see ???.

2. The representation of packedset types is defined by the semantics of bit-level operations on packedset values which are available by import from the system module `SYSTEM` --- see Packedset Functions

### Pointer Types

A pointer type defines a new elementary type. One of the values of every pointer type is called the nil value, and is denoted by the pervasive identifier `NIL`. The values of a pointer type other than the nil value can be used to designate variables of a type called the bound type of the pointer type. A value of a pointer type is frequently obtained by a call to an allocation procedure exported from a storage management module.

Note: The type of the nil value is an anonymous type called the `nil type'. All pointer types are assignment compatible (and hence value-parameter-compatible) with the nil type --- see Assignment Compatibility and Value Parameter Compatibility. All pointer types are expression- compatible with the nil type in pointer relational operations --- see Pointer Relational Operations.

Concrete Syntax

pointer type= "POINTER", "TO", bound type ;

bound type= type denoter ;

Declaration Semantics

A new type that is a pointer type shall define the denoted bound type as the bound type of the unique pointer type that is established by the new type.

annotations The bound type is elaborated; a unique type name is generated to denote the new type being defined; and the structure of the new type is added to the environment.

Static Semantics

If the bound type of a pointer type is specified by a type identifier, then this type identifier shall be predefined or have a defining occurrence that appears elsewhere; otherwise the bound type shall be specified by a new type.

Note: The declaration of a pointer type may precede the declaration of its bound type --- see Declarations.

### Procedure Types

A procedure type may be either a proper procedure type or a function procedure type.

Concrete Syntax

procedure type= proper procedure type | function procedure type ;

- Proper Procedure Types
- Function Procedure Types
- Formal Parameter Type Lists
- Variable Formal Types
- Value Formal Types

#### Proper Procedure Types

A proper procedure type defines a new elementary type. Each value of the type is a proper procedure, with a declaration level of 0, and with formal parameters that correspond with those defined in the formal parameter type list of the type.

Concrete Syntax

proper procedure type=
"PROCEDURE", [ "(", [ formal parameter type list ], ")" ] ;

Declaration Semantics

A new type that is a proper procedure type shall establish a unique procedure type that has the associated structure of a proper procedure with the number, positions, formal types, and binding of formal parameters specified by the formal parameter type list.

annotations The type of each of the parameters is elaborated; a unique type name is generated to denote the new type that is being defined; and the structure of the new type is added to the environment.

#### Function Procedure Types

A function procedure type defines a new elementary type. Each value of the type is a function procedure, with a declaration level of 0, with formal parameters that correspond with those defined in the formal parameter type list of the type, and with a result type that is identical to the function result type of the type.

Concrete Syntax

function procedure type=
"PROCEDURE", "(", [ formal parameter type list ], ")", ":", function result type ;

Declaration Semantics

A new type that is a function procedure type shall establish a unique procedure type that has the associated structure of a function procedure with the number, positions, formal types, and binding of formal parameters specified by the formal parameter type list, and with the result type that is denoted by the function result type of the new type.

annotations The type of each of the parameters is elaborated; the type of the returned value is elaborated; a unique type name is generated to denote the new type that is being defined; and the structure of the new type is added to the environment.

Static Semantics

The function result type shall be specified by a type identifier that is predefined or has a defining occurrence that appears elsewhere.

Clarification: In this International Standard, the function result type of a function procedure type can be any elementary type or structured (composite) type. It may be identical to the function procedure type.

#### Formal Parameter Type Lists

A formal parameter type list specifies the number of formal parameters of a procedure type, the formal type of each of these formal parameters, and whether each formal parameter is a value parameter or a variable parameter --- see Formal Parameters.

Concrete Syntax

formal parameter type list=
formal parameter type, { ",", formal parameter type } ;

formal parameter type=
variable formal type | value formal type ;

#### Variable Formal Types

A variable formal parameter type defines the formal type of a variable formal parameter of a procedure type.

Concrete Syntax

variable formal type= "VAR", formal type ;

Declaration Semantics

A variable formal type shall define the corresponding formal parameter of the procedure type to be a variable formal parameter of the declared formal type --- see Formal Types.

#### Value Formal Types

A value formal parameter type defines the formal type of a value formal parameter of a procedure type.

Concrete Syntax

value formal type= formal type ;

Declaration Semantics

A value formal type shall define the corresponding formal parameter of the procedure type to be a value formal parameter of the declared formal type --- see Formal Types.

### Formal Types

Formal types are used in procedure headings and in procedure types to specify the structure of formal parameters. The structure of a formal parameter may either be a single identified type or an open array of an identified type or of another open array.

Concrete Syntax

formal type= type identifier | open array formal type ;

open array formal type= "ARRAY", "OF", open array component type ;

open array component type= formal type ;

Change: This International Standard permits multidimensional open array parameters.

Declaration Semantics

A formal type that is a type identifier shall define the structure of the corresponding formal parameter, or open array component type, to be the single type that is denoted by the type identifier.

An open array formal type shall define the structure of the corresponding formal parameter, or open array component type, to be an open array with a component type that has the structure defined by the open array component type of the open array formal type.

Static Semantics

If a formal type is a type identifier, then this type identifier shall be predefined or have a defining occurrence that appears elsewhere.

Clarification: In this International Standard, the defining occurrence of a type identifier used as a formal type may be the definition or declaration of the procedure type in which that formal type occurs; the formal type of a procedure type may thus be of a type that is identical to the procedure type --- see Type Declarations.

If a formal type is an open array formal type, then the type identifier of the open array formal type shall be predefined or have a defining occurrence that appears elsewhere.

### Array Types

An array type defines a new structured (composite) type. An array type is a mapping from a set of values defined by an index type onto a set of distinct components. Each one of these components has the same type, called the component type of the array type.

Concrete Syntax

array type= "ARRAY", index type, { ",", index type }, "OF", component type ;

index type= ordinal type denoter ;

component type= type denoter ;

The concrete syntax allows for a full or abbreviated form of array type in cases where a component type is itself an array type. In the abbreviated form, a single comma shall replace the sequence ``OF ARRAY`' that occurs in the full form. The abbreviated form and the full form shall be equivalent.

Example: Abbreviated form for array of array types. An array type of the form:

        ARRAY MonthType OF ARRAY [1 .. 31] OF CARDINAL

may be abbreviated to:

        ARRAY MonthType, [1 .. 31] OF CARDINAL

Abstract Syntax

annotations The abstract syntax only uses the full form.

Declaration Semantics

If the index type ordinal type denoter of an array type (in its full form) is a new ordinal type, a corresponding new ordinal type shall be established for the index type; otherwise, if the index type ordinal type denoter is a type identifier, the index type shall be the corresponding identified type.

If the component type denoter of an array type (in its full form) is a new type, a corresponding new type shall be established for the component type; otherwise, if the component type denoter is a type identifier, the component type shall be the corresponding identified type.

The array type (denoter) shall establish a unique array type that has the specified index type and component type.

The type of each component of the array type shall be the component type of the array type.

annotations The types of the index and components are elaborated; a unique type name is generated to denote the new type that is being defined; and the structure of the new type is added to the environment.

Static Semantics

The index type of an array type shall be an ordinal type. If the index type is specified by an ordinal type identifier, then this type identifier shall be predefined or have a defining occurrence that appears elsewhere; otherwise the index type shall be specified by a new type that is an enumeration type or a subrange type. If the component type of an array type is specified by a type identifier, then this type identifier shall be predefined or have a defining occurrence that appears elsewhere; otherwise the component type shall be specified by a new type.

Note: If the index type of an array type is an enumeration type, the enumeration constant identifiers that are thereby declared may be used in the component type of the array type.

### Record Types

A record type defines a new structured (composite) type. Each value of the type has a collection of components. These components, called the fields of the record type, may be of different types. The individual fields of a value or variable of a record type are selected by their names (called field identifiers). A record type may specify that some groups of fields (called fixed fields) are always to be present in values and variables of that type. A record type may specify that other groups of fields (called variant fields) include alternatives (called variants) whose presence within a value or variable of that type depends upon the value of another field (called the tag field). The variant that applies, given the value of the tag field, is called the `active variant'.

Concrete Syntax

record type= "RECORD", field list, "END" ;

field list= fields, { ";", fields } ;

fields= [ fixed fields | variant fields ] ;

Declaration Semantics

A new type that is a record type shall establish a unique record type that has the structure of the group or groups of fields specified by the record type field list. Any enumeration constant identifiers introduced by enumeration types within a group of fields shall be defined for possible use within subsequent groups of fields.

annotations The type of each of the components of the record is elaborated; a unique type name is generated to denote the new type that is being defined; and the structure of the new type is added to the environment.

Static Semantics

All the field identifiers of a record type shall be distinct.

- Fixed Fields
- Variant Fields

#### Fixed Fields

A group of fields specified as fixed fields of a record type share the same field type; the group shall always be present in values and variables of the record type, unless the group is part of an inactive variant.

Concrete Syntax

fixed fields= identifier list, ":", field type ;

field type= type denoter ;

Declaration Semantics

If the field type of a group of fixed fields is a new type, a corresponding new type shall be established which shall be the type of each field in the group of fixed fields; otherwise, if the field type is a type identifier, the type of each field shall be the corresponding identified type.

annotations The type of the fixed fields component of the record is elaborated; a unique type name is generated to denote any new type that may be defined; the result is the structure of the component.

Static Semantics

If the field type of a group of fixed fields is specified by a type identifier, this type identifier shall be predefined or have a defining occurrence that appears elsewhere; otherwise the field type shall be specified by a new type.

#### Variant Fields

A groups of fields specified as variant fields of a record type include alternatives (called variants) whose presence within a value or variable of that type depends upon the value of another field (called the tag field). The variant that applies, given the value of the tag field, is called the `active variant'.

Concrete Syntax

variant fields= "CASE", tag field, "OF", variant list, "END" ;

tag field= [ tag identifier ], ":", tag type ;

tag identifier= identifier ;

tag type= ordinal type identifier ;

variant list= variant, { "|", variant }, [ variant else part ] ;

variant else part= "ELSE", field list ;

Declaration Semantics

The tag type of a group of variant fields shall be the ordinal type denoted by the tag type ordinal type identifier. If present, the tag identifier shall be defined as the field identifier of the tag field; otherwise, the group of variant fields shall not have an identifiable tag field.

The variants of a group of variant fields shall have the structure specified by each variant of the variant list and, if present, the variant else part. Any enumeration constant identifiers introduced by enumeration types within a variant shall be defined for possible use within subsequent variants, including a variant else part.

The variant else part, if present, shall have the structure of the group or groups of fields specified by the variant else part field list.

annotations The type of the tag field of the variant field is obtained; the structures of the variant components and of the optional variant else part list component are elaborated; the result is the structure of the component.

Static Semantics

The tag type of a group of variant fields shall be an ordinal type. The tag type shall be specified by an ordinal type identifier that is predefined or has a defining occurrence that appears elsewhere. The types of the constant expressions of the variant label list of each variant shall be expression compatible with the tag type.

The values contained in different variant label lists of a variant shall be distinct from each other.

Note: In addition to the requirement that the values contained in different variant label lists of a variant shall be distinct from each other, it is also required that the values contained in each variant label list shall be distinct from each other.

Example: Duplication of variant labels in record declarations. The alternatives illustrated in the following source code are illegal for the reasons given in the associated comments.

        TYPE
          TagRange = [1..19];
        RECORD
          CASE TagFieldIdentifier : TagRange OF
          | (*a*) 1           : (* duplicate of label in list d *)
          | (*b*) 11          : (* label 11 in b duplicated in range 11..13 in list i *)
          | (*c*) 15..17      : (* range 15..17 in c overlaps with range 16..19 in list j *)
          | (*d*) 1           : (* duplicate of label in list a *)
          | (*e*) 2, 2        : (* label 2 is duplicated in list e *)
          | (*f*) 3..5, 3..5  : (* range 3..5 is duplicated in list f *)
          | (*g*) 6, 6..7     : (* label 6 duplicated in range 6..7 in list g *)
          | (*h*) 8..9, 8..10 : (* range 8..9 overlaps range 8..10 in list h *)
          | (*i*) 11..13      : (* label 11 in b duplicated in range 11..13 in list i *)
          | (*j*) 16..19      : (* range 15..17 in c overlaps with range 16..19 in list j *)
          END
        END

If there is no variant else part, there shall be a value contained in the variant label lists for each value of the tag type.

Example: Coverage of variant labels in record declarations. The requirement that if there is no variant else part there shall be a value contained in the variant label lists for each value of the tag type means that example (a) is illegal, whereas examples (b) and (c) are legal.

        (a)			 (b)			 (c)
        RECORD		 RECORD			 RECORD
        CASE : INTEGER OF	 CASE : INTEGER OF	 CASE : INTEGER OF
        | 1: x: BOOLEAN	 | 1: x: BOOLEAN	 | 1: x: BOOLEAN
        | 2: y: CARDINAL	 | 2: y: CARDINAL	 | 2: y: CARDINAL
        END			 ELSE (*empty*)		 | MIN(INTEGER)..0: (*empty*)
        END			 END			 | 3..MAX(INTEGER): (*empty*)
       			 END			 END
       						 END

Variants

A variant specifies the value or values of the tag field for which the variant is to be active, and the group or groups of fields that are present when the variant is active.

Concrete Syntax

variant= [ variant label list, ":", field list ] ;

variant label list= variant label, { ",", variant label } ;

variant label= constant expression, [ "..", constant expression ] ;

Abstract Syntax

annotations The translation process (from concrete to abstract syntax) will ensure that the number of members in the labels component of a Variant component of the abstract representation is equal to the number of variant labels in the variant label list of the concrete representation.

Declaration Semantics

The values of the tag field for which the variant is to be active shall be the set of values contained in the variant label list. A value shall be contained in a variant label list if it is equal to the value of one of the constant expressions of the variant label list, or if the value lies within the range specified by a pair of constant expressions of the variant label list.

The group or groups of fields that are present when the variant is active shall be the those specified by the variant field list.

annotations The value of the labels that are associated with the variant are evaluated; the structures of the fields are elaborated; and the result is the structure of the component.

Static Semantics

Each variant label shall be a constant expression, or a range indicated by a pair of constant expressions. The values contained in a variant label list shall be distinct from each other.

Auxiliaries

annotations Check that all the field identifiers of a field list are distinct.

annotations The result of this function is a sequence containing the field identifiers of a record type. The order of the identifiers in the sequence is identical to the order in which they occur in the record type.

annotations The result of this function is a sequence containing the field identifiers of a fixed fields or a variant fields. The order of the identifiers in the sequence is identical to the order in which they occur in the fixed fields or variant fields.

annotations The result of this function is a sequence containing the field identifiers of a variant field component of a record. The order of the identifiers in the sequence is identical to the order in which they occur in the variant field component.

annotations The result of this function is a sequence containing the field identifiers of a variant component of a variant field of a record. The order of the identifiers in the sequence is identical to the order in which they occur in the variant component.

annotations Check that all of the variant labels are expression-compatible with the tag type.

annotations Check that the sets of values defined by each of the variant label lists are disjoint.

annotations Check that there is a value contained in the variant label lists for each value of the tag type.

### Storage Allocation

Program storage is allocated during the elaboration of variable declarations and during the binding of actual parameters to formal parameters that occurs on procedure calls.

annotations Note that a value of type Type has been replaced by a value of type Typed at this point | information on the type defined in the environment is used for storage allocation, rather than the type information defined by the source code.

- Allocating Storage for Constructed Types
- Allocating Storage for Elementary Types
- Allocating Storage for Structured (Composite) Types

#### Allocating Storage for Constructed Types

annotations Identifiers that have been declared as identifiers of variables or parameters of a constructed type have their type name looked up in the environment to give their structure, and storage is allocated for this structure.

#### Allocating Storage for Elementary Types

##### Allocating Storage for Basic Types

All basic types are elementary types | see 6.10.2.

annotations The storage for a whole-number variable is tagged withthe values included in the whole-number type; there are no individual storage-allocation functions for other basic types since they have no associated structure.

##### Allocating Storage for Subrange Types

annotations The storage for a subrange variable is tagged with the values included in the subrange.

##### Allocating Storage for Pointer Types

annotations The storage for a pointer variable is tagged with the type of the bound type of the pointer type.

#### Allocating Storage for Structured (Composite) Types

The meaning given to programs by this International Standard is independent of any particular layout strategy in mapping components of a variable of a structured (composite) type onto the addressable locations of an underlying computer system. The storage model of this International Standard, therefore allocates storage for each component of a variable of a structured (composite) type independently of any other components of that variable.

Note: Conforming implementations are required to document the layout strategy that is used for a particular target computer system --- see ???.

##### Allocating Storage for Array Types

Dynamic Semantics

The allocation of storage for a variable of an array structure shall allocate storage for each component of the array structure such that each component may be accessed using an indexed designator | see 6.7.2.

annotations The result is an array variable, which is a mapping from each value in the set specified by its index type to a distinct variable whose type is the component type of the array type.

##### Allocating Storage for Record Types

Dynamic Semantics

The allocation of storage for a variable of a record structure shall allocate storage for each group of fixed fields of the record structure such that each field may be accessed using a selected designator --- see Selected Designators.

The allocation of storage for a variable of a record structure shall allocate storage for each group of variant fields of the record structure such that each field of the active variant, and the tag field, if present, may be accessed using a selected designator --- see Selected Designators.

Note: In the case of a group of variant fields with an identified tag field, storage is allocated for the tag field and the active variant is determined by the value of that field. If there is no identified tag field, the storage model in this International Standard constructs an implicit tag field so that it can be specified that an exception occurs if a field of an inactive variant is accessed by a value designator --- see Selected Values.

annotations The result is a record variable that consists of a mapping from the identifier field names to the associated storage.

Allocating Storage for Fields

annotations The result is a record variable that consists of a mapping from the identifier field names to the associated storage.

Allocating Storage for Fixed Fields

annotations The result is a record variable that consists of a mapping from the identifier field names to the associated storage.

Allocating Storage for Implicitly Tagged Variants

annotations Allocate storage for each of the components of a variant fields component of a variant record.

annotations Construct a tagged variable from the tag location and the range of values associated with that variant component.

Allocating Storage for Explicitly Tagged Variants

annotations Allocate a storage location for the tag field. Allocate storage for each variant, and for the variant else part if it is present.

annotations Construct a mapping that associates a variant variable with each of the label values of a variant component.

Auxiliaries

annotations Construct a sequence of variant structures from a sequence of variants.

annotations Allocate storage space for the variant else part if it is present.

## Expression and Assignment Compatibility

The concept of compatibility between entities of possibly differing type is fundamental to Modula-2. Expression compatibility determines the types that may be combined in forming expressions; assignment compatibility determines, for a given type of variable, the type or types of the values of expressions that may be assigned to variables of that type.

There is a third form of compatibility, called `parameter compatibility', which determines for a given type and structure of formal parameter, the type and structure of the actual parameters that may be passed to formal parameters of that type and structure --- see Parameter Compatibility.

- Expression Compatibility
- Assignment Compatibility

### Expression Compatibility

Modula-2 limits the types that may be combined in forming expressions to identical types except that there are special rules where subrange types are involved and where literal values are involved. Expression compatibility is a symmetric relation --- a type of an expression T e1 is expression compatible with a type of an expression T e2 if T e 2 is expression compatible with T e1 .

Static Semantics

The types of two expressions shall be expression-compatible if any of the following statements is true:

a) The types are identical types.

b) One type is a complex number type and the other type is the C -type.

c) One type is a real number type and the other type is the R-type.

d) One type is a whole number type and the other type is the Z-type.

e) One type is the character type and the other type is the character literal type (the string literal type of length 0 or of length 1).

Change: In Programming in Modula-2 a string literal of length 0 represents the empty string only and the character type is not expression-compatible with the type of the empty string.

Notes:

1. A value of a subrange type is also a value of the host type of that subrange type, and the type of expressions that are value designators, or function calls, is defined in terms of the host type of any subrange type that might otherwise apply --- see Value Designators and Function Calls. Values of subranges of the same host type are therefore expression compatible with each other, and with that host type, under rule Expression Compatibilitya.
2. There are other special cases of expression compatibility for pointer relational operations and for procedure relational operations; these are dealt with where they arise --- see Relational Operations.

annotations The `t-...' functions used in applications of the function is-expression-compatible return the host type for values of a subrange type; thus this function does not need to deal with special rules for subrange types. In parts of the formal definition, expression compatibility between the types of two expressions, expra and exprb, is tested using relations of the form t-expression (expra )? = t-expression (exprb)?

### Assignment Compatibility

Modula-2 limits the types of value that may be assigned to a variable to identical types except that there are special rules for subrange types, literal values, whole number types, and the address type. Assignment compatibility is not a symmetric relation since the types of variables and of values are treated differently.

Within a procedure block, formal parameters are treated as variables to which assignments may be made. However, formal parameters are of a formal type and may have the structure of an open array | see 6.3.10. No direct assignments to open array formal parameters may be made, even from another open array formal parameter of identical structure.

Static Semantics

The type T v of a variable denoted by a variable designator shall be assignment-compatible with the type T e of the value of an expression if any of the following statements is true:

a) T v is identical to the type T e and that type is not a formal type having an open array structure.

b) T v is a subrange of the type T e .

c) T v is the unsigned type or a subrange of the unsigned type and T e is the signed type or is the Z-type.

d) T v is the signed type or a subrange of the signed type and T e is the unsigned type or is the Z-type.

e) T v is a real number type and T e is the R-type.

f ) T v is a complex number type and T e is the C -type.

g) T v is a pointer type and T e is the nil type.

h) T v is a proper procedure type or a function procedure type, and the expression designates a procedure value, or procedure constant value, of a procedure that has the same structure as the procedure type T v , and that has been declared at declaration level 0.

i) T v is the character type, or a subrange of the character type, and T e is the character literal type (the string literal type of length 0 or of length 1).

j) T v is an array type having the character type as its component type and T e is the string literal type of length less than or equal to the number of components in arrays of the type T v .

k) T v is the address type and T e is a pointer type, or T v is a pointer type and T e is the address type.

Notes:

1. A variable designator only occurs on the left-hand side of an assignment statement, or as an actual parameter that corresponds to a variable formal parameter; only the first of these uses is relevant to assignment compatibility. Variable identifiers that occur in expressions are value designators.

2. The component type of a concrete string type is the character type. Since it must be possible to assign the value of the character type that has been defined by an implementation as its string terminating character to a component of a concrete string variable, a quoted string is not assignment-compatible with an array whose component type is a subrange of the character type.

Changes:

1. In Programming in Modula-2 a string literal of length zero represents the empty string only and the character type is not assignment-compatible with the type of the empty string.

2. A concrete string type, i.e. an array whose component type is the character type, that is either the target of a string assignment, or a formal parameter to which a string is passed as an actual parameter, may have an index type of any ordinal type.

Clarification: This International Standard has not adopted a change to Modula-2 (described in the fourth edition of Programming in Modula-2 ) of always requiring a string terminator for a string value. The length of a string literal may therefore equal the number of components in an array to which it is assigned.

annotations The type of the variable designator and the type of the expression are identical. The result type of the expression is not an open array type.

annotations The type of the variable designator is a subrange of the type of the expression.

annotations The type of the variable designator is the unsigned type or a subrange of the unsigned type, and the type of the expression is the signed type or Z-type.

annotations The type of the variable designator is the signed type or a subrange of the signed type, and the type of the expression is the unsigned type or Z-type.

annotations The type of the variable designator is a real type and the type of the expression is the R-type.

annotations The type of the variable designator is a complex type and the type of the expression is the C -type.

annotations The type of the variable designator is a pointer type and the type of the expression is the nil type.

annotations The type of the variable designator is a proper procedure type or function procedure type, and the type of the expression is a proper procedure or function procedure value with the same structure, declared at level 0.

annotations The type of the variable designator is a character type, and the type of the expression is the character literal type.

annotations The type of the variable for string literal assignment is an array of characters. The result of the expression is a string literal, and the length of the string literal is less than or equal to the number of elements in the array associated with the type ltype .

annotations The type of the variable is the address type, and the result of the expression is a pointer type, or vice-versa.

## Blocks

Blocks consist of a possibly empty sequence of declarations which may be followed by a body; they are a component of program modules, implementation modules, local modules, and full procedure declarations. The body contains the statements that are to be executed when a module is initialized or finalized, or when a procedure is activated.

The presence of a body is required only for function procedure blocks; the bodies of function procedures return a result value whereas the bodies of modules and of proper procedures do not return a result value.

The presence of a body is marked by the keyword `BEGIN` which is followed by a block body. In the case of module blocks, the block body marked by the keyword `BEGIN` is the initialization body; it may be followed by a finalization body, marked by the keyword `FINALLY`. Block bodies have a normal part and, optionally, an exceptional part to handle exceptions raised during execution of the normal part.

The execution of the block bodies of protected modules and of protected procedures is protected from the occurrence of interrupts --- see Protected Modules.

- Proper Procedure Blocks
- Function Procedure Blocks
- Module Blocks
- Static Module Initialization
- Static Module Finalization
- Dynamic Module Initialization
- Dynamic Module Finalization
- Block Bodies and Exception Handling

### Proper Procedure Blocks

A proper procedure block defines the sequence of declarations and the optional procedure body that are associated with the proper procedure identifier. On a call of the procedure, the initialization bodies of any local modules declared in the declarations are executed. If a procedure body is present, it is then executed in an environment that includes identifiers introduced in the declarations of the procedure block.

Concrete Syntax

proper procedure block= declarations, [ procedure body ], "END" ;

procedure body= "BEGIN", block body ;

Abstract Syntax

annotations In the translation from concrete to abstract syntax, a proper procedure block without a procedure body is repre- sented by a Proper-procedure-block with a nil value for the body component.

Static Semantics

If present, the block body of a proper procedure block shall be a well-formed block body that does not return a result.

Dynamic Semantics

If there are local modules contained in the declarations of the proper procedure block, they shall be initialized in the textual order in which they occur --- see Dynamic Module Initialization.

On the execution of a proper procedure block that is not protected and does not have an exceptional part, the procedure body shall be executed in the state of exceptional execution or in the state of normal execution, according to the state of execution of the caller of the procedure.

Note: If the procedure block has no exceptional part, the exceptional part that is the current exception handler is found as follows:

- If the procedure has been called, directly or indirectly, from a normal part of another procedure block, or from the initialization body or finalization body of a module block, and the calling procedure or module block has an exceptional part, then that exceptional part will be the current exception handler.

- If the procedure has been called, directly or indirectly, from the exceptional part of a static module, no exceptional part will be the current exception handler.

- If the procedure has been called, directly or indirectly, from the exceptional part of another procedure, the current exception handler will be the exception handler for the caller of that other procedure.

- If the procedure has been called, directly or indirectly, from the exceptional part of a dynamic module, the current exception handler will be the exception handler for the caller of the procedure in which the dynamic module is declared.

If the procedure block has no exceptional part, and no other exceptional part is the current exception handler, the raising of an exception during the execution of the normal part is a termination event --- see Program Termination.

On completion of the execution of the procedure body, if there are local modules contained in the declarations of the proper procedure block, they shall be finalized in the reverse order of their initialization --- see Dynamic Module Finalization.

If an exception is raised during execution of the procedure body the local dynamic modules shall not be finalized.

If the procedure is a protected procedure, the protection domain shall be entered before the local dynamic modules are initialized and shall be left after the local dynamic modules have been finalized.

If an exception is raised during execution of the procedure body the protection domain shall not be left.

On the execution of a proper procedure block that has an exceptional part, the procedure body shall be executed in the state of normal execution.

On completion of the execution of the block body, the execution state shall revert to that which applied before the execution of the block body.

If execution of the procedure body completed in the state of exceptional execution, the exception shall be re-raised after the local dynamic modules have been finalized.

If an exception is raised during execution of the exceptional part of the procedure body, the local dynamic modules shall not be finalized.

On the execution of a proper procedure block that is protected and whose body has an exceptional part, if execution of the procedure body completes in the state of exceptional execution, the exception shall be re-raised after the protection domain has been left.

If an exception is raised during execution of the exceptional part of the procedure body, the protection domain shall not be left.

### Function Procedure Blocks

A function procedure block defines the sequence of declarations and the procedure body that are associated with the procedure identifier. On a call of the procedure, the initialization bodies of any local modules declared in the declarations are executed. The procedure body is then executed in an environment that includes identifiers introduced in the declarations of the procedure block.

Concrete Syntax

function procedure block= declarations, function body, "END" ;

function body= "BEGIN", block body ;

Change: Programming in Modula-2 allows the body of a function procedure to be empty, but the well-formed rules in this International Standard demand at least one return statement. The concrete syntax has been changed to reflect this.

Static Semantics

The block body of a function procedure block shall be a well-formed block body that returns a result.

Dynamic Semantics

If there are local modules contained in the declarations of the procedure block, they shall be initialized in the textual order in which they occur --- see Dynamic Module Initialization.

On the execution of a function procedure block, that is not protected and does not have an exceptional part, the procedure body shall be executed in the state of exceptional execution or in the state of normal execution, according to the state of execution of the caller of the procedure.

Note: If the procedure block has no exceptional part, the exceptional part that is the current exception handler is found as follows:

- If the procedure has been called, directly or indirectly, from an normal part of another procedure block, or from the initialization body or finalization body of a module block, and the calling procedure or module block has an exceptional part, then that exceptional part will be the current exception handler.

- If the procedure has been called, directly or indirectly, from the exceptional part of a static module, no exceptional part will be the current exception handler.

- If the procedure has been called, directly or indirectly, from the exceptional part of another procedure, the current exception handler will be the exception handler for the caller of that other procedure.

- If the procedure has been called, directly or indirectly, from the exceptional part of a dynamic module, the current exception handler will be the exception handler for the caller of the procedure in which the dynamic module is declared.

If the procedure block has no exceptional part, and no other exceptional part is the current exception handler, the raising of an exception during the execution of the normal part is a termination event --- see Program Termination.

On completion of the execution of the procedure body, if there are local modules contained in the declarations of the procedure block, they shall be finalized in the reverse order of their initialization --- see Dynamic Module Finalization.

If an exception is raised during execution of the procedure body the local dynamic modules shall not be finalized.

If the procedure is a protected procedure, the protection domain shall be entered before the local dynamic modules are initialized and shall be left after the local dynamic modules have been finalized.

If an exception is raised during execution of the procedure body the protection domain shall not be left.

On the execution of a function procedure block that is not protected but does have an exceptional part, the procedure body shall be executed in the state of normal execution.

On completion of the execution of the block body, the execution state shall revert to that which applied before the execution of the block body.

If execution of the procedure body completed in the state of exceptional execution, the exception shall be re-raised after the local dynamic modules have been finalized.

If an exception is raised during execution of the exceptional part of the procedure body, the local dynamic modules shall not be finalized.

On the execution of a function procedure block that is protected and has an exceptional part, if execution of the procedure body completes in the state of exceptional execution, the exception shall be re-raised after the protection domain has been left.

If an exception is raised during execution of the exceptional part of the procedure body, the protection domain shall not be left.

### Module Blocks

A module block consists of a sequence of declarations and an optional module body. It is a component of a program module, an implementation module, or a local module.

Module bodies have an initialization body and, optionally, a finalization body. The initialization body is executed during static module initialization or dynamic module initialization --- see Static Module Initialization and Dynamic Module Initialization. The finalization body, if present, is executed during static module finalization or dynamic module finalization --- see Static Module Finalization and Dynamic Module Finalization. Initial- ization and finalization takes place in an environment that includes identifiers introduced in the declarations of the module block.

Concrete Syntax

module block= declarations, [ module body ], "END" ;

module body= initialization body, [ finalization body ] ;

initialization body= "BEGIN", block body ;

finalization body= "FINALLY", block body ;

Abstract Syntax

annotations In the translation from concrete to abstract syntax, a module block with no module body is represented by a Module-block with nil values for both the initial and final components and a module body with no finalization body is represented by a Module-block with a nil value for the final component.

Static Semantics

If present, The initialization body of a module block shall be a well-formed block body that does not return a result.

If a module block has a finalization body, that body shall be a well-formed block body that does not return a result.

Dynamic Semantics

The elaboration of a module block shall allocate storage for the declarations of of the block.

### Static Module Initialization

Static module initialization applies to the initialization of the module blocks of implementation modules, to the execution of the program module block, and, recursively, to the initialization of local modules declared in these module blocks --- see Program Modules and Sourced Implementation Modules.

A module block comprises a sequence of declarations and, optionally, a module body. The local modules contained in the declarations of a static module block are initialized in the textual order in which they occur.

A module body comprises an initialization body and, optionally, a finalization body. Finalization bodies of static modules are executed during program termination --- see Program Termination and Static Module Finalization. If a coroutine causes termination, and starts to finalize the static modules, no further static modules are initialized --- see Program Termination.

The initialization body of a static module is executed in the environment defined by its import lists and declarations.

Dynamic Semantics

If program termination is in progress, there shall be no further initialization of static modules.

The local modules contained in the declarations of the static module block shall be initialized in the textual order in which they occur.

Notes:

1. The use of an imported variable or procedure in the initialization body of a local module might cause an exception to occur if that variable or procedure is declared in a local module that is declared later in the same block: since local modules are initialized in the textual order in which they occur, the local module that exports the variable or procedure will not have initialized that variable or any local variables which the procedure might use.

   This situation does not usually arise with variables or procedures that are imported from separate modules because the rules for initialization of separate modules guarantee that the initialization body of the module that exports the variable is executed before that of the module that imports it | provided that no separate module indirectly imports itself --- see Module Initialization Order. It will be prevented from arising with local modules in implementations that choose the `declare before use' model for the ordering of declarations --- see Ordering of Procedure and Module Declarations.

2. The use of an imported variable or procedure in the initialization body of a local module might cause an exception to occur if that variable or procedure is declared (earlier or later) in the same block as the local module: since local modules are initialized before the execution of the body of the block in which they are declared, that body will not have initialized the variable or any local variables which the procedure might use.

On the execution of an initialization body that does not have an exceptional part, the initialization body shall be executed without changing the current execution state.

Note: The current execution state will always be that of normal execution during static module initialization. If the static module initialization body has no exceptional part, the raising of an exception is a termination event --- see Program Termination.

annotations After the initialization of local static modules, the finalization body is queued for execution during program termi- nation.

If the static module is a protected module, the protection domain for that module shall be entered before the local static modules are initialized and shall be left after execution of the initialization body has completed.

If an exception is raised during execution of the static module initialization body, the protection domain shall not be left.

If the static module initialization body has an exceptional part, completion of the initialization body in the state of exceptional execution shall be a termination event --- see Program Termination.

Note: The raising of an exception during execution of the exceptional part of the initialization body is also a termination event.

If the static module is protected and the initialization body has an exceptional part then, if execution of the initial- ization body completes in the state of exceptional execution, the protection domain shall be left.

If an exception is raised during execution of the exceptional part of the initialization body, the protection domain shall not be left.

Auxiliaries

annotations The environment for the execution of the block of a static module is retrieved from the given environment.

### Static Module Finalization

The finalization body of a static module is executed on program termination --- see Program Termination. Execution is in the environment defined by the import lists and declarations of the module block.

Dynamic Semantics

On the finalization of a static module, the finalization body shall be executed.

On the execution of a finalization body that does not have an exceptional part, the finalization body shall be executed without changing the current execution state.

Note: In normal termination, the coroutine execution state is that of normal execution; in exceptional termination, the coroutine execution state is that of exceptional execution --- see Program Termination. Normal termination can switch to exceptional termination because of the raising of an exception during termination that is not handled. Exceptional termination can switch to normal termination during the execution of a finalization body that has an exception handler or that calls a procedure that has an exception handler. If the standard procedure `HALT` is then called, subsequent static module finalization will remain in the state of normal execution.

If the static module is a protected module, the protection domain for that module shall be entered before the finalization body is executed, and shall be left after execution of the finalization body has completed.

If an exception is raised during execution of the static module finalization body, the protection domain shall not be left.

If the static module finalization body has an exceptional part, the finalization body shall be executed in the state of normal execution. Completion of the finalization body in the state of exceptional execution shall be a termination event --- see Program Termination.

Note: The raising of an exception during execution of the exceptional part of the finalization body is also a termination event.

If the static module is protected and the finalization body has an exceptional part then, if execution of the finalization body completes in the state of exceptional execution, the protection domain shall be left.

If an exception is raised during execution of the exceptional part of the finalization body, the protection domain shall not be left.

### Dynamic Module Initialization

Dynamic module initialization applies to the initialization of the module blocks of local modules declared in a procedure block and recursively to the initialization of local modules declared in these module blocks --- see Proper Procedure Blocks and Function Procedure Blocks.

Dynamic Semantics

The local modules contained in the declarations of a procedure block shall be initialized in the textual order in which they occur.

Note: Since the local modules contained in the declarations of a procedure block are initialized in the textual order in which they occur, and are initialized before the procedure body is executed, the direct or indirect use of variables initialized in following local modules, or in the procedure body, might cause an exception to occur.

annotations The environment for the execution of the block of a local dynamic module is the environment constructed by the elaboration of its declarations given the imported identifiers.

The local modules contained in the declarations of the dynamic module block shall be initialized in the textual order in which they occur.

An initialization body that does not have an exceptional part shall be executed without changing the current execution state.

Note: If the initialization body of a dynamic module has no exceptional part, the exceptional part that is the current exception handler is the exceptional part that is the current exception handler for the caller of the procedure whose dynamic modules are being initialized --- see Proper Procedure Blocks and Function Procedure Blocks.

If the dynamic module is a protected module, the protection domain for that module shall be entered before the local dynamic modules are initialized, and shall be left after execution of the initialization body has completed.

If an exception is raised during execution of the dynamic module initialization body, the protection domain shall not be left.

If the initialization body of the dynamic module has an exceptional part, the initialization body shall be executed in the state of normal execution.

On completion of the execution of the block body, the execution state shall revert to that which applied before the execution of the block body.

If execution of the initialization body completed in the state of exceptional execution, the exception shall be re-raised.

On the initialization of a dynamic module that is protected and whose initialization body has an exceptional part, if execution of the initialization body completes in the state of exceptional execution, the exception shall be re-raised after the protection domain has been left.

If an exception is raised during execution of the exceptional part of the initialization body, the protection domain shall not be left.

### Dynamic Module Finalization

Dynamic module finalization applies to the finalization of the module blocks of local modules declared in a procedure block and recursively to the finalization of local modules declared in these module blocks --- see Proper Procedure Blocks and Function Procedure Blocks.

Dynamic Semantics

The local modules contained in the declarations of a procedure block shall be finalized in the reverse order of their initialization.

annotations The environment for the execution of the block of a local dynamic module is the environment constructed by the elaboration of its declarations given the imported identifiers.

A finalization body that does not have an exceptional part shall be executed without changing the current execution state.

Note: If the finalization body of a dynamic module has no exceptional part, the exceptional part that is the current exception handler is the exceptional part that is the current exception handler for the caller of the procedure whose dynamic modules are being finalized --- see Proper Procedure Blocks and Function Procedure Blocks.

The local modules contained in the declarations of the dynamic module block shall be finalized in the reverse order of their initialization.

If the dynamic module is a protected module, the protection domain for that module shall be entered before the finalization body is executed, and shall be left after the local modules contained in the declarations of the dynamic module block have been finalized.

If an exception is raised during execution of the dynamic module finalization body, the protection domain shall not be left.

If the finalization body of the dynamic module has an exceptional part, the finalization body shall be executed in the state of normal execution.

On completion of the execution of the block body, the execution state shall revert to that which applied before the execution of the block body.

If execution of the finalization body completed in the state of exceptional execution, the exception shall be re-raised after the local modules contained in the declarations of the dynamic module block have been finalized.

If an exception is raised during execution of the exceptional part of the finalization body, the local modules contained in the declarations of the dynamic module block shall not be finalized.

On the finalization of a dynamic module that is protected and whose finalization body has an exceptional part, if execution of the finalization body completes in the state of exceptional execution, the exception shall be re-raised after the protection domain has been left.

If an exception is raised during execution of the exceptional part of the finalization body, the protection domain shall not be left.

### Block Bodies and Exception Handling

Block bodies contain the statements that are to be executed when a module is initialized or finalized, or when a procedure is activated.

The block bodies of function procedures return a result value, whereas the block bodies of modules and of proper procedures do not return a result value.

Block bodies have a normal part and, optionally, an exceptional part to handle exceptions raised during execution of the normal part.

Execution of a coroutine takes place in normal execution state or in exceptional execution state. Initially, in each coroutine, the execution state is that of normal execution, and no exceptional part is selected as the current exception handler.

If a block body has an exceptional part, that exceptional part becomes the new current exception handler during execution of the normal part.

If an exception is raised in the state of normal execution, the execution state becomes that of exceptional execution. If there is an exceptional part that is the current exception handler for the coroutine, that exceptional part is executed in the state of exceptional execution.

The execution of a retry statement within the exceptional part of a block body causes the normal part to be retried, in the state of normal execution.

The execution of a return statement within the exceptional part of a block body causes normal completion of execution of the block body.

If an exception is raised in the state of exceptional execution, it is re-raised in the calling context; finalization of local dynamic modules will not take place, and the protection domain, if any, will not be left.

Exceptional completion occurs if there is no return or retry statement executed in the exceptional part; the finalization of local dynamic modules will take place, and the protection domain, if any, will be left. The exception will then be re-raised in the calling context.

If there is no exceptional part selected as the current exception handler for the coroutine, the raising of the exception is a termination event --- see Program Termination. In that case, the subsequent execution of the finalization bodies of the static modules of the program will take place in the state of exceptional execution --- see Static Module Finalization.

Example: Exception handling. In the following example, use is made of the example module `GeneralUserExceptions` --- see The Use of EXCEPTIONS.

        FROM LibModule IMPORT
          Fly, ReplaceRubberBand, SupplyRubberBands, IsLibException, LibException, LibExceptions;
        FROM GeneralUserExceptions IMPORT
          GeneralExceptions, RaiseGeneralException;

        PROCEDURE TryFlying();
        BEGIN
          Fly
        EXCEPT
          (* statements in exceptional execution *)
          IF IsLibException() THEN
            CASE LibException() OF
            |brokenRubberBand:
              ReplaceRubberBand;
              RETRY
            ELSE
            END
          END
          (* Exceptional return re-raises the exception *)
        END TryFlying;

        PROCEDURE KeepFlying();
        BEGIN
          (* statements in normal execution *)
          TryFlying;
          (* statements in normal execution *)
        EXCEPT
        (* statements in exceptional execution *)
          IF IsLibException() THEN
            CASE LibException() OF
            |outOfRubberBands:
              SupplyRubberBands;
              RETRY
            ELSE
              (* can keep flying no longer - normal return *)
              RETURN
            END
          ELSE
            RaiseGeneralException(disaster, "Unexpected exception from LibModule")
          END
        END KeepFlying;

Concrete Syntax

block body= normal part, [ "EXCEPT", exceptional part ] ;

normal part= statement sequence ;

exceptional part= statement sequence ;

Abstract Syntax

annotations In the translation from concrete to abstract syntax, a block body that has no exceptional part shall be represented by a Block-body with a `nil` value for the except component.

Static Semantics

The control variable of any for statement contained within a block body shall be declared as a simple variable within the declarations of the block body.

Any exit statements contained within the block body shall be contained within a loop statement inside the statement part.

There shall be no retry statements within the normal part of a block body.

- Non-result Bodies
- Result Bodies

#### Non-result Bodies

Non-result bodies are the block bodies of proper procedure blocks or the initialization or finalization bodies of module blocks.

Static Semantics

Any return statements contained within non-result bodies shall be simple return statements.

Dynamic Semantics

If there is no exceptional part to a non-result body, the execution of such a body shall cause execution of the normal part with no change to the current exception handler.

The execution of a simple return statement contained in the normal part shall cause the execution of the block body to terminate prematurely.

If there is an exceptional part to a non-result body, the execution of such a body shall cause execution of the normal part with that exceptional part as the new current exception handler.

The execution of a simple return statement contained in the normal part shall cause the execution of the block body to complete prematurely.

The raising of an exception during execution of the normal part shall cause execution of the exceptional part in the state of exceptional execution.

The execution of a simple return statement contained in the exceptional part shall cause the execution of the block body to complete prematurely in the state of normal execution.

The execution of a retry statement contained in the exceptional part shall cause reversion to the state of normal execution and cause the normal part to be retried.

Note: The exceptional part will again be the handler for any exceptions raised during execution of the normal part.

If an exception is raised during execution of the exceptional part, it shall replace the exception that was being handled and shall be raised in the calling context.

If execution reaches the end of the exceptional part, execution of the handled body shall complete in the state of exceptional execution.

#### Result Bodies

Result bodies are the block bodies of function procedure blocks.

Static Semantics

The return statements of result-bodies shall be function return statements returning a value of the result type of the function. The normal part of a block body shall have at least one function return statement.

Dynamic Semantics

If there is no exceptional part to a non-result body, the execution of such a body shall cause execution of the normal part with no change to the current exception handler.

The execution of a function return statement contained in the normal part shall cause the execution of the block body to terminate prematurely. The value of the function return statement expression shall be the value that is returned as the value of the call.

It shall be an exception if the completion of the normal part of a result body is not by the execution of a return statement.

If there is an exceptional part to a result body, the execution of such a body shall cause execution of the normal part with that exceptional part as the new current exception handler.

The execution of a function return statement contained in the normal part shall cause the execution of the block body to complete prematurely. The value of the function return statement expression shall be the value that is returned as the value of the call.

The raising of an exception during execution of the normal part shall cause execution of the exceptional part in the state of exceptional execution.

The execution of a function return statement contained in the exceptional part shall cause the execution of the block body to complete prematurely in the state of normal execution. The value of the function return statement expression shall be the value that is returned as the value of the call.

The execution of a retry statement contained in the exceptional part shall cause reversion to the state of normal execution, and cause the normal part to be retried.

Note: The exceptional part will again be the handler for any exceptions raised during execution of the normal part.

If an exception is raised during execution of the exceptional part, it shall replace the exception that was being handled, and shall be raised in the calling context.

If execution reaches the end of the exceptional part, execution of the handled body shall complete in the state of exceptional execution.

## Statements

Except for the empty statement, statements denote actions. Statements are executed and their execution has an effect that is a transformation of the program state. The empty statement, the assignment statement, the procedure call, the return statement, the retry statement, and the exit statement are not composed of any parts that are themselves statements. The remaining statements have components that are themselves statements; these are the with statement, the if statement, the case statement, the while statement, the repeat statement, the loop statement, and the for statement.

Concrete Syntax

statement=
empty statement | assignment statement | procedure call |
return statement | retry statement | with statement |
if statement | case statement | while statement |
repeat statement | loop statement | exit statement |
for statement ;

- Statement Sequences
- Empty Statements
- Assignment Statements
- Procedure Calls
- Return Statements
- Retry Statements
- With Statements
- If Statements
- Case Statements
- While Statements
- Repeat Statements
- Loop Statements
- Exit Statements
- For Statements
- Well-formed Control Variables
- Auxiliary Functions

### Statement Sequences

A statement sequence specifies that a sequence of actions is to be performed. Each action is specified by a statement. The statements of a statement sequence are separated by semicolons.

Concrete Syntax

statement sequence= statement, { ";", statement } ;

Static Semantics

annotations Check each statement of the statement sequence.

Dynamic Semantics

The execution of a statement sequence shall cause the execution of the first statement in the sequence, followed by the execution, in order, of any remaining statements of the sequence.

Notes:

1. The execution of a statement sequence may be prematurely terminated by the execution of a return statement, or by the execution of an exit statement if the statement sequence is contained within a loop statement.

2. The execution of a statement sequence may be prematurely terminated if an exception is raised.

### Empty Statements

An empty statement contains no symbols and denotes no action. Its use permits the relaxation of punctuation rules in statement sequences.

Concrete Syntax

empty statement= ;

Dynamic Semantics

An empty statement shall denote no action; its execution shall produce no changes to the state.

### Assignment Statements

An assignment statement specifies that a variable is to be given a value. The variable may be either an elementary variable or a structured (composite) variable.

Concrete Syntax

assignment statement= variable designator, ":=", expression ;

Static Semantics

The variable designator shall denote a variable. The type of the variable designator shall be assignment-compatible with the type of the expression --- see Assignment Compatibility.

Dynamic Semantics

The execution of an assignment statement shall cause the expression to be evaluated and the resulting value to become the new value of the variable denoted by the variable designator. The order of evaluation of the variable designator and the expression shall be implementation-dependent.

If the assignment is to an elementary variable, and the value to be assigned is not a value of the range of values defined by the type of the variable designator, an exception shall be raised.

If the assignment is of a string constant or string literal to an array whose component type is the character type, and the string constant does not fill the array, the string shall be terminated with a string terminator, and the remainder of the array shall become undefined.

Note: For assignment to a concrete string variable to work as described, it is not sufficient for the variable's component type to be a subrange of `CHAR`. It must be identical to `CHAR` so that it can contain a string terminator.

If the assignment is to a tag field of a record, and the new value of the tag field causes a new variant to be selected, the value of each field of the field list of the variant associated with the old value of the tag field shall become undefined. If the new value of the tag field does not cause a new variant to be selected, the assignment to the tag field shall produce no change to the associated variant.

Notes:

1. The evaluations of the variable designator and the expression could produce a transformation of the program state, i.e. have side-effects.

2. An exception occurs during the evaluation of the expression if the value of an elementary variable that is a factor of that expression is undefined. If the value of a variable of a record or array structure is to be assigned, and the value of any of the components is undefined, then no exception occurs. Undefined values can therefore be assigned to the components of a structured (composite) variable, but only if the assignment is applied to the entire variable.

3. An exception occurs during the evaluation of the variable designator if the variable designator is a selected designator and the assignment is to a field of a variant for which there is an explicit tag field and the variant is inactive --- see Selected Designators.

4. An exception occurs if assignment is to a variable whose designator is an indexed designator and the index is not a valid value of the variable's index type.

annotations The above evaluation order for the variable designator and the expression is just one of those permitted; the expression may instead be evaluated before the variable designator, or both may be evaluated in parallel --- see ???.

After the two evaluations, the result of the expression evaluation is assigned to the target of the assignment.

When the variable designator is a selected designator and the target is a field of a variant, then in the case of explicit tag fields, the evaluation of the selected designator will check that the values of the tag fields that select the field are correctly set. In the case of implicit tag fields selecting the variant, these implicit tag fields will be set to appropriate values.

Auxiliaries

annotations This function is used to assign to elementary variables, and is used recursively to assign to array, record, tag, variant, and tagged variables. An undefined value can only occur as part of an array or record value; it cannot occur as an elementary value.

annotations Check that the value to be assigned is within range or is undefined: if it is, change the value of the target designator; otherwise an exception shall be raised. Character literals are interpreted as values of the character type.

annotations Component by component assignment of the array value to the array variable occurs, and assignment of an undefined value is allowed for.

annotations If the assignment is a string literal to an array of `CHAR`, and the string constant does not fill the array, the string is terminated with a string terminator (denoted by end-of-string-char) and the remainder of the array is set to undefined. The well-formed conditions guarantee that the length of the string constant is less than or equal to the number of the components of the array.

annotations Set the variables that are components of a variant to undefined.

annotations Return the (variant) component of a record that corresponds to the value of the associated tag field. If the tag field contains an undefined value, the result is an empty record.

annotations Assign a value to a field of a variant for the case where there is an explicit tag field.

annotations Assign a value to a field of a variant for the case where there is an implicit tag field.

### Procedure Calls

A procedure call specifies the evaluation of any actual parameters and the execution of the actions associated with the procedure designator of the procedure call.

Concrete Syntax

procedure call= procedure designator, [ actual parameters ] ;

procedure designator= value designator ;

Abstract Syntax

annotations The identifiers of predefined procedures are distinguished since these do not denote values (that can be assigned or compared in expressions). If the actual parameter list is not present in the concrete representation, then the translation process (from concrete to abstract syntax) will supply an empty sequence for the aps component of Procedure-call .

Static Semantics

The procedure designator of a procedure call shall be a value designator that denotes a proper procedure or the identifier of a predefined proper procedure.

Notes:

1. A value designator that denotes a proper procedure is either a procedure identifier of a proper procedure heading (possibly qualified by the name or names of modules from which the procedure identifier is exported), a value designator that denotes a constant that has a proper procedure value, or a value designator that denotes a variable that has a proper procedure type.

2. The identifiers of predefined procedures are not value designators since predefined procedures are not values that can be assigned, compared in expressions, or passed as procedure parameters.

In the case of a call of a predefined proper procedure, the actual parameters shall correspond in number and in type to those required for that predefined proper procedure; otherwise, each actual parameter shall be parameter compatible with the corresponding formal parameter of the designated proper procedure.

Dynamic Semantics

The execution of a procedure call shall be the evaluation of any actual parameters to give corresponding arguments, the binding of the results of this evaluation to the corresponding formal parameters, and the execution of the actions associated with the procedure designator. In the case of a call of a predefined proper procedure, the actions are as specified for that predefined procedure; otherwise, the actions are as specified by the block of the proper procedure declaration.

The order of evaluation, the order of accessing, and the order of binding of the actual parameters shall be implementation-dependent. The order of evaluation of the procedure designator and the actual parameters shall be implementation-dependent.

The actual parameters shall be evaluated before the execution of the actions associated with the proper procedure designator.

annotations The above evaluation order for the procedure designator and the actual parameters is one of those permitted; the actual parameters may instead be evaluated before the procedure designator, or both may be evaluated in parallel | see 4.1.

### Return Statements

A return statement specifies the termination of the execution of the block of a proper procedure, a function procedure, or a module.

Concrete Syntax

return statement= simple return statement | function return statement ;

Static Semantics

annotations The checks that simple return statements are only contained in modules and proper procedures, and that function return statements must be contained in function procedures are performed by wf-module-block (see Module Blocks), wf-proper-procedure-block (see Proper Procedure Blocks), and wf-function-procedure-block (see Function Procedure Blocks).

- Simple Return Statements
- Function Return Statements

#### Simple Return Statements

A simple return statement specifies the termination of the execution of a proper procedure block or a module block.

Concrete Syntax

simple return statement= "RETURN" ;

Dynamic Semantics

The execution of a simple return statement shall terminate the execution of a proper procedure block or a module block.

Note: There is an implicit simple return statement at the end of the proper procedure block of a proper procedure. An explicit simple return statement within the proper procedure block means that there is an additional point at which the execution of the block is to be terminated.

#### Function Return Statements

A function return statement specifies the termination of the execution of a function procedure block, and defines the value to be returned by that function procedure.

Concrete Syntax

function return statement= "RETURN", expression ;

Static Semantics

The result type (see Function Procedure Declarations) of the function procedure in which the function return statement appears shall be assignment-compatible with the type of the expression.

Dynamic Semantics

The execution of a function return statement shall terminate the execution of a function procedure block and return a value. If the type of the function result is a subrange type, the value returned shall belong to the set of values defined by the subrange type; otherwise an exception shall be raised.

Notes:

1. There may be several function return statements in a function procedure block, although only one of these will be executed on any activation of the function procedure.

2. An exception is raised if the termination of a function procedure block is not by the execution of a function return statement --- see Function Procedure Blocks.

annotations The expression of the return statement is evaluated. If the result is one of the values of the type defined by the return type of the function procedure, the result is returned, otherwise an exception is raised. A character literal is converted to a character value before the range is checked.

### Retry Statements

A retry statement may occur only within the exceptional part of a module body or procedure body. It specifies that the normal part of the block body is to be re-executed --- see Block Bodies and Exception Handling.

Concrete Syntax

retry statement= "RETRY" ;

Static Semantics

A retry statement shall be contained within an exceptional part of a block body.

annotations The check that the retry statement is contained within an exceptional part of a block body is included in the consistency check for the procedure/function/module that contains the retry statement --- see Proper Procedure Blocks, Function Procedure Blocks, and Module Blocks.

Dynamic Semantics

The execution of a retry statement shall revert to the state of normal execution and cause the handled block body to be retried --- see Block Bodies and Exception Handling.

### With Statements

A with statement specifies a record designator and a statement sequence; within that statement sequence, the field identifiers of the designated record need not be qualified by the record designator.

Concrete Syntax

with statement= "WITH", record designator, "DO", statement sequence, "END" ;

record designator= variable designator | value designator ;

Static Semantics

The record designator shall denote a record variable or a record value. Within the statement sequence, the field identifiers of the record variable or record value may be used without selection.

annotations Check that the designator designates either a record variable or record value. Add the field identifiers with their corresponding types to the current environment to give the environment for the body of the with statement.

Dynamic Semantics

The record variable designator or record value designator shall be evaluated before the statement sequence of the with statement is executed, and that evaluation shall establish a reference to the variable or value throughout the execution of the statement sequence of the with statement.

annotations Add the field identifiers with their corresponding variables or values to the current environment to give the envi- ronment for the body of the with statement.

### If Statements

An if statement is used to select one statement sequence for execution from an ordered list of alternatives guarded by Boolean expressions.

Concrete Syntax

if statement= guarded statements, [ if else part ], "END" ;

guarded statements=
"IF", boolean expression, "THEN", statement sequence,
{ "ELSIF", boolean expression, "THEN", statement sequence } ;

if else part= "ELSE", statement sequence ;

boolean expression= expression ;

Abstract Syntax

annotations An if statement always contains at least one statement sequence (which follows the first occurrence of a `THEN` symbol); thus after the translation process (from concrete to abstract syntax) there is always a non-empty sequence of guarded statements. A missing if else part in the concrete syntax is denoted by nil in the abstract syntax.

Static Semantics

All if statement boolean expressions shall be of the Boolean type.

Dynamic Semantics

The boolean expressions of the guarded statements shall be evaluated in the order they occur, as far as the first boolean expression (if any) that has the value true . If there is such a boolean expression, its associated statement sequence shall then be executed; however, if all the boolean expressions have the value false , the statement sequence of the else part (if present) shall be executed. An if statement shall denote no action if all the boolean expressions have the value false , and there is no else part.

Note: The evaluation of the if statement boolean expressions could produce a transformation of the program state, i.e. have side-effects.

annotations If there are no more elements remaining in the sequence of guarded statements then the if else part of the if statement (if present) is executed. If there are more elements remaining in the sequence of guarded statements, the Boolean expression of the first guarded statement in the sequence is evaluated, and if the result is true, the corresponding statement sequence is executed. If the result of the evaluation of the Boolean expression is false, then this element is removed from the sequence of guarded statements and the remainder of the sequence executed.

Auxiliaries

annotations If an if else part is present, and no other component of the if statement has been executed, then the if else part is executed.

### Case Statements

A case statement is used to select one statement sequence for execution from alternatives; the selection of the statement sequence depends on the value of an expression.

Concrete Syntax

case statement= "CASE", case selector, "OF", case list, "END" ;

case selector= ordinal expression ;

case list= case alternative, { "|", case alternative }, [ case else part ] ;

case else part= "ELSE", statement sequence ;

Abstract Syntax

annotations The number of elements in the cases component of the abstract representation of a case statement is equal to the number of case alternatives of the concrete representation.

Static Semantics

The case selector shall be of an ordinal type and shall be expression compatible with the types of the constant expressions of the case label list of each case alternative.

The values contained in the case label lists of different case alternatives shall be distinct from each other.

Note: In addition to the requirement that the values contained in the case label lists s of different case alternatives shall be distinct from each other, it is also required that the values contained in each case label list shall be distinct from each other.

Example: Duplication of case labels in case statements. The alternatives illustrated in the following source code are illegal for the reasons given in the associated comments.

        CASE i OF
          (*a*) 1           : (* duplicate of label in list d *)
        | (*b*) 11          : (* label 11 in b duplicated in range 11..13 in list i *)
        | (*c*) 15..17      : (* range 15..17 in c overlaps with range 16..19 in list j *)
        | (*d*) 1           : (* duplicate of label in list a *)
        | (*e*) 2, 2        : (* label 2 is duplicated in list e *)
        | (*f*) 3..5, 3..5  : (* range 3..5 is duplicated in list f *)
        | (*g*) 6, 6..7     : (* label 6 duplicated in range 6..7 in list g *)
        | (*h*) 8..9, 8..10 : (* range 8..9 overlaps range 8..10 in list h *)
        | (*i*) 11..13      : (* label 11 in b duplicated in range 11..13 in list i *)
        | (*j*) 16..19      : (* range 15..17 in c overlaps with range 16..19 in list j *)
        END

annotations Check each of the case alternatives and the case else part if it is present. Check that the case selector is of an ordinal type and that it is expression-compatible with the type associated with each case label list.

Dynamic Semantics

The case selector shall be evaluated. The resulting value shall specify the execution of the statement sequence whose case label list contains that value. If the value of the case selector is not contained in any case label list, the statement sequence of the case else part (if present) shall be executed; otherwise an exception shall be raised.

Clarification: In Programming in Modula-2 , it is not stated what should happen when the value of the case selector is not contained in any case label list and there is no case else part.

Note: The evaluation of the case selector could produce a transformation of the program state, i.e. have side-effects.

annotations The expression is evaluated, and the result is used to determine which statement sequence of the case statement is to be executed.

- Case Alternatives

#### Case Alternatives

A case alternative specifies the execution of a statement sequence if its case label list contains the value of the case selector.

Concrete Syntax

case alternative= [ case label list, ":", statement sequence ] ;

case label list= case label, { ",", case label } ;

case label= constant expression, [ "..", constant expression ] ;

Abstract Syntax

annotations The translation process (from concrete to abstract syntax) will ensure that the number of members in the labels component of a Case component of the abstract representation is equal to the number of case labels in the case label list of the concrete representation.

Static Semantics

Each case label shall be a constant expression, or a range indicated by a pair of constant expressions. The values contained in a case label list shall be distinct from each other. A value shall be contained in a case label list if it is equal to the value of one of the constant expressions of the case label list, or if the value lies within the range specified by a pair of constant expressions of the case label list.

Auxiliaries

annotations Check that all of the variant labels are expression-compatible with the tag type.

annotations Check that the sets of values defined by each of the case label lists are disjoint.

### While Statements

A while statement specifies the execution of a statement sequence zero or more times, depending on the value of a Boolean expression.

Concrete Syntax

while statement=
"WHILE", boolean expression, "DO", statement sequence, "END" ;

Static Semantics

A while statement boolean expression shall be of the Boolean type.

Dynamic Semantics

The while statement boolean expression shall be evaluated before each iteration of a while statement. If the expression has the value true , the statement sequence shall be executed, followed again by the execution of the while statement. If the expression has the value false , the statement sequence shall not be executed, and the execution of the while statement shall terminate.

Notes:

1. If the result of the first evaluation of the boolean expression is false , the statement sequence of the while statement is not executed.

2. The evaluation of the while statement boolean expression could produce a transformation of the program state, i.e. have side-effects.

3. The execution of a while statement may be prematurely terminated by the execution of a return statement, or by the execution of an exit statement (if the while statement is contained within a loop statement).

### Repeat Statements

A repeat statement specifies the execution of a statement sequence one or more times, depending on the value of a Boolean expression.

Concrete Syntax

repeat statement=
"REPEAT", statement sequence, "UNTIL", boolean expression ;

Static Semantics

A repeat statement boolean expression shall be of the Boolean type.

Dynamic Semantics

In the execution of a repeat statement, the statement sequence shall first be executed. The repeat statement boolean expression shall be evaluated; if the expression has the value true , the repeat statement shall be executed again. If the expression has the value false , the execution of the repeat statement shall terminate.

Notes:

1. The statement sequence of a repeat statement is executed at least once.

2. The evaluation of the repeat statement boolean expression could produce a transformation of the program state, i.e. have side-effects.

3. The execution of a repeat statement may be prematurely terminated by the execution of a return statement, or by the execution of an exit statement (if the repeat statement is contained within a loop statement).

### Loop Statements

A loop statement specifies the repeated execution of a statement sequence. The statement sequence may contain zero or more exit statements, the execution of any one of which terminates the execution of the loop statement.

Concrete Syntax

loop statement= "LOOP", statement sequence, "END" ;

Dynamic Semantics

The statement sequence of a loop statement shall be repeatedly executed until an exit statement of the loop statement is executed.

Note: The execution of a loop statement may be prematurely terminated by the execution of a return statement.

### Exit Statements

An exit statement may occur only within a loop statement, where it specifies the termination of that loop statement.

Concrete Syntax

exit statement= "EXIT" ;

Static Semantics

annotations The check that the exit statement is contained inside a loop statement is part of the consistency check for the procedure/function/module that contains the exit statement.

Dynamic Semantics

The execution of an exit statement shall terminate the execution of a loop statement; the loop statement that is terminated is the loop statement that most immediately contains the exit statement.

### For Statements

A for statement specifies that a statement sequence is to be repeatedly executed as elements of a sequence of values are assigned, one by one, to a control variable.

Concrete Syntax

for statement=
"FOR", control variable identifier, ":=", initial value,
"TO", final value, [ "BY", step size ], "DO",
statement sequence, "END" ;

control variable identifier= identifier ;

initial value= ordinal expression ;

final value= ordinal expression ;

step size= constant expression ;

Abstract Syntax

annotations If the step size is not present in the concrete representation, the translation process (from concrete to abstract syntax) will supply a step component in the abstract representation equal to 1.

Static Semantics

The control variable identifier shall be the identifier of the control variable. The initial value and the final value shall be expressions. The type of the control variable shall be an ordinal type that is assignment-compatible with the type of the initial value. Either the type of the control variable or the host type of the type of the control variable and the type of the final value shall be expression-compatible. If a for statement does not contain a step size, the step size shall have the value 1. Otherwise the step size shall be a constant expression of a whole number type, shall be in an implementation-defined range, and shall not have the value 0.

Notes:

1. The requirement that the type of the control variable is assignment-compatible with the type of the initial value is made since this value might be assigned to the control variable.

2. Other constraints on the use of a control variable are given in Well-formed Control Variables.

Change: In Programming in Modula-2 , it is required that the type of the control variable is expression-compatible with the type of the initial value.

annotations Check each of the components of the for statement. The check that the control variable is declared in a variable declaration part of the block that contains the for statement is part of the consistency check for the procedure, function, or module that contains the for statement.

annotations Check that the step value is between implementation-defined limits.

Dynamic Semantics

The expressions that specify the initial value and the final value shall be evaluated in an implementation-dependent order.

If the step size is positive and the initial value is greater than the final value, the statement sequence shall not be executed, and the execution of the for statement shall terminate. If the step size is negative and the initial value is less than the final value, the statement sequence shall not be executed, and the execution of the for statement shall terminate. Otherwise a sequence of values shall be established and for each element of the sequence in turn, the element shall be assigned to the control variable, and then the statement sequence shall be executed; the execution of the for statement shall terminate when the statement sequence has been executed for each value in the sequence.

The sequence of values for the control variable shall be the longest sequence that satisfies the conditions that the first element of the sequence shall be equal to the initial value, the last element of the sequence shall be less than or equal to the final value if the step size is positive, or greater than or equal to the final value if the step size is negative, and the difference between adjacent values in the sequence shall be equal to the step size.

After termination of the for statement, the value of the control variable shall be undefined.

Notes:

1. The expressions that are the initial value and the final value are evaluated only once at the start of the execution of a for statement. These evaluations could produce a transformation of the program state, i.e. have side-effects.

2. The statement sequence of a for statement is not executed at all if the initial value is greater than the final value (in the case that the step size is positive) or if the initial value is less than the final value (in the case that the step size is negative).

3. The execution of a for statement may be prematurely terminated by the execution of a return statement, or by the execution of an exit statement (if the for statement is contained within a loop statement).

annotations The above evaluation order for the initial value and the final value is one of those permitted; the final value may instead be evaluated before the initial value, or both may be evaluated in parallel | see 4.1. The iteration sequence for the loop is built from the initial value, step, and final value and then the loop is executed using the iteration sequence.

Auxiliaries

annotations If the iteration sequence is empty, terminate the execution of the loop and assign the value undefined to the control variable. If the iteration sequence is not empty, assign the next iteration value to the control variable, execute the body of the loop and execute the for statement again with an iteration sequence having the value used for the current iteration removed.

annotations This function constructs the sequence of values that may be assigned to the control variable. The sequence of values starts with the initial value. The last value in the sequence is less than or equal to the final value if the step is positive, or greater than or equal to the final value if the step is negative. The difference between adjacent values in the sequence is equal to the step. If the initial value is greater than the final value (in the case that the step is positive) or if the initial value is less than the final value (in the case that the step is negative) the sequence of values is empty.

annotations Construct the sequence of consecutive values from the initial and final values.

annotations Construct a sequence of iteration values from the first and last values.

### Well-formed Control Variables

A variable that is used as a control variable of a for statement must be a simple variable. It must be a local variable, and it must not be exported nor imported. It must not be threatened in any statement within the statement sequence of the for statement, or by any procedure in the declarations part of the block containing the for statement.

If a control variable is not threatened, no statement other than the for statement itself can attempt to alter the for loop control variable.

Static Semantics

The control variable of each for statement in the body of a block shall be declared as a simple variable in a variable declaration part of the block that immediately contains the for statement.

Note: Since a control variable must be declared in the declaration part of a block in which the variable is used, it follows that it is not possible for the control variable to be:

- a formal parameter, or

- a variable that is imported into a program module or an implementation module, or

- a variable that is exported from a separate module.

A variable that is used as a control variable shall not be imported by a local module declaration of the block in which the variable is declared.

A variable that is used as a control variable in the block of a local module declaration shall not be exported from that module.

Note: This restriction is checked by the well-formed condition for a module --- see Local Module Declarations.

A control variable shall not be threatened in a statement of the statement sequence of the for statement.

Note: This restriction is checked by the well-formed condition for a for statement --- see For Statements.

A control variable shall not be threatened in a procedure declared in the declarations of the block that contains the for statement.

Clarification: In Programming in Modula-2 :

- it is not stated that a control variable must be a local variable,

- it is not stated that a control variable cannot be exported,

- it is stated that the control variable should not be changed by the statement sequence of the for statement.

- Threatening

#### Threatening

A control variable shall be threatened in a proper procedure declaration if an identifier with the same spelling is not declared in the procedure heading, and the control variable is threatened in the block component of the procedure.

A control variable shall be threatened in a function procedure declaration if an identifier with the same spelling is not declared in the procedure heading, and the control variable is threatened in the block component of the procedure.

A control variable shall be threatened in a block if an identifier with the same spelling is not declared in a declaration of the block, and the control variable is threatened either in a procedure of a declaration of the block or in a statement of the statement sequence of the block.

A control variable shall be threatened in an assignment statement if it is the variable designator of the assignment, if it is threatened in an expression of the variable designator component, or if it is threatened in the expression component of the assignment statement.

A control variable shall be threatened in a procedure call if it is threatened in an expression component of the procedure designator component of the procedure call or it is threatened in an actual parameter of the procedure call.

A control variable shall be threatened in a return statement if the return statement is a function return statement and the control variable is threatened in the expression component of the return statement.

A control variable shall be threatened in a with statement if an identifier with the same spelling is not a field of the variable designated by the designator component of the with statement and the control variable is threatened in a statement of the statement sequence component of the with statement.

A control variable shall be threatened in an if statement if it is threatened in any Boolean expression components or if it is threatened in a statement of the statement sequence component.

A control variable shall be threatened in a case statement if it is threatened in the case selector or if it is threatened in a statement of the statement sequence component.

A control variable shall be threatened in a while statement if it is threatened in the Boolean expression component or if it is threatened in a statement of the statement sequence component.

A control variable shall be threatened in a repeat statement if it is threatened in a statement of the statement sequence component or if it is threatened in the Boolean expression component.

A control variable shall be threatened in a loop statement if it is threatened in a statement of the statement sequence component.

A control variable shall be threatened in a for statement if it is the control variable of the for statement, if it is

threatened in the initial value, if it is threatened in the final value, or if it is threatened in a statement of the statement sequence component.

Note: This rule is concerned with the threatening of the control variable of a for statement in another for statement nested within the statement sequence of the first for statement.

A control variable shall be threatened in a variable designator if it is threatened in an expression component of the variable designator.

A control variable shall be threatened in an expression if it is threatened as an element of the expression.

A control variable shall be threatened in a function call if it is threatened in the value designator component or if it is threatened in an actual parameter of the function call.

A control variable shall be threatened in an actual parameter to a procedure or function call if it is an actual parameter corresponding to a variable formal parameter or if it is threatened in an expression component of the actual parameter.

Notes:

1. The predefined procedures `DEC` and `INC`, and the function `ADR` of the module `SYSTEM`, are considered to take a variable parameter, and therefore cannot be passed a control variable.

2. A control variable is not threatened in an empty statement or in an exit statement or in a simple return statement or in a retry statement.

annotations Return the set of identifiers that are used (in a block) as the identifiers of for statement control variables.

annotations The result is true if and only if all the variables that are used as control variables are declared in the block, are not threatened in the statements or expressions contained in the block, are not threatened in procedures declared in the block, and are not imported by a module declared in the block.

annotations The result is true if and only if there exists a variable declaration that contains a declaration of the variable.

annotations The identifier parameter in the following operations is a control variable identifier and it designates a control variable.

annotations A control variable is threatened in the procedures declared in a block if there exists a procedure in the declarations component that threatens the control variable.

annotations A control variable is threatened in a proper procedure if an identifier with the same spelling is not declared in the procedure heading, and the control variable is threatened in the block component of the procedure.

annotations A control variable is threatened in a function procedure if an identifier with the same spelling is not declared in the procedure heading, and the control variable is threatened in the block component of the procedure.

annotations A control variable is threatened in a proper procedure block if an identifier with the same spelling is not declared in the declarations component of the block, and the control variable is threatened either in a procedure of the declarations component of the block or in the statement sequence of the block.

annotations A control variable is threatened in a function procedure block if an identifier with the same spelling is not declared in the declarations component of the block, and the control variable is threatened either in a procedure of the declarations component of the block or in the statement sequence of the block.

annotations A control variable is threatened in a statement sequence if at least one of the statements of the statement sequence threatens the control variable.

annotations Check if control variable threatened by a statement.

annotations A control variable is threatened in a procedure call if it is threatened as the procedure designator component of the procedure call or it is threatened in an actual parameter of the procedure call.

annotations A control variable is threatened in a return statement if the return statement is a function return statement and the control variable is threatened in the expression component of the return statement.

annotations A control variable is threatened in a with statement if an identifier with the same spelling is not a field of the variable or value designated by the designator component of the with statement and the control variable is threatened in the statement sequence that is the body of the with statement. renv is the addition to the environment caused by the with statement. If the control variable identifier belongs to the domain of the mapping then within the with statement, it is to a field of the record that is being threatened, not the control variable.

annotations A control variable is threatened in an if statement if it is threatened in the Boolean expression component of a guarded statement, if it is threatened in the statement sequence component of a guarded statement, or if it is threatened in the statement sequence component of the if else part.

annotations A control variable is threatened in a case statement if it is threatened in the case selector, if it is threatened in one of the statement sequences of the case alternatives, or if it is threatened in the statement sequence of the if else part.

annotations A control variable is threatened in a while statement if it is threatened in the expression or if it is threatened in the statement sequence.

annotations A control variable is threatened in a repeat statement if it is threatened in the statement sequence or if it is threatened in the expression.

annotations A control variable is threatened in a loop statement if it is threatened in the statement sequence.

annotations A control variable is threatened in a for statement if it is the control variable of the for statement, if it is threatened in the initial expression, if it is threatened in the final expression, or if it is threatened in the statement sequence that is the body of the for statement.

annotations A control variable is threatened in a variable designator if it is threatened in any expression component of the variable designator.

annotations A control variable is threatened in an expression if it is threatened as an element of the expression.

annotations A control variable is threatened in an infix expression if it is threatened in an expression component of the infix expression.

annotations A control variable is threatened in an prefix expression if it is threatened in the expression component of the prefix expression.

annotations A control variable is threatened in a value designator if it is threatened in any expression component of the value designator.

annotations A control variable is threatened in a function call if it is threatened as the value designator component or if it is threatened in an actual parameter of the function call.

annotations A control variable is threatened in a value constructor if it is threatened in any expression component of the value constructor.

annotations A control variable is threatened in a structured value if it is threatened in any expression component of the structured value. Note that a control variable cannot be threatened in the replication component as it is a constant expression.

annotations A control variable is threatened in a set constructor if it is threatened in any expression component of the set constructor.

annotations A control variable is threatened as an actual parameter to a procedure or function call if it is an actual parameter corresponding to a variable formal parameter or if it is threatened in an expression component of the actual parameter.

annotations Check if a control variable is imported by a module declaration of the block.

### Auxiliary Functions

- Well-formed Return Statements
- Well-formed Retry Statements
- Well-formed Exit Statements
- Statement Classes of Statement Sequences

#### Well-formed Return Statements

annotations Check that the return statement components of the statement sequence are all function return statements and that for each return statement, the return type of the function procedure is assignment-compatible with the type of the expression component of the return statement.

annotations The return-statements of a statement sequence is the set containing all the return statements contained in the statements of the statement sequence.

#### Well-formed Retry Statements

annotations Check that there are no `RETRY` statements in a block body.

annotations The retry statements of a statement sequence is the set containing all the retry statements contained in the state- ments of the statement sequence.

#### Well-formed Exit Statements

annotations This function returns true if and only if each exit statement of the statement sequence is textually contained within a loop statement. A free exit statement is one that is not contained within a loop statement, thus the loop statements of a statement sequence are well-formed if the statement sequence contains no free exit statements.

annotations The free-exit-statements of a statement sequence is the set containing all the exit statements contained in the statements of the statement sequence that are not contained in loop statements.

annotations The free exit statements of an exit statement is a set containing that statement. The free exit statements of any other statement that is not composed of any parts that are themselves statements is the empty set. The free exit statements of a loop statement is the empty set. The free exit statements of any other statement that is composed of parts that are themselves statements is the free exit statements contained in the statement sequence component parts.

annotations The free exit statements contained in a with statement are the free exit statements contained in the statement sequence of the with statement.

annotations The free exit statements contained in an if statement are the free exit statements contained in the statement sequence component of the if statement.

annotations The free exit statements contained in a case statement are the free exit statements contained in the statement sequence components of the case statement.

annotations The free exit statements contained in a while statement are the free exit statements contained in the statement sequence component of the while statement.

annotations The free exit statements contained in a repeat statement are the free exit statements contained in the statement sequence component of the repeat statement.

annotations The free exit statements contained in a for statement are the free exit statements contained in the statement sequence component of the for statement.

#### Statement Classes of Statement Sequences

annotations This function returns a set containing all the statements contained in the statement sequence that are members of the set defined by the second parameter.

annotations The statements of a with statement that are members of the set defined by the second parameter are obtained from the statement sequence of the with statement.

annotations The statements of an if statement that are members of the set defined by the second parameter are obtained from the statement sequences of the if statement.

annotations The statements of a case statement that are members of the set defined by the second parameter are obtained from the statement sequences of the case statement.

annotations The statements of a while statement that are members of the set defined by the second parameter are obtained from the statement sequence of the while statement.

annotations The statements of a repeat statement that are members of the set defined by the second parameter are obtained from the statement sequence of the repeat statement.

annotations The statements of a loop statement that are members of the set defined by the second parameter are obtained from the statement sequence of the loop statement.

annotations The statements of a for statement that are members of the set defined by the second parameter are obtained from the statement sequence of the for statement.

## Variable Designators

A variable designator denotes a variable. The denoted variable may be a variable introduced in a variable definition or variable declaration, a formal parameter of a procedure, or a component of such a variable.

Concrete Syntax

variable designator=
entire designator | indexed designator |
selected designator | dereferenced designator ;

#### Entire Designators

An entire designator is a variable designator that is a qualified identifier; it denotes an entire elementary or structured (composite) variable (which may be a formal parameter), or a field of a record variable within a with statement that applies to that variable.

Concrete Syntax

entire designator= qualified identifier ;

Static Semantics

The qualified identifier of an entire designator shall denote an entire variable (which may be a formal parameter), or a field of a record variable within a with statement that applies to that variable.

The type of an entire designator shall be the type of the entity that is denoted by the qualified identifier.

annotations Check that the qualified identifier component is defined or declared as a variable, or is a component of a record if the context is the statement sequence of a with statement, and that any qualification is by a module name.

annotations Return the type of the variable or, if the context is a with statement and the entire designator designates a field of a record, the type of the field.

Dynamic Semantics

If the variable designated by an entire designator is a component of a group of variant fields which has an identified tag field, and the value of the tag field is such that the variant containing that component is not active, an exception shall occur (but need not be raised); otherwise, the variable designated by the entire designator shall be the variable or formal parameter associated with the qualified identifier.

If the designated variable belongs to one or more variants without an identified tag field, the variants shall become active.

annotations Return the variable denoted by the qualified identifier. If the variable denoted by the identifier is a field of a variant of a group of variant fields and the tag for that variant fields component exists, then check that the value of the tag is such that it selects that field. If there is no explicit tag, set the implicit tag to select the field.

### Indexed Designators

An indexed designator is a variable designator that is an array variable designator followed by one or more index expressions, and it denotes a component variable of the indexed array variable, or a component of a component of the indexed array variable.

Concrete Syntax

indexed designator=
array variable designator, "[", index expression, { ",", index expression }, "]" ;

array variable designator= variable designator ;

index expression= ordinal expression ;

The concrete syntax allows for a full or abbreviated representation of the indexing of an array variable that is itself designated by an indexed designator. In the abbreviated form, a single comma shall replace the sequence ``] [`' that occurs in the full form. The abbreviated form and the full form shall be equivalent.

Example: Indexing of an indexed designator A variable designator of the form:

        A[E1][E2][E3]

may also be written in the following ways:

        A[E1,E2,E3]  A[E1][E2,E3]  A[E1,E2][E3]

Abstract Syntax

annotations The abstract syntax only uses the full form.

Static Semantics

The array variable designator of an indexed designator shall be a variable designator that is of an array type. The type of the index expression shall be assignment-compatible with the index type of the array type.

The type of an indexed designator shall be the component type of the array type.

annotations Check the designator and expression components of the indexed designator. Check that the variable denoted by the designator is of an array type, and that the index type given in the definition or declaration of the variable is assignment- compatible with the index expression.

annotations Return the type of the component of the array as given in the definition or declaration of the variable.

Dynamic Semantics

The variable designator shall be evaluated to give an array variable. The index expression shall be evaluated to give an ordinal value. Provided that this ordinal value is a value of the index type of the array variable, the variable designated by the indexed designator shall be the component of the array variable indexed by the ordinal value; otherwise an exception shall be raised.

The order of evaluation of the variable designator and the index expression of an indexed designator shall be implementation-dependent.

Note: If a function call appears in the index expression, the evaluation of the indexed designator could produce a transformation of the program state, i.e. have side-effects.

annotations The above evaluation order for the array variable and the index expression is one of those permitted; the index expression may instead be evaluated before the array variable, or both may be evaluated in parallel --- see ???.

### Selected Designators

A selected designator is a variable designator that is a record variable designator followed by a field identifier, and it denotes a component variable of a variable of a record type.

Concrete Syntax

selected designator= record variable designator, ".", field identifier ;

record variable designator= variable designator ;

field identifier= identifier ;

Static Semantics

The record variable designator of a selected designator shall be a variable designator that is of a record type. The field identifier shall be one of the identifiers or tag identifiers of the field list of that record type.

The type of a selected designator shall be the type of the field identifier.

annotations Check the designator component and that it designates a record structure. Check that identifier component is one of the field list identifiers of the record.

annotations Return the type of the field corresponding to the field list identifier.

Dynamic Semantics

The variable designator shall be evaluated to give a record variable. If the field identifier denotes a component of the record variable's type that belongs to a variant of a group of variant fields that has a tag field, and the variant is not active, an exception shall occur (but need not be raised); otherwise the variable designated by the selected designator shall be the component of the record variable selected by the field identifier.

If the designated variable belongs to one or more variants without an identified tag field, the variants shall become active.

annotations Evaluate the designator and select the appropriate field of the record. If the field is a variant component of a variant fields and the tag for that variant fields component exists, then check that the value of the tag is such that it selects that field. If there is no explicit tag, set the implicit tag to select the field.

Auxiliaries

annotations A field of a record may occur in a variant that is nested in several variants. First check that the outer variant is an active variant; this is done by checking that the value of the tag field is consistent with the field component that is referenced. The function is called recursively to check the next (inner) variant.

annotations A field of a record may occur in a variant that is nested in several variants. The outermost variant is made active by assigning an appropriate value to the tag field associated with this variant. The function is called recursively to make the next innermost variant active.

### Dereferenced Designators

A dereferenced designator is a variable designator that is a pointer variable designator followed by a dereferencing operator, and it denotes the variable (if any) that is referenced by the value of the pointer variable designator.

Concrete Syntax

dereferenced designator= pointer variable designator, " " ;

pointer variable designator= variable designator ;

Static Semantics

The pointer variable designator of a dereferenced designator shall be a variable designator that is of a pointer type.

The type of a dereferenced designator shall be the bound type specified in the declaration of the pointer type.

annotations Check the designator and that it designates a variable of a pointer type. Outside of the implementation module in which it is defined, an opaque type is not a pointer type.

Dynamic Semantics

The variable designator shall be evaluated to give a variable P. Provided that the value of the variable P denotes a variable, the variable designated by the dereferenced designator shall be the value of the variable P.

An exception shall be raised if the value of the variable P is the value of the pervasive identifier `NIL`.

An exception shall occur (but need not be raised) if the value of the variable P is a value associated with non-existing storage.

An exception shall occur (but need not be raised) if the value of the variable P is a pointer to a variable of the wrong type.

Note: Since the address type is assignment compatible with all pointer types, the value of the variable P may be a pointer to a variable of the wrong type if it has been assigned through a variable or parameter of the address type.

annotations Check that the value of the pointer is such that it denotes a variable that exists, and that the type of the variable it denotes matches the type of the pointer.

## Expressions

An expression is a formula involving operators and operands whose computation produces a value. However, an expression does not define a value if the computation does not terminate, or if an exception is raised during the computation, such as might arise from using an undefined value, or from dividing by zero.

Changes:

1. This International Standard does not allow arithmetic on values of the address type (except via functions imported from `SYSTEM`).
2. In Programming in Modula-2 there are no predefined types for complex values, nor is any provision made for arithmetic on complex values.

Concrete Syntax

expression= simple expression, [ relational operator, simple expression ] ;

simple expression= [ sign ], term, { term operator, term } ;

term= factor, { factor operator, factor } ;

factor=
"(", expression, ")" |
logical negation operator, factor |
value designator | function call |
value constructor | constant literal ;

Within one expression, operators shall be applied in decreasing order of precedence. If there are two or more operators of the same precedence within a single expression, simple expression, or term, these operators shall be applied from left to right.

Notes:

1. The concrete syntax does not permit an expression to have two operators juxtaposed.

2. The concrete syntax defines four levels of operator precedence. From highest to lowest these are: logical negation operator, factor operators, term operators and signs, and relational operators.

3. Parentheses can be used in an expression to nest another expression, and they can be used to override the operator precedence.

Abstract Syntax

annotations An expression in the concrete representation may include simple expressions and/or terms containing more than one operator. Such an expression is an abbreviation of a fully-parenthesized expression whose simple expressions contain at most one operator (a sign or a term operator) and whose terms contain at most one factor operator. The abstract syntax for expressions models fully-parenthesized expressions. For example, the expression `a*b+c` is an abbreviation of the fully-parenthesized expression `(a*b)+c`. It is modelled in the abstract syntax by an Expression that is an InfixExpression.

- Ordinal Expressions
- Infix Expressions and Operations
- Prefix Expressions
- Value Designators
- Function Calls
- Value Constructors
- Constant Literals
- Constant Expressions

### Ordinal Expressions

An ordinal expression is an expression that produces an ordinal result. There are numerous places where this restriction is needed, and the concrete syntax has been designed to make this readily apparent when this occurs.

Concrete Syntax

ordinal expression= expression ;

### Infix Expressions and Operations

An infix expression is an expression whose value is obtained by applying an infix operator to the values of two operands.

Concrete Syntax

relational operator=
equals operator | inequality operator |
less than operator | greater than operator |
less than or equal operator | subset operator |
greater than or equal operator | superset operator |
set membership operator ;

term operator=
plus operator | set union operator |
minus operator | set difference operator |
logical disjunction operator | string catenate symbol ;

factor operator=
multiplication operator | set intersection operator |
division operator | symmetric set difference operator |
rem operator | div operator |
mod operator | logical conjunction operator ;

Note: The syntax for the various forms of infix operators is given in the Lexis --- see Chapter ???.

Dynamic Semantics

If the operator of an infix expression is not a Boolean operator, the two expressions shall be evaluated, and then the infix operator shall be applied.

Note: The evaluation order that applies when the operator is a Boolean operator is given in Boolean Infix Operations.

annotations In the case of an infix operator other than a Boolean operator, the above evaluation order for the left operand and the right operand is one of those permitted; the right operand may instead be evaluated before the left operand, or both may be evaluated in parallel --- see ???.In the case of a Boolean operator, whether or not the right operand is evaluated depends upon the value of the left operand: the left operand is evaluated first, and, if necessary, the right operand is evaluated and the infix operation performed.

Auxiliaries

annotations For any operand (of an infix expression) that is of the Z-type, the R-type or the C -type, check that its value is within the range of values defined by the type of that infix expression.

Infix Operations

Abstract Syntax

annotations For convenience of the description, infix operations are divided into seven classes.

- Complex Number Infix Operations
- Real Number Infix Operations
- Whole Number Infix Operations
- Boolean Infix Operations
- Set Infix Operations
- String Literal Infix Operations
- Relational Operations

#### Complex Number Infix Operations

For operands of a complex number type, there are four arithmetic infix operations: addition, subtraction, multiplica- tion, and division. These operations are denoted lexically by the symbols ``+`'`,`' ``-`', ``*`', and ``/`' respectively. The result of a complex number infix operation is an approximation to the result of the corresponding mathematical operation.

Static Semantics

A complex number infix operation whose operands are both of the C -type has a result that shall be of the C -type; a complex number infix operation with one operand that is of the C -type has a result that shall be of the same type as the other operand, which shall be of a complex number type. Otherwise both operands shall be of the identical complex number type, and the result shall also be of this type.

Note: Given the types of two operands, the following table indicates the type of the result for those combinations that are permitted.

| complex type | long complex type | C -type
complex type | complex type | error | complex type
long complex type | error | long complex type | long complex type
C -type | complex type | long complex type | C -type

Dynamic Semantics

A complex number infix operation shall be performed with an accuracy that is determined by the types of its operands. This accuracy shall not decrease from the complex type to the long complex type, or from the long complex type to the C -type.

An exception shall be raised if a complex number infix operation leads to overflow. The value of a complex number infix operation that leads to underflow shall be an approximation to the mathematically correct result of the operation.

Notes:

1. Underflow does not cause an exception to be raised.

2. `Gradual underflow' is different from `underflow'. It is defined in the Glossary, and discussed in ???.

Auxiliaries

annotations The result of the function is undefined if the two parameters are not the same complex number type (unless at least one of the parameters is the C -type).

annotations The functions complex-approximation , long-complex-approximation , and complex-constant-approximation are implementation-defined and give approximations to the corresponding mathematical result. The order of non-decreasing accuracy of these functions is: complex-approximation , long-complex-approximation , complex-constant-approximation .

Complex Number Infix Operators

Abstract Syntax

annotations The above operators correspond to ``+`', ``-`', ``*`', and ``/`' respectively.

Dynamic Semantics

The evaluation of the left and right operands of a complex number infix operation shall result in two values, denoted by `lval` and `rval`.

The value of the complex number infix operation ``lval + rval`' shall be the value that results from the addition of the two values `lval` and `rval`.

The value of the complex number infix operation ``lval - rval`' shall be the value that results from subtracting the value `rval` from the value `lval`.

The value of the complex number infix operation ``lval * rval`' shall be the value that results from the multiplication of the two values `lval` and `rval`.

Provided that the magnitude of `rval` is non-zero, the value of the complex number infix operation ``lval / rval`' shall be the value that results from the division of the value `lval` by the value `rval`; otherwise an exception shall be raised.

annotations The operations +, -, *, and / that are used in the above definitions are the mathematical ones, which are of infinite precision. Hence the finite precision of actual implementations is mirrored by infinite precision followed by an approximation operation (performed by get-complex-result ).

#### Real Number Infix Operations

For operands of a real number type, there are four arithmetic infix operations: addition, subtraction, multiplication, and division. These operations are denoted lexically by the symbols ``+`', ``-`', ``*`', and ``/`' respectively. The result of a real number infix operation is an approximation to the result of the corresponding mathematical operation.

Static Semantics

A real number infix operation whose operands are both of the R-type has a result that shall be of the R-type; a real number infix operation with one operand that is of the R-type has a result that shall be of the same type as the other operand, which shall be of a real number type. Otherwise both operands shall be of the identical real number type, and the result shall also be of this type.

Note: Given the types of two operands, the following table indicates the type of the result for those combinations that are permitted.

| real type | long real type | R-type
real type | real type | error | real type
long real type | error | long real type | long real type
R-type | real type | long real type | R-type

Dynamic Semantics

A real number infix operation shall be performed with an accuracy that is determined by the types of its operands. This accuracy shall not decrease from the real type to the long real type, or from the long real type to the R-type.

An exception shall be raised if a real number infix operation leads to overflow. The value of a real number infix operation that leads to underflow shall be an approximation to the mathematically correct result of the operation.

Notes:

1. Underflow does not cause an exception to be raised.

2. `Gradual underflow' is different from `underflow'. It is defined in the Glossary, and discussed in ???.

Auxiliaries

annotations The result of the function is undefined if the two parameters are not the same real number type (unless at least one of the parameters is the R-type).

annotations The functions real-approximation , long-real-approximation , and real-constant-approximation are implementation- defined and give approximations to the corresponding mathematical result. The order of non-decreasing accuracy of these functions is: real-approximation, long-real-approximation , real-constant-approximation .

Real Number Infix Operators

Abstract Syntax

annotations The above operators correspond to ``+`', ``-`', ``*`', and ``/`' respectively.

Dynamic Semantics

The evaluation of the left and right operands of a real number infix operation shall result in two values, denoted by `lval` and `rval`.

The value of the real number infix operation ``lval + rval`' shall be the value that results from the addition of the two values `lval` and `rval`.

The value of the real number infix operation ``lval - rval`' shall be the value that results from subtracting the value `rval` from the value `lval`.

The value of the real number infix operation ``lval * rval`' shall be the value that results from the multiplication of the two values `lval` and `rval`.

Provided that the value `rval` is non-zero, the value of the real number infix operation ``lval / rval`' shall be the value that results from the division of the value `lval` by the value `rval`; otherwise an exception shall be raised.

annotations The operations +, -, *, and / that are used in the above definitions are the mathematical ones, which are of infinite precision. Hence the finite precision of actual implementations is mirrored by infinite precision followed by an approximation operation (performed by get-real-result ).

#### Whole Number Infix Operations

For operands of a whole number type, there are seven arithmetic infix operations: addition, subtraction, multiplication, two forms of division, and two forms of remaindering. These operations are denoted lexically by the symbols ``+`', ``-`', ``*`', ``/`', ``DIV`', ``REM`', and ``MOD`' respectively. The result of a whole number infix operation is mathematically correct if it is within the range of values defined by the whole number type.

Change: The operators ``/`' and ``REM`' are not described in Programming in Modula-2 .

Static Semantics

A whole number infix operation whose operands are both of the Z-type has a result that shall be of the Z-type; a whole number infix operation with one operand that is of the Z-type has a result that shall be of the same type as the other operand, which shall be of a whole number type. Otherwise both operands shall be of the identical whole number type, and the result shall also be of this type.

Note: Given the types of two operands, the following table indicates the type of the result for those combinations that are permitted.

| signed type | unsigned type | Z-type
signed type | signed type | error | signed type
unsigned type | error | unsigned type | unsigned type
Z-type | signed type | unsigned type | Z-type

Dynamic Semantics

The value of a whole number infix operation shall be the mathematically correct result of the operation if the result is within the range of values defined by the result type.

An exception shall occur, and may be raised, if the result is not within the range of values defined by the result type.

Note: If the result of a whole number infix operation is not within the range of values defined by the result type, an implementation for which the result type conforms to the requirements of ISO 10967-1:199x (LIA1) will raise the whole number overflow exception.

Auxiliaries

annotations The result of the function is undefined if the two parameters are not the same whole number type (unless at least one of the parameters is the Z-type).

Whole Number Infix Operators

Abstract Syntax

annotations The above operators correspond to ``+`', ``-`', ``*`', ``/`', ``REM`', ``DIV`', and ``MOD`' respectively.

Dynamic Semantics

The evaluation of the left and right operands of a whole number infix operation shall result in two values, denoted by `lval` and `rval`.

The value of the whole number infix operation ``lval + rval`' shall be the value that results from the addition of the two values `lval` and `rval`.

The value of the whole number infix operation ``lval - rval`' shall be the value that results from subtracting the value `rval` from the value `lval`.

The value of the whole number infix operation ``lval * rval`' shall be the value that results from the multiplication of the two values `lval` and `rval`.

The evaluation of the whole number infix operation ``lval / rval`' shall raise an exception if `rval` is zero; otherwise the value of the whole number infix operation shall be the value `quotient` which is such that the identity

`lval = rval * quotient + remainder`

is satisfied for a value of `remainder` that is either zero, or an integer of the same sign as `lval` and of smaller absolute value than rval.

Note: If `x` and y are whole numbers and `y` is not equal to zero, then `(-x)/y = x/(-y) = - (x/y)`

The evaluation of the whole number infix operation ``lval REM rval`' shall raise an exception if `rval` is zero; otherwise the value of the whole number infix operation shall be the value `remainder` which is such that the identity

`lval = rval * quotient + remainder`

is satisfied for an integral value of `quotient`, and a value of `remainder` that is either zero, or an integer of the same sign as `lval` and of smaller absolute value than `rval`.

The evaluation of the whole number infix operation ``lval DIV rval`' shall raise an exception if `rval` is zero or negative; otherwise the value of the whole number infix operation shall be the value `quotient` which is such that the identity

`lval = rval * quotient + modulus`

is satisfied for a value of `modulus` that is a non-negative integer less than `rval`.

The evaluation of the whole number infix operation ``lval MOD rval`' shall raise an exception if `rval` is zero or negative; otherwise the value of the whole number infix operation shall be the value `modulus` which is such that the identity

`lval = rval * quotient + modulus`

is satisfied for an integral value of `quotient`, and a value of `modulus` that is a non-negative integer less than `rval`.

Note: These operations are exemplified by the following table.

op | 31op10 | 31op(-10) | (-31)op10 | (-31)op(-10)
`/` | 3 | -3 | -3 | 3
`REM` | 1 | 1 | -1 | -1
`DIV` | 3 | Exception | -4 | Exception
`MOD` | 1 | Exception | 9 | Exception

#### Boolean Infix Operations

For operands of the Boolean type, there are two Boolean infix operations: logical conjunction and logical disjunction. These operations are denoted lexically by the symbols ``AND`' and ``OR`' respectively.

Note: The symbol ``&`' may be used as a synonym for ``AND`'.

Static Semantics

Both operands of a Boolean infix operation shall be of the Boolean type, and the result shall also be of the Boolean type.

Boolean Infix Operators

Abstract Syntax

annotations The above operators correspond to ``AND`' (or ``&`') and ``OR`' respectively.

Dynamic Semantics

If the left operand to a logical conjunction operator has the value false , the value of the Boolean infix operation shall be the value false , and the right operand shall not be evaluated. If the left operand to a logical conjunction operator has the value true , the value of the Boolean infix operation shall be the value of the right operand.

If the left operand to a logical disjunction operator has the value true , the value of the Boolean infix operation shall be the value true , and the right operand shall not be evaluated. If the left operand to a logical disjunction operator has the value false , the value of the Boolean infix operation shall be the value of the right operand.

#### Set Infix Operations

For operands of a set type or of a packedset type, there are four set infix operations: set union, set difference, set intersection, and symmetric set difference. These operations are denoted lexically by the symbols ``+`', ``-`', ``*`', and ``/`' respectively.

Note: Set infix operations apply to operands of a set type and to operands of a packedset type.

Static Semantics

Both operands of a set infix operation shall be of the identical set type, and the result shall also be of this type.

Dynamic Semantics

annotations For each set, the actual set of values is contained in a composite object; the sets must be extracted in order to apply the operator, and then the result converted back to the appropriate composite type.

Set Infix Operators

Abstract Syntax

annotations The above operators correspond to ``+`', ``-`', ``*`', and ``/`' respectively.

Dynamic Semantics

The evaluation of the left and right operands of a set infix operation shall result in two values, called the `left value' and the `right value'.

The value of a set union operation shall be the set whose elements are elements of either the left value, or of the right value, or of both values.

The value of a set difference operation shall be the set whose elements are elements of the left value, but are not elements of the right value.

The value of a set intersection operation shall be the set whose elements are elements of both the left value and the right value.

The value of a symmetric set difference operation shall be the set whose elements are elements found in only one of the two values, left value and right value.

#### String Literal Infix Operations

For operands of the string literal type, there is one string literal infix operation: string catenation. This operation is denoted lexically by the symbol ``+`'.

Change: String catenation is not described in Programming in Modula-2 .

Note: String catenation is not applicable to variables of a concrete string type, or to constants of the character type. The examples below show both valid and invalid attempts to perform string catenation.

Example: String catenation.

        CONST
          CR = 15C;
          LF = 12C;
          LineEnd = CR + LF;		 (* valid *)
          DoubleLineEnd = LineEnd + LineEnd; (* valid *)
          Greeting = "hello " + "world";	 (* valid, same as "hello world" *)
          Reply = "hello " + "" + "world";	 (* valid, same as "hello world" *)
          String1 = "I said " + Greeting;	 (* valid, same as "I said hello world" *)
          String2 = Greeting + CR;		 (* valid *)

        CONST
          Linefeed = CHR(10);
          String3 = "hello" + Linefeed;	 (* invalid, Linefeed is of type CHAR *)

        VAR
          who: ARRAY [0 .. 79] OF CHAR;

        BEGIN
          who := Greeting + CR;		 (* valid *)
          who := "I said " + who;		 (* invalid, who is of a concrete string type *)

Static Semantics

Both operands of a string literal infix operation shall be of the string literal type, and the result shall also be of this type.

Dynamic Semantics

The evaluation of the left and right operands of a string literal infix operation shall result in two values, called the `left value' and the `right value'.

The value of a string literal infix operation shall be the string value formed by the catenation of the right value to the end of the left value.

Clarification: This International Standard has not adopted a change to Modula-2 (described in the fourth edition of Programming in Modula-2 ) of always requiring a string terminator for a string value.

#### Relational Operations

For operands of an elementary type, there are relational operations that provide tests for equality and inequality. These operations are denoted lexically by the symbols ``=`' and ``<>`' respectively. For operands of a scalar type, there are further relational operations that provide tests for ordering. These operations are denoted lexically by the symbols ``<`', ``>`', ``<=`' and ``>=`'. For operands of a set type or a packedset type, there are relational operations that provide set relationships, and an operation that provides a test for set membership. These operations are denoted lexically by the symbols ``<=`', ``>=`' and ``IN`' respectively.

Note: The symbol ``#`' may be used as a synonym for ``<>`'.

##### Complex Comparison Operations

Two complex comparison operators are provided for operands of a complex number type. These operators are denoted lexically by the symbols ``=`' and ``<>`' (or ``#`').

Static Semantics

Both operands of a complex comparison operation shall be of types that are complex number types, and these types shall be expression-compatible. The result of a complex comparison operation shall be of the Boolean type.

Complex Comparison Operators

Abstract Syntax

annotations The above operators correspond to ``=`' and ``<>`' (or ``#`') respectively.

Dynamic Semantics

The evaluation of the left and right operands of a complex comparison operation shall result in two values.

The value of a complex equality operation shall be the value true if and only if the two values are the same.

The value of a complex inequality operation shall be the value true if and only if the two values are different.

Note: A consequence of the approximation inherent in complex number types is that the result of a complex comparison operation will depend upon the nature of the approximation.

##### Scalar Relational Operations

Six scalar relational operators are provided for operands of a scalar type. These operators are denoted lexically by the symbols ``=`', ``<>`' (or ``#`'), ``<`', ``>`', ``<=`', and ``>=`'.

Static Semantics

Both operands of a scalar relational operation shall be of types that are scalar types, and these types shall be expression-compatible. The result of a scalar relational operation shall be of the Boolean type.

Note: The Boolean type is an ordinal type with the value false being less than the value true . So, if `p` and `q` are operands of the Boolean type, ``p = q`' denotes their equivalence and ``p <= q`' means ``p` implies `q`'.

Scalar Relational Operators

Abstract Syntax

annotations The above operators correspond to ``=`', ``<>`' (or ``#`'), ``<`', ``>`', ``<=`' and ``>=`' respectively.

Dynamic Semantics

The evaluation of the left and right operands of a scalar relational operation shall result in two values, called the `left value' and the `right value'.

The value of a scalar equality operation shall be the value true if and only if the two values are the same.

The value of a scalar inequality operation shall be the value true if and only if the two values are different.

The value of a scalar less than operation shall be the value true if and only if the left value is less than the right value.

The value of a scalar greater than operation shall be the value true if and only if the left value is greater than the right value.

The value of a scalar less than or equal operation shall be the value true if and only if the left value is less than or equal to the right value.

The value of a scalar greater than or equal operation shall be the value true if and only if the left value is greater than or equal to the right value.

Note: A consequence of the approximation inherent in real number types is that, for operands of these types, the result of a scalar relational operation will depend upon the nature of the approximation.

##### Set Relational Operations

Five set relational operators are provided. These operators are denoted lexically by the symbols ``=`', ``<>`' (or ``#`'), ``<=`', ``>=`', and ``IN`'.

Static Semantics

Both operands of a set equality, set inequality, subset, or superset operation shall be of types that are set types, and these types shall be identical.

The right operand of a set membership operation shall be of a set type. The type of the left operand and the base type of the set type shall be assignment-compatible.

The result of a set relational operation shall be of the Boolean type.

Dynamic Semantics

annotations The actual set of values is contained in a composite object, so the sets must be extracted in order to apply the operator.

Set Relational Operators

Abstract Syntax

annotations The above operators correspond to ``=`', ``<>`' (or ``#`'), ``<=`', ``>=`' and ``IN`' respectively.

Dynamic Semantics

The evaluation of the left and right operands of a set relational operation shall result in two values, called the `left value' and the `right value'.

The value of a set equality operation shall be the value true if and only if the two values have the same elements.

The value of a set inequality operation shall be the value true if and only if the two values do not have the same elements.

The value of a subset operation shall be the value true if and only if all the elements of the left value are also in the right value.

The value of a superset operation shall be the value true if and only if all the elements of the right value are also in the left value.

The value of a set membership operation shall be the value true if and only if the left value is an element of the right value.

Note: A consequence of the above rules is that ``1000 IN DigitSet{0..9}`' produces a result of false , and no exception is raised.

Example: Set complement. Given the declarations:

        TYPE
          BaseType = ...
          SetType = SET OF BaseType;
        VAR
          s, complement : SetType;

the complement of the set s can be calculated by:

        complement := SetType{MIN(BaseType)..MAX(BaseType)} - s;

##### Procedure Relational Operations

Two procedure relational operators are provided for operands of a procedure type or a procedure structure. These operators are denoted lexically by the symbols ``=`' and ``<>`' (or ``#`').

Static Semantics

If both operands of a procedure relational operation are variables of a procedure type, those variables shall be of identical type.

If at least one of the operands of a procedure relational operation is a declared procedure, or a procedure constant, the operands shall be of identical structure.

Notes:

1. The structure of a procedure, procedure constant, or procedure type is given by the number, formal types, and binding of the formal parameters, and by the function return type (in the case of a function procedure, function procedure constant, or function procedure type).

2. Standard procedures and system procedures may not be operands in a procedure relational operation.

Example: Procedure relational operations.

        PROCEDURE Relations(fp: INTEGER);
          PROCEDURE A(fp: CARDINAL); BEGIN END A;
          PROCEDURE B(fp: CARDINAL); BEGIN END B;
          PROCEDURE C(fp: INTEGER); BEGIN END C;
          TYPE TC1 = PROCEDURE(CARDINAL); TC2 = PROCEDURE(CARDINAL);
          CONST AA = A; untrue = (A = B); (* valid *)
          VAR VC1a, VC1b: TC1; VC2: TC2;
        BEGIN
          VC1a := A; VC1b := AA; VC2 := B;
          IF VC1a = VC1b THEN END ; (* valid *)
          IF VC1a = VC2 THEN END ; (* invalid - different types *)
          IF VC1a = B THEN END ; (* valid *)
          IF VC1a = C THEN END ; (* invalid - different structure *)
          IF Relations = C THEN END ; (* valid *)
        END Relations;

The result of a procedure relational operation shall be of the Boolean type.

Procedure Relational Operators

Abstract Syntax

annotations The above operators correspond to ``=`' and ``<>`' (or ``#`') respectively.

Clarification: Programming in Modula-2 does not state whether the equality and inequality operators are applicable to values that are procedures.

Dynamic Semantics

The value of a procedure equality operation shall be the value true if and only if the values of both operands denote the same procedure text.

The value of a procedure inequality operation shall be the value true if and only if the values of both operands do not denote the same procedure text.

##### Pointer Relational Operations

Two pointer relational operators are provided for operands of a pointer type or an opaque type. These operators are denoted lexically by the symbols ``=`' and ``<>`' (or ``#`').

Static Semantics

One of the following shall hold for the operands of a pointer relational operation:

a) both operands are of identical opaque type,

b) both operands are of identical pointer type,

c) one operand is of a pointer type and the value of the other is the nil value.

d) both operands have the nil value.

Note: The nil value is that denoted by the pervasive identifier `NIL` --- see The Nil Type.

The result of a pointer relational operation shall be of the Boolean type.

Clarification: This International Standard agrees with the third edition of Programming in Modula-2 , which allows the equality and inequality operators to be applied to values of an opaque type.

annotations Opaque types are indistinguishable from pointer types with respect to the meaning function. The well-formed conditions forbid the dereferencing of a value of an opaque type outside of the implementation module in which the opaque type is declared --- see Dereferenced Designators.

Pointer Relational Operators

Abstract Syntax

annotations The above operators correspond to ``=`' and ``<>`' (or ``#`') respectively.

Dynamic Semantics

The value of a pointer equality operation shall be the value true if and only if the values of both operands denote the same variable, or if they both have the nil value.

The value of a pointer inequality operation shall be the value true if and only if the values of both operands do not denote the same variable, and if they do not both have the nil value.

Note: Since pointer values can be constructed via `SYSTEM.MAKEADR`, these semantics are defined in terms of the underlying model rather than the objects held in the store.

##### Protection Relational Operations

Two protection relational operators are provided for operands of the implementation-defined protection type. These operators are denoted lexically by the symbols ``<=`' and ``>=`'. The protection relational operators are those that are common both to ordinal types and to set types --- see The Protection Type.

Static Semantics

Both operands of a protection relational operation shall be of the protection type.

The result of a protection relational operation shall be of the Boolean type.

Protection Relational Operators

Abstract Syntax

annotations The above operators correspond to ``<=`' and ``>=`' respectively.

Dynamic Semantics

The value of a protection less than or equal operation, or a protection greater than or equal operation, shall depend on the implementation-defined order of the values of the protection type. The ordering shall be such that a value P1 of the protection type shall compare less than or equal to another value P2 if and only if P1 does not prevent any of the interrupts not prevented by P2.

##### System Basic Types Relational Operations

Two relational operators are provided for operands of a system basic type, other than the location type. These operators are denoted lexically by the symbols ``=`' and ``<>`' (or ``#`').

The system basic type whose values may be compared for equality and inequality is the coroutine type --- see The Module COROUTINES. The interrupt source type, which is also defined by the system module `COROUTINES`, is an implementation-defined type that may be identical to a basic type or may be a predefined constructed type; corresponding operations will therefore be applicable to that type.

The only operation directly defined on the location type is assignment --- see The Module SYSTEM. Values of the location type may only be compared if they are first interpreted as a value of another type using `SYSTEM.CAST`.

Static Semantics

The operands of a system basic type relational operation shall be of identical type.

The result of a system basic type relational operation shall be of the Boolean type.

System Basic Types Relational Operators

Abstract Syntax

annotations The above operators correspond to ``=`' and ``<>`' (or ``#`') respectively.

Dynamic Semantics

The value of a system basic type equality operation shall be the value true if and only if the values of both operands are the same, and hence identify the same coroutine.

The value of a system basic type inequality operation shall be the value true if and only if the values of both operands are not the same, and hence do not identify the same coroutine.

### Prefix Expressions

A prefix expression is an expression whose value is obtained by applying a prefix operator to the value of a single operand.

Concrete Syntax

Note: The syntax for the various forms of prefix operators is given in the Lexis --- see Chapter ???.

Dynamic Semantics

The expression shall be evaluated first, and then the prefix operator shall be applied.

Prefix Operations

Abstract Syntax

annotations For convenience of the description, prefix operations are divided into two classes.

- Arithmetic Prefix Operations
- Boolean Prefix Operations

#### Arithmetic Prefix Operations

There are two arithmetic prefix operations: identity and arithmetic negation. These operations are denoted lexically by the symbols ``+`' and ``-`' respectively. If the operand of an arithmetic prefix operation is of a complex number type or a real number type, the result of the operation is an approximation to the result of the corresponding mathematical operation. If the operand is of a whole number type, the result of the operation is mathematically correct if it is within the range of values defined by the whole number type.

Static Semantics

The operand of an arithmetic prefix operation shall be of a complex number type, a real number type or a whole number type, except that the arithmetic negation operator shall not be applied to an operand of an unsigned type.

Note: The semantics disallow the use of the arithmetic negation operator in an expression such as `(-a+b)` when the type of the expression is the unsigned type.

Dynamic Semantics

The value of an arithmetic prefix operation shall be the mathematically correct result of the operation if the result is within the range of values defined by the type of the operand.

An exception shall be raised if the result is not within the range of values defined by the type of the operand.

Note: An exception may be raised if the arithmetic negation operator is applied to an operand of a numeric type that has a non-symmetric range.

Auxiliaries

annotations Return the type of an arithmetic prefix operation. The result is undefined if the arithmetic negation operator is applied to a value of an unsigned type or if it is applied to a value of a non-numeric type.

Arithmetic Prefix Operators

Abstract Syntax

annotations The above operators correspond to ``+`' and ``-`' respectively.

Dynamic Semantics

The value of an identity operation shall be the value of its operand.

The value of an arithmetic negation operation shall be the additive inverse of the value of its operand.

#### Boolean Prefix Operations

There is one Boolean prefix operation: logical negation. This operation is denoted lexically by the symbol ``NOT`'.

Note: The symbol ``~`' may be used as a synonym for ``NOT`'.

Static Semantics

The operand of a Boolean prefix operation shall be of the Boolean type.

Boolean Prefix Operators

Abstract Syntax

annotations The above operator corresponds to ``NOT`' or ``~`'.

Dynamic Semantics

The value of a Boolean prefix operation shall be the value true if its operand has the value false , or false if its operand has the value true .

### Value Designators

A value designator is an expression denoting a constant, a variable (including a formal parameter of a procedure), a component of a constant or variable, or a procedure.

Concrete Syntax

value designator=
entire value | indexed value |
selected value | dereferenced value ;

- Entire Values
- Indexed Values
- Selected Values
- Dereferenced Values

#### Entire Values

An entire value is a value designator that is a qualified identifier; it denotes a constant, a variable (which may be a formal parameter), a field of a record within a with statement that applies to that record, or a declared procedure.

Concrete Syntax

entire value= qualified identifier ;

Abstract Syntax

annotations Within the body of a with statement, an entire value may also be the field identifier of a record that has been specified in the designator component of the with statement.

Static Semantics

The qualified identifier of an entire value shall denote a constant, a variable (which may be a formal parameter), a field of a record within a with statement that applies to that record, or a procedure.

If the type of the entity denoted by the qualified identifier is a subrange type, the type of the entire value shall be the host type of that subrange type; otherwise it shall be the type of the entity denoted by the qualified identifier.

annotations The type information for a procedure or procedure constant includes its structure and its declaration level.

Dynamic Semantics

The value of an entire value shall be the value of the entity denoted by the qualified identifier.

An exception shall occur (but need not be raised) if the entity denoted by the qualified identifier is a variable of an elementary type whose value is undefined.

Note: The value of a variable might be undefined because no value has been assigned to that variable, or because the variable is a component of a variant and either that variant is not active or no value has been assigned to that component since the variant was made active.

#### Indexed Values

An indexed value is an expression that is an array value followed by one or more index expressions, and it denotes a component of the indexed array value, or a component of a component of the indexed array value.

Concrete Syntax

indexed value= array value, "[", index expression, { ",", index expression }, "]" ;

array value= value designator ;

The concrete syntax allows for a full or abbreviated representation of the indexing of an array value that is itself an indexed value. In the abbreviated form, a single comma shall replace the sequence ``] [`' that occurs in the full form. The abbreviated form and the full form shall be equivalent.

Example: Indexing of an indexed value. A value designator of the form:

        A[E1][E2][E3]

may also be written in the following ways:

        A[E1,E2,E3] A[E1][E2,E3] A[E1,E2][E3]

Abstract Syntax

annotations The abstract syntax only uses the full form.

Static Semantics

The array value of an indexed value shall be a value designator that is of an array type. The type of the index expression shall be assignment-compatible with the index type of the array type.

If the component type of the array type is a subrange type, the type of an indexed value shall be the host type of that component type; otherwise it shall be the component type of the array type.

Note: An indexed value cannot be formed by indexing a string constant.

Dynamic Semantics

The value designator shall be evaluated to give an array value. The index expression shall be evaluated to give an ordinal value. Provided that this ordinal value is a value of the index type of the array value, the value of the indexed value shall be the value of the component of the array value indexed by the ordinal value; otherwise an exception shall be raised.

The order of evaluation of the value designator and the index expression of an indexed value shall be implementation- dependent.

Note: If a function call appears in the index expression, the evaluation of the indexed value could produce a transfor- mation of the program state, i.e. have side-effects.

annotations The above evaluation order for the array value and the index expression is one of those permitted; the index expression may instead be evaluated before the array value, or both may be evaluated in parallel | see 4.1.

#### Selected Values

A selected value is an expression that is a record value followed by a field identifier, and it denotes the value of the identified field of the record value.

Concrete Syntax

selected value= record value, ".", field identifier ;

record value= value designator ;

Static Semantics

The record value of a selected value shall be a value designator that is of a record type. The field identifier shall be one of the identifiers or tag identifiers of the field list of that record type.

If the the type of the field denoted by the field identifier is a subrange type, the type of a selected value shall be the host type of the type of the denoted field; otherwise it shall be the type of that field.

Dynamic Semantics

The value designator shall be evaluated to give a record value. Provided that the field identifier denotes a component of a variant of the record type that is a component of the record value, the value of the selected value shall be the value of the component of the record value selected by the field identifier; otherwise an exception shall occur (but need not be raised).

#### Dereferenced Values

A dereferenced value is an expression that is a pointer value followed by a dereferencing operator, and it denotes the value of the variable (if any) that is referenced by the pointer value.

Concrete Syntax

dereferenced value= pointer value, dereferencing operator ;

pointer value= value designator ;

Static Semantics

The pointer value of a dereferenced value shall be a value designator that is of a pointer type.

If the the type of the bound type specified in the declaration of the pointer type is a subrange type, the type of a dereferenced value shall be the host type of the bound type; otherwise it shall be the bound type.

Dynamic Semantics

The value designator shall be evaluated to give a pointer value. Provided that this pointer value denotes a variable, the value of the dereferenced value shall be the value of that variable.

An exception shall be raised if the pointer value is the nil value.

An exception shall occur (but need not be raised) if the pointer value is undefined.

An exception shall occur (but need not be raised) if the value is a pointer to a variable of the wrong type.

Note: Since the address type is assignment compatible with all pointer types, the value may be a pointer to a variable of the wrong type if it has been assigned through a variable or parameter of the address type.

### Function Calls

A function call specifies the evaluation of any actual parameters and the activation and execution of the block associated with the function designator of the function call. The value of a function call is the value returned by the execution of this block.

Concrete Syntax

function call= function designator, actual parameters ;

function designator= value designator ;

Abstract Syntax

annotations The identifiers of predefined procedures are distinguished since these do not denote values (that can be assigned or compared in expressions).

Static Semantics

The function designator of a function call shall be a value designator that denotes a function procedure or the identifier of a predefined function procedure.

Notes:

1. A value designator that denotes a function procedure is either a procedure identifier of a function procedure heading (possibly qualified by the name or names of modules from which the procedure identifier is exported), a value designator that denotes a constant that has a function procedure value, or a value designator that denotes a variable that has a function procedure type.

2. The identifiers of predefined procedures are not value designators since predefined procedures are not values that can be assigned, compared in expressions, or passed as procedure parameters.

In the case of a call of a predefined function procedure, the actual parameters shall correspond in number and in type to those required for that predefined function; otherwise, each actual parameter shall be parameter compatible with the corresponding formal parameter of the designated function procedure.

If the return type of the designated function procedure is a subrange type, then the type of the function call shall be the host type of that subrange type; otherwise it shall be the return type of the designated function procedure.

Dynamic Semantics

The execution of a function call shall be the evaluation of any actual parameters to give corresponding arguments, the binding of the results of this evaluation to the corresponding formal parameters, and the execution of the actions associated with the function designator. In the case of a call of a predefined function, the actions are as specified for that predefined function; otherwise, the actions are as specified by the block of the function procedure declaration.

The order of evaluation, the order of accessing and the order of binding of the actual parameters shall be implementation-dependent. The order of evaluation of the function designator and the actual parameters shall be implementation-dependent.

The actual parameters shall be evaluated before the execution of the actions associated with the function procedure designator.

The value of a function call shall be the value returned by the execution of the associated actions.

annotations The above evaluation order for the function designator and the actual parameters is one of those permitted; the actual parameters may instead be evaluated before the function designator, or both may be evaluated in parallel | see 4.1.

### Value Constructors

A value constructor is an expression denoting a value of an array type, a record type, or a set type. In the case of array constructors and record constructors a list of values, known as `structure components', is specified to define the values of the components of the array value or the fields of the record value. In the case of a set constructor a list of `members' is specified, whose elements define the elements of the set value.

Change: Array constructors and record constructors are not described in Programming in Modula-2 .

Note: The syntax of each form of value constructor requires a type identifier, and so a value constructor cannot be used to denote a value for a variable or a constant of an anonymous type.

Concrete Syntax

value constructor= array constructor | record constructor | set constructor ;

- Array Constructors
- Record Constructors
- Set Constructors

#### Array Constructors

An array constructor is an expression that denotes a value of a specified array type. The array type is specified by an array type identifier. The array value is specified by an array constructed value that has a structure component for each component of the array. The repetition of a structure component may be specified by giving an optional repetition factor.

Note: An array constructor cannot denote a value for a formal parameter that is an open array parameter.

Concrete Syntax

array constructor= array type identifier, array constructed value ;

array type identifier= type identifier ;

array type identifier = type identifier ; Example: Array constructors. Given the declarations:

        TYPE StringType = ARRAY [0..24] OF CHAR;
      	 RowType = ARRAY [1..3] OF REAL;
      	 Array1Type = ARRAY [1..2] OF RowType;
     	 Array2Type = ARRAY [1..2], [1..3] OF REAL;
        VAR  filler: CHAR;
      	 string: StringType;
     	 row: RowType;
      	 array1: Array1Type;
      	 array2: Array2Type;

the following statements are possible:

        string:= StringType{' ' BY 25};
        string:= StringType{filler BY 25};
        string:= StringType{filler, ' ' BY 23, filler};
        row:= RowType{1.0, 1.0, 1.0};
        row:= RowType{1.0 BY 3};
        array1:= Array1Type{row, row};
        array1:= Array1Type{row BY 2};
        array1:= Array1Type{RowType{1.0, 1.0, 1.0},
      			RowType{1.0, 1.0, 1.0}};
        array1:= Array1Type{RowType{1.0, 1.0, 1.0} BY 2};
        array1:= Array1Type{{1.0, 1.0, 1.0}, {1.0, 1.0, 1.0}};
        array1:= Array1Type{{1.0, 1.0, 1.0} BY 2};
        array1:= Array1Type{{1.0 BY 3} BY 2};
        array2:= Array2Type{{1.0, 1.0, 1.0}, {1.0, 1.0, 1.0}};
        array2:= Array2Type{{1.0, 1.0, 1.0} BY 2};
        array2:= Array2Type{{1.0 BY 3} BY 2};

Static Semantics

The array type identifier of an array constructor shall be a type identifier that denotes an array type. The type of the array constructor shall be that array type.

The array constructed value of an array constructor shall be well-formed with respect to a given array type that is the type of the array constructor.

Dynamic Semantics

The value of an array constructor shall be the value of the array constructed value evaluated as a value of the type of the array constructor.

annotations Note that an exception may be detected as each individual component is evaluated.

Array Constructed Values

An array constructed value denotes a value of an array type by specifying a structure component for each component of the array. It can either form part of an array constructor, or it can be used as a structure component of an array constructor or a record constructor.

Array constructed values are evaluated as a value of a given type. This type is specified explicitly by the type identifier in the case of array constructors. For structure components, the type is implicitly the component type of an array type or the corresponding field type of a record type.

Concrete Syntax

array constructed value=
"{", repeated structure component, { ",", repeated structure component }, "}" ;

Static Semantics

The sequence of repeated structure components of an array constructed value of a given array type shall be taken, one at a time, in the order that the repeated structure components appear in the sequence of repeated structure components. Each repeated structure component having a repetition factor of N shall lead to N consecutive occurrences of its structure component in a sequence of structure components. The length of this sequence of structure components shall be equal to the number of values of the range of values defined by the index type of the given array type.

The structure components shall be well-formed with respect to a structure component type that is the component type of the given array type.

annotations Check that the number of structure components of an array definition is the same as the number of values of the range of values defined by the index type of the array type.

Dynamic Semantics

The value of an array constructed value, evaluated as a value of a given array type, shall be the value of that type for which the value of the Nresults of the evaluation of the repeated structure components as sequences of values of the component type of the given array type.

The order of evaluation of the expressions of an array constructed value shall be implementation-dependent.

Note: The evaluation of the expressions of an array constructed value could produce a transformation of the program state, i.e. have side-effects.

Auxiliaries

annotations Return the number of structure components in an array definition.

annotations Return the number of structure components in an array definition after expanding any repetitions.

annotations Construct an array value from an evaluated array definition.

annotations Evaluate the structure components of an array definition.

Repeated Structure Components

Repeated structure components are structure components that can be followed by a repetition factor.

Concrete Syntax

repeated structure component=
structure component, [ "BY", repetition factor ] ;

repetition factor= constant expression ;

Abstract Syntax

annotations If the repetition factor is not present in the concrete representation, the translation process (from concrete to abstract syntax) will supply a by component in the abstract representation equal to 1.

Static Semantics

If a repeated structure component contains a repetition factor, the repetition factor shall be a constant expression of a whole number type and shall not have a value less than 0.

Note: A repetition factor of 0 is allowed for parameterized source code.

Example: Parameterized repetion factors.

        CONST
          mayChangeToZeroOneDay = 6;
        TYPE
          T = ARRAY [0 .. mayChangeToZeroOneDay] OF CARDINAL;
        VAR
          v: T;
        BEGIN
          v := T{0, 1 BY mayChangeToZeroOneDay};

Dynamic Semantics

The structure component shall be evaluated to give a value of the given type. The value of a repeated structure component shall be the sequence of N occurrences of that value, where N is the value of the repetition factor, if given, or is the value 1, if a repetition factor is not given.

Structure Components

Structure components define the values of the components of an array constructed value or the fields of a record constructed value.

Concrete Syntax

structure component=
expression | array constructed value |
record constructed value | set constructed value ;

Static Semantics

If a structure component is an expression, the structure component type shall be assignment-compatible with the type of the expression.

If a structure component is an array, record, or set constructed value, the constructed value shall be well-formed with respect to a given type that is the structure component type.

Dynamic Semantics

The value of a structure component that is an expression shall be the value of the expression. An exception shall be raised if the value is not within the range of values defined by the structure component type.

The value of a structure component that is an array constructed value, a record constructed value, or a set constructed value shall be the value of the constructed value evaluated as a value of the structure component type.

#### Record Constructors

A record constructor is an expression that denotes a value of a specified record type. The record type is specified by a record type identifier. The record value is specified by a record constructed value that has a structure component for each field of the record.

Concrete Syntax

record constructor= record type identifier, record constructed value ;

record type identifier= type identifier ;

Example: Record constructors. Given the declarations:

        TYPE NameType = ARRAY [0..24] OF CHAR;
      	 DateType = RECORD
     		      year, month, day: CARDINAL
      		    END ;
     	 PersonType = RECORD
     	 		  name: NameType;
     		   DateOfBirth: DateType
      		      END ;
        VAR  day, month, year: CARDINAL;
      	 date: DateType; person: PersonType;

the following statements are possible:

        SWholeIO.ReadCard(year);
        SWholeIO.ReadCard(month);
        SWholeIO.ReadCard(day);
        date:= DateType{year, month, day};
        date:= DateType{1623, 6, 19};
        person:= PersonType{"Blaise Pascal", date};
        person:=
          PersonType{"Blaise Pascal", DateType{1623, 6, 19}};
        nobody:=
          PersonType{NameType{"" BY 25}, DateType{0, 0, 0}};
        nobody:= PersonType{{"" BY 25}, {0, 0, 0}};

Static Semantics

The record type identifier of a record constructor shall be a type identifier that denotes a record type. The type of the record constructor shall be that record type.

The record constructed value of a record constructor shall be well-formed with respect to a given record type that is the type of the record constructor.

Dynamic Semantics

The value of a record constructor shall be the value of the record constructed value evaluated as a value of the type of the record constructor.

annotations Note that an exception may be detected as each individual component is evaluated.

Record Constructed Values

A record constructed value denotes a value of a record type by specifying a structure component for each field of the record. It can either form part of a record constructor, or it can be used as a structure component of an array constructor or a record constructor.

Record constructed values are evaluated as a value of a given type. This type is specified explicitly by the type identifier in the case of record constructors. For structure components, the type is implicitly the component type of an array type or the corresponding field type of a record type.

Concrete Syntax

record constructed value=
"{", [ structure component, { ",", structure component } ], "}" ;

Static Semantics

A sequence of fields shall be formed from the fields of the given record type taken, one at a time, in the order that the fields textually appear in the declaration of the type denoted by the given record type. If the Nsequence of fields is a tag field, then the Nconstructed value shall be an expression that is a constant expression. If there is no else variant part associated with the tag field, then the value of the constant expression shall be such that there is a variant associated with the value of the constant expression. The fields of any variant that is not associated with the value of the constant expression shall be excluded from the sequence of fields. If no variant is associated with the value of the constant expression, then the fields of the else variant part shall be included in the sequence of fields.

Note: A constant expression must be supplied for a tag field even if the tag field is an implicit tag field.

The length of the sequence of structure components of the record constructed value shall be equal to the length of the sequence of fields.

The Ncomponent type that is the type of the N

annotations Check that the number of structure components of a record definition is the same as the number of fields of the record type, taking into account tag field variant selection.

Dynamic Semantics

The value of a record constructed value, evaluated as a value of a given record type, shall be the value of that type for which the value of the Ncomponents as values of the corresponding field type of the given record type.

The order of evaluation of the expressions of a record constructed value shall be implementation-dependent.

Note: The evaluation of the expressions of a record constructed value could produce a transformation of the program state, i.e. have side-effects.

Auxiliaries

annotations Calculate the number of components in a fields-list.

annotations Calculate the number of components in a fields.

annotations Calculate the number of components in a fixed-fields.

annotations Calculate the number of components in a variant component of a record structure, selected by the value of the tag field.

annotations Calculate the number of components in a variant component of a record structure.

annotations Check that the structure defined by a fields-list matches the structure given by an expression sequence component of a structured record value.

annotations Check that the structure defined by a fields matches the structure given by an expression sequence component of a structured record value.

annotations Check that the type of each expression in the record constructor is assignment-compatible with the type of the corresponding component of a record type.

annotations Check that the type of each expression in the record constructor is assignment-compatible with the type of the corresponding component of the record type; also check that the expression that corresponds to any tag field is a constant expression. The result is undefined if the structured value does not match the type.

annotations Check the expressions in the record constructor that correspond to a variant component.

annotations Build a record value corresponding to a fields-list component of a record from an expression sequence.

annotations Build a record value corresponding to a fixed-fields component of a record from an expression sequence. construct-variant-fields-value : Variant-fields-structure ? Elements ! Environment

annotations Build a record value corresponding to a variant-fields component of a record from an expression sequence.

annotations Build a record value corresponding to a variant component of a record from an expression sequence.

#### Set Constructors

A set constructor is an expression that denotes a value of a specified set type or packedset type. The type is specified by a set type or packedset type identifier. The set or packedset value is specified by a set constructed value that specifies each of the elements of the set. An individual element can be specified by using an expression, and several elements can be specified by using an interval.

Concrete Syntax

set constructor= set type identifier, set constructed value ;

set type identifier= type identifier ;

Change: In Programming in Modula-2 the set type identifier of a set constructor may be omitted, in which case it implicitly denotes the standard type `BITSET`.

Example: Set constructors. Given the declarations:

        TYPE YearType = CARDINAL;
       	 PeriodType = SET OF YearType;
       	 EntryType = RECORD
       			name: NameType;
       			lifetime: PeriodType
      		     END ;
        VAR year: CARDINAL;
      	period: PeriodType; entry: EntryType;

the following statements are possible:

        period:= PeriodType{1982, 1983, 1985, 1988};
        SWholeIO.ReadCard(year);
        period:= PeriodType{year-4..year+4};
        period:= PeriodType{1623..1662};
        entry:= EntryType{"Blaise Pascal", period};
        entry:= EntryType{"Blaise Pascal",
    		      PeriodType{1623..1662}};
        entry:= EntryType{"Blaise Pascal", {1623..1662}};

Static Semantics

The set type identifier of a set constructor shall be a type identifier that denotes a set type or a packedset type. The type of the set constructor shall be that set type or packedset type.

The set constructed value of a set constructor shall be well-formed with respect to a given set type that is the type of the set constructor.

Dynamic Semantics

The value of a set constructor shall be the value of its set constructed value evaluated as a value of the type of the set constructor.

Set Constructed Values

A set constructed value denotes a value of a set type, by specifying each of the elements of the set. It can either form part of a set constructor, or it can be used as a structure component of an array constructor or a record constructor. An individual element of the set can be specified by using an expression, and several elements can be specified by using an interval.

Set constructed values are evaluated as a value of a given type. This type is specified explicitly by the type identifier in the case of set constructors. For structure components, the type is implicitly the component type of an array type or the corresponding field type of a record type.

Notes:

1. The construct '`{}`' denotes the empty set of the given set type. An empty set is a value of every set type.

2. Since the base type of a set type contains at least one value, there are at least two values of a set type.

Concrete Syntax

set constructed value= "{", [ member, { ",", member } ], "}" ;

Static Semantics

For each element of the set constructed value, the base type of the given set type shall be assignment-compatible with the type of the element.

Clarification: In Programming in Modula-2 it is not stated that, for each element of the set constructed value, the base type of the given set type has to be assignment-compatible with the type of the element.

annotations In the VDM-SL modelling of a Modula-2 set, the Set-constructed-value is given a type according to the types of the elements of the set. The given type is tested for assignment-compatibility with the type of the Set-constructed-value.

Dynamic Semantics

Each member of a set constructed value shall be evaluated to give a value. The value of the set constructed value shall be the union of these values.

An exception shall be raised if at least one element of this value is not within the range of values defined by the base type of the given set type.

The order of evaluation of the expressions of a set constructed value shall be implementation-dependent.

Note: The evaluation of the expressions of a set constructor could produce a transformation of the program state, i.e. have side-effects.

Members

A member denotes a set value that either contains values from a range of values or contains a single value.

Concrete Syntax

member= interval | singleton ;

Static Semantics

If a member is an interval, then the type of the member shall be the type of the interval; otherwise it shall be the type of the singleton.

Dynamic Semantics

If a member is an interval, then the value of the member shall be the value of the interval; otherwise it shall be the value of the singleton.

Intervals

An interval denotes a set value whose elements are defined by a range of values.

Concrete Syntax

interval= ordinal expression, "..", ordinal expression ;

Static Semantics

Each ordinal expression of an interval shall be an expression that is of an ordinal type. The types of the ordinal expressions shall be expression-compatible.

The base type of the interval shall be the type of each ordinal expression, if they are of the same type. If the type of one ordinal expression is the Z-type, and the type of the other ordinal expression is the signed type, the base type of the interval shall be the signed type. If the type of one ordinal expression is the Z-type, and the type of the other ordinal expression is the unsigned type, the base type of the interval shall be the unsigned type.

Dynamic Semantics

The value of an interval of the form ``x..y`', where x and y are ordinal expressions, shall be an empty set if the value of `x` is greater than the value of `y`; otherwise it shall be a set whose elements have the values in the closed interval from the value of `x` to the value of `y`.

annotations The above evaluation order for the minimum expression and the maximum expression is one of those permitted; the maximum expression may instead be evaluated before the minimum expression, or both may be evaluated in parallel --- see ???.

Singletons

A singleton denotes a set value with one element, defined by a expression.

Concrete Syntax

singleton= ordinal expression ;

Static Semantics

The ordinal expression of a singleton shall be an expression that is of an ordinal type.

The base type of a singleton shall be the type of the ordinal expression.

Dynamic Semantics

The value of a singleton shall be a set of one element that has the value of the ordinal expression.

### Constant Literals

A constant literal denotes a constant value.

Concrete Syntax

constant literal= whole number literal | real literal | string literal ;

Note: There is no denotation for a complex literal. However, a value of the C -type can be formed by applying the standard function `CMPLX` to two real literals; for example ``CMPLX(0.0, 1.0)`' --- see The Function CMPLX.

- Whole Number Literals
- Real Literals
- String Literals

#### Whole Number Literals

A whole number literal denotes a constant value of a whole number type. It can be denoted by means of decimal, octal, or hexadecimal notation.

Concrete Syntax

Note: The syntax for whole number literals is given in the Lexis --- see Chapter ???.

The radix of a decimal number shall be ten; the radix of an octal number shall be eight; and the radix of a hexadecimal number shall be sixteen.

No separators shall appear within a whole number literal.

Notes:

1. The additional requirement of no separators must be made since this is not a consequence of the concrete syntax.

2. A whole number literal has a non-negative value. The syntax does not permit a whole number literal that has a negative value. A whole number literal preceded by an arithmetic negation operator is a prefix expression --- see Prefix Expressions. Such an expression has a non-positive value of the Z-type.

Static Semantics

The value denoted by a whole number literal shall be less than or equal to the implementation-defined maximum value for values of the Z-type.

The type of a whole number literal shall be the Z-type.

Notes:

1. There is no identifier that denotes the maximum value for values of the Z-type.

2. This maximum value is at least as large as the maximum value of any whole number type. --- see Ranges of the Predefined Numeric Types.

Dynamic Semantics

The value of a whole number literal shall be the numerical value denoted by the whole number literal.

#### Real Literals

A real literal denotes a constant value of a real number type. It is denoted by means of a decimal notation, using an optional scale factor.

Concrete Syntax

Note: The syntax for real literals is given in the Lexis --- see Chapter ???.

A real literal shall be written in decimal notation with an optional scale factor. The scale factor shall give the power of ten by which the remaining part of the real literal is multiplied to produce the value of the real literal.

No separators shall appear within a real literal.

Notes:

1. The additional requirement of no separators must be made since this is not a consequence of the concrete syntax.

2. A real literal has a non-negative value. The syntax does not permit a real literal that has a negative value. A real literal preceded by an arithmetic negation operator is a prefix expression --- see Prefix Expressions. Such an expression has a non-positive value of the R-type.

3. A real literal always contains a decimal point.

Static Semantics

The value denoted by a real literal shall be less than or equal to the implementation-defined maximum value for values of the R-type.

The type of a real literal shall be the R-type.

Notes:

1. There is no identifier that denotes the maximum value for values of the R-type.

2. This maximum value is at least as large as the maximum value of any real number type. --- see Ranges of the Predefined Numeric Types.

Dynamic Semantics

The value of a real literal shall be an implementation-defined approximation to the numerical value denoted by the real literal.

#### String Literals

There are two forms of string literal, namely quoted strings and character number literals. A quoted string denotes a constant value of the string literal type which is a sequence of zero or more characters. A character number literal denotes a constant value of the string literal type of length one. String literals of length zero or length one are also known as character literals.

Concrete Syntax

Notes:

1. The syntax for string literals is given in the Lexis --- see ???.

2. A string literal is not equivalent to a concrete string constant constructed with an array constructor. For example, values of the string literal type cannot be indexed, concrete string constants cannot be concatenated using the catenation symbol, and the compatibility rules for string literals are more relaxed than those for concrete string constants.

##### Quoted Strings

A quoted string denotes a constant value of the string literal type which is a sequence of zero or more characters.

Concrete Syntax

Note: The syntax for quoted strings is given in the Lexis --- see ???.

Static Semantics

The type of a quoted string shall be the string literal type with length given by the number of quoted characters --- see The String Literal Type.

Dynamic Semantics

The value of a quoted string shall be the string literal value denoted by the characters, if any, between the pair of single quotes or double quotes.

Note: A quoted string containing an empty sequence of characters is called the `empty string literal' and is a denotation both for the empty string and the character that is the string terminator --- see Character Literals.

##### Character Number Literals

A character number literal denotes a constant value of the string literal type of length 1.

Concrete Syntax

Note: The syntax for character number literals is given in the Lexis --- see ???.

Static Semantics

The value of the sequence of octal digits that precede the ``C`' shall be the ordinal number of a value of the character type.

The type of a character number literal shall be the string literal type of length one.

Change: In Programming in Modula-2 a character number literal is of the character type.

Notes:

1. The character type is expression-compatible and assignment-compatible with the string literal type of length one.

2. Concrete string types are assignment-compatible with the string literal type of length one.

Dynamic Semantics

The value of a character number literal shall be the string literal value denoted by the character whose ordinal value is given by the value of the sequence of octal digits that precede the ``C`'.

Note: The ordinal number of a character need not be the same as the internal code used to represent the character --- see The Character Type.

##### Character Literals

In contexts where a value of an ordinal type is required, values of the string literal type of length 0 or length 1 are interpreted as values of the character type.

### Constant Expressions

A constant expression is an expression whose constituents are constants. It can therefore be evaluated by a mere textual scan of the program without having to execute it.

Concrete Syntax

constant expression= expression ;

Abstract Syntax

annotations The abstract syntax for constant-expression is the same as the abstract syntax for expression .

Static Semantics

An infix expression is constant if and only if its two operands are both constant expressions.

Note: The constant expression ``TRUE OR (1/0=1)`' is permitted and has the value true since the right operand is not evaluated.

A prefix expression is constant if and only if its operand is a constant expression.

A constant expression shall not contain a function call, unless the actual parameters of the function call are constant expressions, and the function designator of the function call denotes a standard function, or is one of the functions `CAST, MAKEADR, ROTATE, SHIFT` and `TSIZE` from the module `SYSTEM`.

A constant expression shall not contain a reference to a variable, unless that variable is contained in an actual parameter to the standard function `SIZE`.

A constant expression shall not contain a value constructor, unless the expressions of the value constructor are constant expressions.

The value of a constant expression that is of the Z-type shall be within the range of values defined by the Z-type.

The value of a constant expression that is of the R-type shall be within the range of values defined by the R-type.

Clarification: A constant expression may contain values of procedure types, or structured values whose components are values of procedure types.

annotations The function checks whether an expression is a constant expression. Any constant literal is a constant expression.

annotations Check that both expression components are constant expressions.

annotations Check that the expression component is a constant expression.

annotations Check that the qualified identifier denotes a constant or a proper procedure or a function procedure.

annotations Check that the designator denotes a constant and that the index expression is a constant expression.

annotations Check that the designator denotes a constant.

annotations A dereferenced value cannot be a constant expression.

annotations Check that the function call is to a standard function or a system function that is defined to be a constant function.

annotations Check that the array definition is a constant expression. Check that each of the repeated element components of an array definition is a constant expression. Check that element and repetition factor are constant expressions.

annotations Check that a record constructor is a constant expression by checking that the record definition component is a constant expression. A record definition is a constant expression if each of the elements is a constant expression.

annotations Check that the set definition is a constant expression by checking that each of the members of the set is a constant expression. A singleton member is constant if it is a constant expression, and an interval is constant if each of its component expressions are constant expressions.

- Constant Expression Evaluation

#### Constant Expression Evaluation

annotations As a constant expression can be evaluated with just a textual scan, the evaluation of a constant expression is defined to be the meaning of an expression with an empty state.

## Parameter Compatibility and Argument Binding

If a proper procedure or function procedure is of a structure that has formal parameters, a call of that procedure has a corresponding actual parameter list. The actual parameters and the formal parameters must match. The execution of a proper procedure call or function procedure call involves the evaluation of any actual parameters to give corresponding arguments, the binding of the results of this evaluation to the corresponding formal parameters, and the execution of the actions associated with the procedure designator.

In the case of a declared procedure, the correspondence between actual parameters and formal parameters is established by the positions of the parameters in the lists of actual and formal parameters respectively; the actions are as specified by the block of the procedure declaration.

In the case of a call of a predefined procedure, parameter correspondence, argument binding, and procedure actions are as specified for that predefined procedure.

- Actual Parameters
- Parameter Matching
- Parameter Compatibility
- Argument Binding

### Actual Parameters

Actual parameters of declared procedures are either variable designators (if the corresponding formal parameter is a variable parameter), or expressions (if the corresponding formal parameter is a value parameter). In the case of calls of predefined procedures, there are special cases of actual parameters that are type identifiers.

Concrete Syntax

actual parameters= "(", [ actual parameter list ], ")" ;

actual parameter list= actual parameter, { ",", actual parameter } ;

actual parameter= variable designator | expression | type parameter ;

Static Semantics

An actual parameter shall be a variable designator, an expression, or a type parameter.

annotations Check that each of the actual parameters is well-formed.

Dynamic Semantics

Each of the actual parameters shall be evaluated. The order of evaluation, the order of accessing and the order of binding of the actual parameters shall be implementation-dependent.

annotations The above evaluation order for the the actual parameters is one of those permitted | see 4.1.

- Variable Actual Parameters
- Expression Actual Parameters
- Type Parameters

#### Variable Actual Parameters

Actual parameters are variable designators if the corresponding formal parameter is a variable parameter.

Abstract Syntax

annotations Type information is supplied with argument variables for the effect of binding with system storage formal parameters to be specified and for calls of the predefined procedures `DEC, DISPOSE, EXCL, INC, INCL, NEW, SIZE`, and `SYSTEM.ADR`.

#### Expression Actual Parameters

Actual parameters are expressions if the corresponding formal parameter is a value parameter.

Abstract Syntax

annotations Type information is supplied with argument values for the effect of binding with system storage formal parameters to be specified and for calls of the predefined procedures `ABS, CMPLX, IM, RE, SYSTEM.ROTATE` and `SYSTEM.SHIFT`.

#### Type Parameters

Some predefined function procedures (`MAX, MIN, SIZE` and `VAL`) and the function procedures `SYSTEM.CAST` and `SYSTEM.TSIZE` take a type identifier as an actual parameter.

Concrete Syntax

type parameter= type identifier ;

### Parameter Matching

Calls of a declared procedure must supply actual parameters that match the formal parameters given in the procedure heading of that declared procedure.

The requirements for parameter matching for a call of a predefined proper procedure, a predefined function procedure, or a proper procedure or a function procedure exported from a system module are given separately for each proper procedure and function procedure in Standard Procedures, Standard Functions and in Chapter System Modules.

Static Semantics

The formal parameters of a proper procedure or a function procedure shall match the actual parameters specified in any call of that proper procedure or function procedure. The formal parameters match the actual parameters if and only if the number of formal parameters is equal to the number of actual parameters, and each formal parameter is parameter-compatible with the corresponding actual parameter --- see Parameter Compatibility. This correspondence shall be established by the positions of the parameters in the lists of formal and actual parameters respectively.

annotations Check that the number of formal parameters is equal to the number of actual parameters, and that each of the formal parameters is parameter-compatible with the actual parameter.

### Parameter Compatibility

There are two cases of parameter-compatibility, depending on whether the formal parameter is a value parameter or a variable parameter. There are special rules common to both cases if the formal type is a system storage formal type --- see System Storage Parameter Compatibility.

Static Semantics

A formal parameter shall be parameter-compatible with an actual parameter if either of the following statements is true:

a) The formal parameter is a value parameter, the actual parameter is an expression, and the formal type of the formal parameter is value parameter compatible with the type of the expression.

b) The formal parameter is a variable parameter, the actual parameter is a variable designator, and the formal type of the formal parameter is variable parameter compatible with the type of the expression.

- Value Parameter Compatibility
- Variable Parameter Compatibility
- System Storage Parameter Compatibility

#### Value Parameter Compatibility

Static Semantics

The formal type of a value parameter shall be compatible with the type of an actual expression if any of the following statements is true:

a) The formal type is a system storage formal type, or a one-dimensional open array of a system storage formal type, and is compatible with the actual type as the type of a system storage formal parameter --- see System Storage Parameter Compatibility.

b) The formal type is an open array, the actual type is the string literal type of any length, and the component type of the formal type is the character type.

c) The formal type is an open array (other than a one-dimensional open array of a system storage formal type), the actual type is an array type, and the component type of the formal type is compatible with the component type of the actual type as an open array component type.

d) The formal type is a single identified type that is assignment-compatible with the actual type.

The component type of an open array value parameter shall be compatible with the component type of an actual array if the component types are system storage parameter compatible, are of the identical identified type, or themselves have component types that are compatible in one or other of these ways.

Example: Value parameter compatibility. Given the declaration

        TYPE Colour = (red, yellow, green);

The following formal types are compatible, as the types of value parameters, with the given actual types. Formal types denoted by Actual types denoted by

        CARDINAL 					 INTEGER
        ARRAY OF ARRAY OF ARRAY OF CARDINAL          ARRAY [-7..-2] OF ARRAY BOOLEAN
                                                                    OF ARRAY Colour OF CARDINAL
        ARRAY OF ARRAY OF SYSTEM.LOC                 ARRAY Colour OF REAL
        ADDRESS                                      POINTER TO LONGREAL

Clarification: A formal open array parameter with the component type T is not parameter-compatible with an actual parameter of the type T; e.g. a formal parameter of the open array structure `ARRAY OF CHAR` is not compatible with an actual parameter of the character type. Note, however, that a string literal such as "`!`" is of the string literal type of length 1, with which the character type is assignment-compatible, and can therefore be passed as a parameter in this case.

#### Variable Parameter Compatibility

Static Semantics

The formal type of a variable parameter shall be compatible with the type of an actual variable if any of the following statements is true:

a) The formal type is the address type and the actual type is any pointer type.

b) The formal type is a system storage formal type, or a one-dimensional open array of a system storage formal type, and is compatible with the actual type as the type of a system storage formal parameter --- see System Storage Parameter Compatibility.

c) The formal type is an open array (other than a one-dimensional open array of a system storage formal type), the actual type is an array type, and the component type of the formal type is compatible, as the formal type of a variable parameter, with the component type of the actual type.

d) The formal type is a single identified type that is identical to the actual type.

Example: Variable parameter compatibility. Given the declaration

        TYPE Colour = (red, yellow, green);

The following formal types are compatible, as the types of variable parameters, with the given actual types. Formal types denoted by Actual types denoted by

                                    CARDINAL     CARDINAL                                    ARRAY [-7..-2] OF ARRAY BOOLEAN
        ARRAY OF ARRAY OF ARRAY OF CARDINAL                        OF ARRAY Colour OF CARDINAL
                                                    ARRAY Colour OF REAL
        ARRAY OF ARRAY OF SYSTEM.LOC                POINTER TO LONGREAL
        ADDRESS

#### System Storage Parameter Compatibility

There are special parameter compatibility rules for formal types that are system storage formal types or open arrays of a system storage formal type.

A formal type is a system storage formal type if it is a system storage type or a zero-based array of a system storage type.

The system storage types are the location type `SYSTEM.LOC`, the word type `SYSTEM.WORD`, and the byte type `SYSTEM.BYTE` --- see System Storage Types. Not all implementations are required to provide the byte type --- see ???.

Static Semantics

A formal type shall be system storage parameter compatible with the type of an actual parameter, other than a numeric literal, if any of the following statements is true:

a) The formal type `F` is a system storage formal type, and the actual parameter is of any data type `T` such that `SIZE(T)` is equal to `SIZE(F)`.

b) The formal type is a one-dimensional open array of a system storage formal type `F`, and the actual parameter is of any data type `T` such that `SIZE(T)` is a multiple of `SIZE(F)`.

Clarification: A system storage formal type is not system storage parameter compatible with numeric literal types since such types do not have a defined storage size.

Change: In Programming in Modula-2 , a zero-based array of a system storage type is not treated as a system storage formal type. This case has been added for consistency with the definition of `SYSTEM.WORD` which has the structure `ARRAY [0..SYSTEM.LOCSPERWORD] OF SYSTEM.LOC`.

Note: It follows from the specification of value parameter compatibility and variable parameter compatibility that a formal parameter that is an n dimensional open array of a system-storage formal type, where n > 1, is parameter compatible with an actual parameter that is an n - 1 dimensional array of any component type. The upper bounds of the first n - 1 dimensions of the formal variable is determined by the index types of the first n - 1 dimensions of the actual parameter; the upper bound of the remaining dimension is determined by rule ???.

Auxiliaries

annotations The formal type is a system storage formal type, or is an open array whose components are a system storage formal type.

annotations A system storage formal type is either a storage type exported from the module `SYSTEM`, or an array whose index type is a whole number type with a lower bound of zero, and whose component type is a storage type exported from the module `SYSTEM`.

### Argument Binding

On a call of a declared procedure, the arguments resulting from the evaluation of the actual parameters are bound to the formal parameters given in the procedure heading of that declared procedure. The form of this binding is different for value formal parameters and for variable formal parameters, and takes account of both open array formal parameters and formal parameters constucted from system storage types.

The binding of arguments for a call of a predefined proper procedure, a predefined function procedure, or a proper procedure or a function procedure exported from a system module is given explicitly for each proper procedure and function procedure in Standard Procedures, Standard Functions and in Chapter System Modules.

Dynamic Semantics

The arguments arising from the evaluation of each actual parameter shall be bound to the corresponding formal parameter. This correspondence shall be established by the positions of the parameters in the lists of actual and formal parameters respectively.

The order of evaluation, the order of accessing and the order of binding of the actual parameters shall be implementation-dependent.

Notes:

1. The binding of the arguments might involve storage allocation and so might lead to the raising of a workspace overflow exception.

2. The binding of the arguments involves the assignment of the arguments to storage allocated for value parameters and so might lead to the raising of a range exception.

3. Exceptions raised during argument binding will be handled by any exception handler that is currently selected for the caller of the procedure for which the arguments are being bound.

4. Since the evaluation of the actual parameters may have side-effects, and the order of evaluation, the order of accessing and the order of binding of the actual parameters is implementation-dependent, this International Standard gives no meaning to a program that relies upon a definition of which actual parameters have been evaluated if an exception is raised during the binding of the arguments.

5. A workspace overflow exception resulting from the elaboration of the declarations of the called procedure will also be handled by any exception handler that is currently selected for the caller of the procedure --- see Block Bodies and Exception Handling.

annotations The argument is bound to the parameter according to whether the formal parameter is a value parameter or a variable parameter.

- Argument Binding to Value Parameters
- Argument Binding to Variable Parameters

#### Argument Binding to Value Parameters

If the formal parameter is a value parameter, and the formal type is not a system storage formal type or an open array of a system storage formal type (see System Storage Types and System Storage Parameter Compatibility), then, on a call of the procedure, the corresponding argument shall be assigned to a formal variable allocated for the call. During the execution of the procedure block, the formal parameter identifier shall designate the formal variable. The structure of the formal variable shall be determined by the formal type of the formal parameter, and by the structure of the actual value given in the corresponding argument of the call.

Note: Since a formal parameter identifier of a value parameter designates a formal variable that is allocated for the call, the formal variable is a local variable of the block that is additional to any local variables declared in the procedure block.

If a formal type is an open array formal type, then the formal variable shall be an array variable; the index type of the formal variable shall have the structure of a subrange type whose lower bound is 0 and whose upper bound is one less than the number of components of the corresponding actual value. The component type of the formal variable shall be determined recursively by the open array component type of the formal type, and by the structure of components of the corresponding actual value.

Note: The upper bound of the index type may be ascertained using the predefined function procedure HIGH --- see The Function HIGH.

If a formal type is a single identified type, the allocated variable shall be a single variable of that identified type; storage shall be allocated for the variable and the corresponding argument value shall be assigned to the allocated variable.

Example: Binding of an open array value parameter. Given:

        TYPE colour = (red, yellow, green);

        VAR a: ARRAY [-7..-2] OF ARRAY BOOLEAN
       			  OF ARRAY colour OF CARDINAL;

        PROCEDURE
          p(f: ARRAY OF ARRAY OF ARRAY OF CARDINAL);

then, during activation by `p(a)', within the body of p the structure of f will correspond to the local declaration

        VAR f: ARRAY [0..5] OF ARRAY [0..1]
       			OF ARRAY [0..2] OF CARDINAL;

and the initial value of the variable designated by

        f[0][0][0] will be the value of a[-7][false][red].

System storage formal types

If the formal parameter is a value parameter, and the formal type is a system storage formal type, or an open array of a system storage formal type, the effect shall be for the value of the argument to be cast to a target type constructed from one or more storage locations, and for the the formal parameter to be bound to the resulting value. The target type shall be determined as follows:

a) If the formal type is a system storage formal type, the target type shall be that system storage formal type.

b) If the formal type is an open array of a system storage formal type `F`, and the actual parameter is of a data type `T`, the target type shall be of the structure `ARRAY [0..n-1] OF F` where `n = SIZE(T)/SIZE(F)`.

Note: A formal type is a system storage formal type if it is a system storage type or a zero-based array of a system storage type.

#### Argument Binding to Variable Parameters

If the formal parameter is a variable parameter, and the formal type is not a system storage formal type or an open array of a system storage formal type (see System Storage Types and System Storage Parameter Compatibility), then, during the execution of the procedure block, the formal parameter identifier shall designate a formal variable that is the actual variable given in the corresponding argument of the call.

Note: Since a formal parameter identifier of a variable parameter designates the actual variable given in the corre- sponding argument of the call, the formal parameter identifier of a variable parameter stands as an alias for the actual variable during execution of the procedure body; however, the scope of the declared identifier for the actual variable does not necessarily include that procedure body.

If a formal type is an open array formal type, the index type of the formal variable shall have the structure of a subrange type whose lower bound is 0 and whose upper bound is one less than the number of components of the corresponding actual variable. The component type of the formal variable shall be determined recursively by the open array component type of the formal type, and by the structure of components of the corresponding actual variable.

Note: The upper bound of the index type may be ascertained using the predefined function procedure HIGH --- see The Function HIGH.

Example: Binding of an open array variable parameter. Given:

        TYPE colour = (red, yellow, green);

        VAR a: ARRAY [-7..-2] OF ARRAY BOOLEAN
      			  OF ARRAY colour OF INTEGER;

        PROCEDURE
          p(VAR f: ARRAY OF ARRAY OF ARRAY OF INTEGER);

then, during activation by ``p(a)`', within the body of `p` the identifier `f` will be an alias for `a`, the structure of `f` will correspond to the declaration

        VAR f: ARRAY [0..5] OF ARRAY [0..1]
      			OF ARRAY [0..2] OF INTEGER;

and the variable designated by `f[0][0][0]` will be vari- able designated by a `[-7][false][red]`.

System storage formal types

If the formal parameter is a variable parameter, and the formal type is a system storage formal type `F`, the effect shall be for the storage for the actual variable to appear as uninterpreted storage locations when accessed through the formal variable which will have the same structure as the structure of `F`.

If the formal parameter is a variable parameter, and the formal type is an open array of a system storage formal type `F`, the effect shall be for the storage for the actual variable of type `T` to appear as an array of uninterpreted storage locations when accessed through the formal variable which will have the structure `ARRAY [0..n-1] OF F` where `n = SIZE(T)/SIZE(F)`.

annotations If the formal parameter is a system storage parameter, the actual variable is aliased to storage that consists of one or more storage locations and gives an alternative representation to the value(s) found in the actual variable; the identifier of the formal parameter is bound to this variable. If the formal parameter is not a sytem storage parameter, the identifier of the formal parameter is bound to the actual variable.

Auxiliaries

annotations Allocate storage for the structure of the formal variable and initialize it to the value of the actual variable.

## Predefined Types, Standard Procedures and Standard Functions

The language provides some predefined entities; these include predefined constants, elementary types, proper proce- dures and function procedures. Besides the entities described in this clause, there are other predefined entities that are denoted by identifiers exported from system modules --- see Chapter System Modules.

- Predefined Types
- Standard Procedures
- Standard Functions

### Predefined Types

There are 16 required types other than those with identifiers exported from system modules: three whole number types, three real number types, three complex number types, the Boolean type, the character type, the string literal type, the nil type, the bitset type, the proc type, and the protection type.

The predefined types are all elementary types. The bitset type is a predefined packedset type and the proc type is a predefined procedure type, whereas the number, Boolean, character, string literal, and nil types constitute the basic types of the language.

The protection type is an implementation-defined type and may either be a basic type or a predefined constructed type, as appropriate to the underlying interrupt structure of the implementation.

The number types include types for numeric literals. The string literal type includes the character literal type as a special case. No corresponding type identifiers are provided for the literal types or for the nil type and so it is not possible to declare variables of these anonymous types; they can only appear as the value of an expression.

Of the basic types, the whole number types, the Boolean type, and the character type are ordinal types. These basic ordinal types, together with the real number types, constitute the basic scalar types. The character literal type is interpreted as a value of the character type in situations where a value of an ordinal type is expected.

- Predefined Whole Number Types
- Predfined Real Number Types
- Predefined Complex Number Types
- The Boolean Type
- The Character Type
- Values of the Basic Types
- The String Literal Type
- The Nil Type
- The Bitset Type
- The Proc Type
- The Protection Type

#### Predefined Whole Number Types

Three predefined types are whole number types: the unsigned type, the signed type and the Z-type. The unsigned type can be used to represent non-negative whole numbers, and the signed type can be used to represent whole numbers that are possibly less than zero. The Z-type is the type of a whole number literal value, and of any expression all of whose factors are whole number constants.

Declaration Semantics

The unsigned type shall be a whole number type that is denoted by the pervasive type identifier `CARDINAL`. A value of the unsigned type shall be an element of an implementation-defined finite subset of the non-negative whole numbers --- see Values of the Basic Types.

The ordinal number of a value of the unsigned type shall be the value itself.

Notes:

1. If x is a value of the unsigned type, then x satisfies the condition:

   x

2. When choosing the range of the unsigned type, an implementor should consider the need to represent results returned by calls of the predefined functions `HIGH` and `SIZE`.

The signed type shall be a whole number type that is denoted by the pervasive type identifier `INTEGER`. A value of the signed type shall be an element of an implementation-defined finite subset of the whole numbers --- see Values of the Basic Types.

The ordinal number of a non-negative value of the signed type shall be the value itself.

Notes:

1. If x is a value of the signed type, then x satisfies the condition:

   x

2. There are no ordinal numbers associated with values of the signed type that are less than zero.

The Z-type shall be a whole number type that is the type of constant expressions all of whose factors are whole number constants. A value of the Z-type shall be an element of an implementation-defined finite subset of the whole numbers. --- see Values of the Basic Types.

Notes:

1. There is no pervasive type identifier that denotes the Z-type.

2. A whole number literal can be used to denote a value of the Z-type --- see Whole Number Literals.

3. If x is a value of the Z-type, then x satisfies the condition:

   min-zz-value ??? x ??? max-zz-value

4. All numeric subrange types have a host type that is either the signed type or the unsigned type; it is not possible to construct a numeric type by using values of the Z-type for the lower and upper bounds of a subrange type that are not both within the range of either the signed type or the unsigned type --- see Subrange Types.

#### Predfined Real Number Types

Three predefined types are real number types: the real type, the long real type and the R-type. Both the real type and the long real type can be used to represent real numbers. These types may differ with respect to the range and the precision with which real numbers are represented. The R-type is the type of a real number literal value, and of any expression all of whose factors are real constants.

Declaration Semantics

The real type shall be a real number type that is denoted by the pervasive type identifier `REAL`. A value of the real type shall be an element of an implementation-defined finite subset of the real numbers --- see Values of the Basic Types.

Note: If x is a value of the real type, then x satisfies the condition:

`MIN(REAL)`

The long real type shall be a real number type that is denoted by the pervasive type identifier `LONGREAL`. A value of the long real type shall be an element of an implementation-defined finite subset of the real numbers --- see Values of the Basic Types.

Note: If x is a value of the long real type, then x satisfies the condition:

`MIN(LONGREAL)`

The R-type shall be a real number type that is the type of constant expressions all of whose factors are real constants. A value of the R-type shall be an element of an implementation-defined finite subset of the real numbers --- see Values of the Basic Types.

Notes:

1. There is no pervasive type identifier that denotes the R-type.

2. A real literal can be used to denote a value of the R-type --- see Real Literals.

3. If x is a value of the R-type, then x satisfies the condition:

   min-rr-value

The precision with which real number values are represented shall not decrease from the real type to the long real type, or from the long real type to the R-type.

#### Predefined Complex Number Types

Three predefined types are complex number types: the complex type, the long complex type and the C -type. Both the complex type and the long complex type can be used to represent complex numbers. These types may differ with respect to the range and the precision with which complex numbers are represented. The C -type is the type of a complex number literal value, and of any expression all of whose factors are complex constants.

Change: The complex number types are not described in Programming in Modula-2 .

Declaration Semantics

The complex type shall be a complex number type that is denoted by the pervasive type identifier `COMPLEX`. A value of the complex type shall be an element of an implementation-defined finite subset of the complex numbers --- see Values of the Basic Types.

Note: If z is a value of the complex type, then z satisfies the condition:

`MIN(REAL)`

The long complex type shall be a complex number type that is denoted by the pervasive type identifier `LONGCOMPLEX` . A value of the long complex type shall be an element of an implementation-defined finite subset of the complex numbers --- see Values of the Basic Types.

Note: If z is a value of the long complex type, then z satisfies the condition:

`MIN(LONGREAL)`

The C -type shall be a complex number type that is the type of constant expressions all of whose factors are complex constants. A value of the C -type shall be an element of an implementation-defined finite subset of the complex numbers --- see Values of the Basic Types.

Notes:

1. There is no pervasive type identifier that denotes the C -type.
2. Although there is no denotation for a complex literal, a value of the C -type can be formed by applying the pervasive standard function `CMPLX` to two real literals; for example ``CMPLX(0.0, 1.0)`' --- see The Function CMPLX.

3. If z is a value of the C -type, then z satisfies the condition:

   min-rr-value

The precision with which complex number values are represented shall not decrease from the complex type to the long complex type, or from the long complex type to the C -type.

#### The Boolean Type

The Boolean type can be used to represent truth values.

Declaration Semantics

The Boolean type shall be an ordinal type that is denoted by the pervasive type identifier `BOOLEAN`. A value of the Boolean type shall be one of the logical truth values false or true . The values false and true shall be denoted by the pervasive constant identifiers `FALSE` and `TRUE` respectively .

The ordinal numbers of the values false and true shall be the values 0 and 1 respectively.

#### The Character Type

The character type can be used to represent single characters.

Declaration Semantics

The character type shall be an ordinal type that is denoted by the pervasive type identifier `CHAR`. A value of the character type shall be an element of a finite set of characters. This set shall contain unique values representing the minus character, the period character, the plus character, the space character, the string terminator, the lower-case letters, the upper-case letters, and the digits. Any other values of this set of characters shall be implementation-defined.

Change: There is no requirement that the value of the string terminator be the same as the value denoted by the character number literal ``0C`', as is specified in Programming in Modula-2 .

Notes:

1. If c is a value of the character type, then c satisfies the condition:

   c

2. A value of the character type may represent a character that does not have a graphic representation.

3. The character type is assignment-compatible and expression-compatible with the character literal type, which is the string literal type of length 1 or of length 0 --- see Character Literals.

4. The string terminator character can be denoted by either of the character literals ``''`' or ``""`'. Both literals represent the same value of the string literal type.

Domains

annotations The type Char is used to model the character type.

The ordinal numbers of the character values shall be implementation-defined values of the unsigned type that satisfy the conditions:

- the ordinal number of each character in the set of characters shall be different from the ordinal number of any other character in the set;

- the ordinal number associated with the (i + 1)th lower-case letter shall be greater than that associated with the i th lower-case letter;

- the ordinal number associated with the (i + 1)th upper-case letter shall be greater than that associated with the i th upper-case letter;

- the ordinal number associated with the (i + 1)th decimal digit shall be one more than that associated with the ith decimal digit.

annotations The collation map associated with the type Char maps from values of the character type to the ordinal numbers of those values.

Notes:

1. The ordering relationship between any two character values is the same as that between their ordinal numbers --- see Scalar Relational Operations. Thus if `x` and `y` are any two character values, then:

   `x` < `y`

2. The ordinal number of a character need not be the same as the internal code used to represent the character. For example, if `ch` is a variable of type `CHAR`, whose current value is `5C`, then, although ``VAL(CARDINAL,ch)`' has the value 5, this need not be the value of ``SYSTEM.CAST(CARDINAL,ch)`'.

#### Values of the Basic Types

##### Ranges of the Basic Types

annotations Return the largest value of a basic scalar type.

annotations Return the smallest value of a basic scalar type.

annotations Return the set of values associated with a basic ordinal type.

##### Ranges of the Predefined Numeric Types

The implementation-defined values specifying the ranges of the predefined numeric types shall have the following properties.

#### The String Literal Type

The string literal type is the type of string literals, of string literal constants, and of the result of string literal catenation.

The string literal type has an associated length. If the length associated with the string literal type is zero or one, the type is also known as the character literal type.

Declaration Semantics

The string literal type shall be an elementary type that is the type of constant expressions all of whose factors are string literals or string literal constants.

A value of the string literal type shall be a sequence of zero or more characters. The string literal type shall have an associated length equal to the number of characters in a value of that type.

Notes:

1. The only operation allowed in string literal expressions is catenation --- see String Literal Infix Operations.

2. There is no pervasive type identifier that denotes the string literal type.

3. A quoted string can be used to denote a value of the string literal type of length zero or more --- see Quoted Strings.

4. A character number literal can be used to denote a value of the string literal type of length one that has a particular ordinal number --- see Character Number Literals.

5. A concrete string type of capacity n , which is an array type with n components of the character type, is assignment- compatible with the string literal type of length l provided l

6. An open array of the character type is value parameter compatible with the string literal type --- see Value Parameter Compatibility.

7. If the length associated with the string literal type is zero or one, the type is also known as the character literal type.

8. Values of the character literal type are interpreted as values of the character type in contexts where a value of an ordinal type is required --- see Character Literals.

9. The character type is expression-compatible and assignment-compatible with the character literal type --- see Expression Compatibility and Assignment Compatibility.

10. An implementation may choose different representations for the elements of a string literal and the values of the character type.

#### The Nil Type

The nil type is the type of the nil value.

Declaration Semantics

The nil type shall be the type of the nil value.

The nil value shall be denoted by the pervasive constant identifier `NIL`.

Note: All pointer types are assignment-compatible and expression-compatible with the nil type.

#### The Bitset Type

The bitset type is a packedset type whose base type is a subrange from zero to one less than the number of bits in a machine word of the underlying computer system. The bitset type may therefore be used to represent small sets in an efficient manner, or to manipulate the bits in a machine word --- see Packedset Types and Packedset mapping.

Declaration Semantics

The bitset type shall be a packedset type that is denoted by the pervasive type identifier `BITSET`. The base type of the bitset type shall be a subrange of the unsigned type. The lower bound of this base type shall be the value 0, and the upper bound shall be the value denoted by the constant expression `SYSTEM.BITSPERLOC*SYSTEM.LOCSPERWORD-1`.

Note: Although there is no denotation for a literal of the bitset type, a value of the bitset type can be formed by using a set constructor; for example ``BITSET{1, 4..6, 9}`' --- see Set Constructors.

#### The Proc Type

The proc type is a procedure type that can be used to represent the type of parameterless proper procedures that are declared at level 0.

Declaration Semantics

The proc type shall be a proper procedure type that is denoted by the pervasive type identifier `PROC`. A value of the proc type shall denote a parameterless proper procedure that has been declared at level 0.

Note: The proc type is effectively defined by the implicit declaration:

`TYPE` `PROC = PROCEDURE;`

#### The Protection Type

The protection type can be used to represent an extent of protection from interrupts.

Change: The treatment of protection differs from that described (as ") in Programming in Modula-2 , which was modelled on the PDP-11 interrupt structure.

Declaration Semantics

The protection type shall be an implementation-defined elementary type that is denoted by the pervasive type identifier `PROTECTION`. A value of the protection type shall be one of an implementation-defined set of values that shall include the values interruptible and uninterruptible; these values shall be denoted by the pervasive constant identifiers `INTERRUPTIBLE` and `UNINTERRUPTIBLE` respectively.

Notes:

1. An implementation may define the protection type as a basic type, distinct from the other basic types of the language, as identical to another basic type, or as a predefined constructed type, as appropriate to the interrupt structure of the underlying system.

2. It is likely that the interrupt structure of the system underlying an implementation will be richer than the two protection values defined here. An implementation may reflect this richer structure by defining the protection type so that it includes other appropriate values. The underlying interrupt structure might be totally or partially ordered: an ordinal type or a set type would then result for the protection type. The protection relational operators (see Protection Relational Operations) are those that are common both to ordinal types and to set types. If the protection type is defined to be identical to a basic ordinal type, or is defined as a constructed ordinal type, other corresponding operations will be applicable to protection values.

3. If `P` is a value of the protection type, then `P` satisfies the condition:

   `INTERRUPTIBLE <= P AND P <= UNINTERRUPTIBLE`

   --- see Protection Relational Operations.

4. A value P1 of the protection type is less restrictive than another value P2 if and only if P1 does not prevent all the interrupts prevented by P2, but P2 prevents all the interrupts prevented by P1 --- see Protection Relational Operations.

### Standard Procedures

The standard procedures are denoted by the pervasive identifiers `DEC, DISPOSE, EXCL, HALT, INC, INCL` and `NEW`.

- The Procedure DEC
- The Procedure DISPOSE
- The Procedure EXCL
- The Procedure HALT
- The Procedure INC
- The Procedure INCL
- The Procedure NEW

#### The Procedure DEC

The procedure `DEC` can be used to decrement the value of a variable that is of an ordinal type.

Static Semantics

A call of `DEC` shall have one or two actual parameters. The first parameter shall be a variable that is of an ordinal type. If there is a second parameter, it shall be an expression that is of a whole number type.

If the second parameter is of the Z-type, its value shall be subject to a constraint that depends on the type of the first parameter: if the first parameter is of the signed type (or is of a subrange type whose host type is the signed type), the value of the second parameter shall be less than or equal to the maximum value of the signed type; otherwise it shall be greater than or equal to zero.

Note: These constraints are present because signed arithmetic will be used if the first parameter is of the signed type, and unsigned arithmetic will be used in all other cases.

Clarification: In Programming in Modula-2 the types of the parameters of `DEC` are not specified.

Dynamic Semantics

The call `DEC(x)` shall assign to the variable `x` the predecessor of its current value. An exception shall be raised if the predecessor lies outside the range of the type of `x`, or if there is no predecessor.

The call `DEC(x,N)` shall assign to the variable `x` the Nif the N

Auxiliaries

annotations Check whether the first parameter of a call of `DEC` or `INC` is valid.

annotations Check whether the two parameters of a call of `DEC` or `INC` are valid. This includes checking that the second parameter is within range when it is of the Z-type.

#### The Procedure DISPOSE

The procedure `DISPOSE` can often be used to release an area of dynamically allocated storage that was earlier claimed by a call to the procedure `NEW`.

Note: The word often appears because there is no requirement that the procedure `DEALLOCATE` that is associated with `DISPOSE` necessarily be the procedure `Storage.DEALLOCATE`, or a procedure that performs a similar task.

Static Semantics

A call of `DISPOSE` shall have one or more actual parameters. The first parameter shall be a variable that is of a pointer type.

If the second and subsequent parameters are present, they shall be constant expressions, and the bound type of the first parameter shall be a record type.

The identifier `DEALLOCATE` shall be visible at the point of the call of `DISPOSE` and shall designate a procedure, procedure constant, or procedure variable with the structure of a proper procedure that has two formal parameters. The first formal parameter of this proper procedure structure shall be a variable parameter that is of the address type, and the second formal parameter shall be a value parameter that is of the unsigned type.

Note: The separate module Storage exports a procedure called `DEALLOCATE` of the correct structure for a call of `DISPOSE`. The requirement that the identifier `DEALLOCATE` is visible at the point of the call of `DISPOSE` is often satisfied by including the import list:

`FROM Storage IMPORT DEALLOCATE;`

in the module containing the call of `DISPOSE`.

Dynamic Semantics

The call `DISPOSE(P)` shall have the same effect as the call `DEALLOCATE(P,SIZE(B))`, where the variable `P` is of a pointer type `T`, and `B` is the bound type given in the declaration of `T`.

The call `DISPOSE(P,` < expression-list >`)` shall have the same effect as the call

`DEALLOCATE(P,SYSTEM.TSIZE(B,` < expression-list >`))`,

where the variable `P` is of a pointer type `T`, and `B` is the bound type given in the declaration of `T`.

#### The Procedure EXCL

The procedure `EXCL` can be used to remove an element from a variable that is of a set type or a packedset type.

Static Semantics

A call of `EXCL` shall have two actual parameters. The first parameter shall be a variable that is of a set type or a packedset type, and the second parameter shall be an expression with which the the host type of the base type of the set type or packedset type is assignment-compatible.

Dynamic Semantics

The call `EXCL(s,x)` shall assign to the set variable `s` the value that is obtained by removing the value of `x` from the current value of `s`. An exception shall be raised if the value of `x` is not a value of the base type of `s`.

#### The Procedure HALT

The procedure `HALT` can be used to terminate the execution of a program at a point other than the end of the program block.

Static Semantics

A call of `HALT` shall have no actual parameters.

Dynamic Semantics

The call `HALT` shall be a program termination event --- see Program Termination

#### The Procedure INC

The procedure `INC` can be used to increment the value of a variable that is of an ordinal type.

Static Semantics

A call of `INC` shall have one or two actual parameters. The first parameter shall be a variable that is of an ordinal type. If there is a second parameter, it shall be an expression that is of a whole number type.

If the second parameter is of the Z-type, its value shall be subject to a constraint that depends on the type of the first parameter: if the first parameter is of the signed type (or is of a subrange type whose host type is the signed type), the value of the second parameter shall be less than or equal to the maximum value of the signed type; otherwise it shall be greater than or equal to zero.

Note: These constraints are present because signed arithmetic will be used if the first parameter is of the signed type, and unsigned arithmetic will be used in all other cases.

Clarification: In Programming in Modula-2 the types of the parameters of `INC` are not specified.

Dynamic Semantics

The call `INC(x)` shall assign to the variable `x` the successor of its current value. An exception shall be raised if the successor lies outside the range of the type of `x`, or if there is no successor.

The call `INC(x,N)` shall assign to the variable `x` the Nthe N

#### The Procedure INCL

The procedure `INCL` can be used to add an element to a variable that is of a set type or a packedset type.

Static Semantics

A call of `INCL` shall have two actual parameters. The first parameter shall be a variable that is of a set type or a packedset type, and the second parameter shall be an expression with which the the host type of the base type of the set type or packedset type is assignment-compatible.

Dynamic Semantics

The call `INCL(s,x)` shall assign to the set variable `s` the value that is obtained by including the value of `x` in the current value of `s`. An exception shall be raised if the value of `x` is not a value of the base type of `s`.

#### The Procedure NEW

The procedure `NEW` can often be used to obtain an area of dynamically allocated storage that is to be bound to a variable that is of a pointer type.

Note: The word often appears because there is no requirement that the procedure `ALLOCATE` that is associated with `NEW` necessarily be the procedure `Storage.ALLOCATE`, or a procedure that performs a similar task.

Static Semantics

A call of `NEW` shall have one or more actual parameters. The first parameter shall be a variable that is of a pointer type.

If the second and subsequent parameters are present, they shall be constant expressions and the bound type of the first parameter shall be a record type.

The identifier `ALLOCATE` shall be visible at the point of the call of `NEW` and shall designate a procedure, procedure constant, or procedure variable with the structure of a proper procedure that has two formal parameters. The first formal parameter of this proper procedure structure shall be a variable parameter that is of the address type, and the second formal parameter shall be a value parameter that is of the unsigned type.

Note: The separate module `Storage` exports a procedure called `ALLOCATE` of the correct structure for a call of `NEW`. The requirement that the identifier `ALLOCATE` is visible at the point of the call of `NEW` is often satisfied by including the import list:

`FROM Storage IMPORT ALLOCATE;`

in the module containing the call of `NEW`.

Dynamic Semantics

The call `NEW(P)` shall have the same effect as the call `ALLOCATE(P,SIZE(B))`, where the variable `P` is of a pointer type `T`, and `B` is the bound type given in the declaration of `T`.

The call `NEW(P,` < expression-list >`)` shall have the same effect as the call

`ALLOCATE(P,SYSTEM.TSIZE(B,` < expression-list >`))`,

where the variable `P` is of a pointer type `T`, and `B` is the bound type given in the declaration of `T`.

### Standard Functions

The standard functions are denoted by the pervasive identifiers `ABS`, `CAP`, `CHR`, `CMPLX`, `FLOAT`, `HIGH`, `IM`, `INT`, `LENGTH`, `LFLOAT`, `MAX`, `MIN`, `ODD`, `ORD`, `RE`, `SIZE`, `TRUNC` and `VAL`.

Change: The functions `CMPLX`, `IM`, `INT`, `LENGTH`, `LFLOAT` and `RE`are not described in Programming in Modula-2.

- Standard Function Designators
- The Function ABS
- The Function CAP
- The Function CHR
- The Function CMPLX
- The Function FLOAT
- The Function HIGH
- The Function IM
- The Function INT
- The Function LENGTH
- The Function LFLOAT
- The Function MAX
- The Function MIN
- The Function ODD
- The Function ORD
- The Function RE
- The Function SIZE
- The Function TRUNC
- The Function VAL
- Auxiliary Definitions

#### Standard Function Designators

#### The Function ABS

The function `ABS` can be used to obtain the absolute value of a value of a real number type or a whole number type.

Static Semantics

A call of `ABS` shall have one actual parameter, which shall be an expression that is of a real number type or a whole number type, except that the expression shall not be of the unsigned type.

The type of a call of `ABS` shall be the same type as the expression.

Clarification: In Programming in Modula-2 the type of the parameter of `ABS` is not specified.

Note: An expression that is a value designator that is of a subrange type is regarded as being of the host type of the subrange type. A call of `ABS` applied to such an expression returns a value of the host type.

Dynamic Semantics

The value of the `call ABS(x)` shall be the absolute value of `x`. An exception shall be raised if this value lies outside the range of the type of `x`.

Note: An exception occurs if the value of `x` is less than zero and the corresponding positive value does not belong to the type of `x` --- this can only occur if this type has a non-symmetric range.

#### The Function CAP

The function `CAP` can be used to obtain the upper-case equivalent of a lower-case character for those characters that have such equivalents.

Static Semantics

A call of `CAP` shall have one actual parameter, which shall be an expression that is of the character type.

The type of a call of `CAP` shall be the character type.

Dynamic Semantics

If the value of `c` is a lower-case letter, the value of the call `CAP(c)` shall be the implementation-defined upper-case letter corresponding to the value of `c`; otherwise it shall be the value of `c`.

Clarification: In Programming in Modula-2 the behaviour of `CAP` is only specified when the parameter is a letter. However, some examples in Programming in Modula-2 assume that `CAP` is defined for all values of the character type. This International Standard defines `CAP` for all values of the character type.

Auxiliaries

annotations Defining capitalizations in this way avoids a dependency on the collating sequence of the character values. implementation-capitalizations is a means by which implementations may have extra capitalization rules (e.g.

#### The Function CHR

The function `CHR` can be used to obtain the value of the character type that has a specified ordinal number.

Static Semantics

A call of `CHR` shall have one actual parameter, which shall be an expression that is of a whole number type.

The type of a call of `CHR` shall be the character type.

Dynamic Semantics

The value of the call `CHR(x)` shall be the same as the value of the call `VAL(CHAR,x)` (see The Function VAL).

Note: An exception occurs if the value of `x` is less than zero, or if it lies outside the range of the ordinal numbers of the character type.

#### The Function CMPLX

The function `CMPLX` can be used to obtain a value of a complex number type from a pair of expressions specifying its real and imaginary parts.

Static Semantics

A call of `CMPLX` shall have two actual parameters. Each parameter shall be an expression, which shall be of a real number type.

If both expressions are of the real type, or if one is of the real type and the other is of the R-type, the type of a call of `CMPLX` shall be the complex type. If both expressions are of the long real type, or if one is of the long real type and the other is of the R-type, the type of the call shall be the long complex type. If both expressions are of the R-type, the type of the call shall be the C -type.

Note: The following table gives the permitted types and the type of the call.

| real type | long real type | R-type
real type | complex type | error | complex type
long real type | error | long complex type | long complex type
R-type | complex type | long complex type | C -type

Dynamic Semantics

The value of the call `CMPLX(x,y)` shall be an implementation-defined approximation to the complex number whose real part is the value of `x` and whose imaginary part is the value of `y`.

Note: An exception occurs if this approximation lies outside the range of the type of the call.

#### The Function FLOAT

The function `FLOAT` can be used to obtain a value of the real type from a value of a real number type or a whole number type.

Static Semantics

A call of `FLOAT` shall have one actual parameter, which shall be an expression that is of a real number type or a whole number type.

The type of a call of `FLOAT` shall be the real type.

Dynamic Semantics

The value of the call `FLOAT(x)` shall be the same as the value of the call `VAL(REAL,x)` (see The Function VAL).

Note: An exception occurs if the value of `x` lies outside the range of the real type.

#### The Function HIGH

The function `HIGH` can be used to obtain the upper bound of the index type of a one-dimensional open array formal parameter, or the upper bound of an index type of a multi-dimensional open array formal parameter.

Change: Multi-dimensional open array parameters are not described in Programming in Modula-2 .

Clarification: This International Standard permits `HIGH` to be applied only to an open array parameter; it does not permit `HIGH` to be applied to an ordinary array variable.

Static Semantics

A call of `HIGH` shall have one actual parameter, which shall be a designator of a variable that is of an open array formal type.

Note: A variable that is of an open array formal type is either an open array formal parameter or a component of an open array formal parameter that has an open array component type.

The type of a call of `HIGH` shall be the unsigned type.

Dynamic Semantics

The value of the call `HIGH(x)` shall be the upper bound of the index type of an array type that has the same number of components of the same component type as `x`, but has an index type declared as a subrange of the unsigned type with a lower bound of zero.

An exception shall be raised if the value to be returned lies outside the range of the unsigned type.

Example: Result of `HIGH`. Given:

        TYPE colour = (red, yellow, green);

        VAR a: ARRAY [-7..-2] OF ARRAY BOOLEAN
       			  OF ARRAY colour OF REAL;

        PROCEDURE p (f: ARRAY OF ARRAY OF ARRAY OF REAL);

then, for a call of `HIGH` from within the body of `p` that was activated by ``p(a)`'

expression | result
`HIGH(f)` | `5`
`HIGH(f[0])` | `1`
`HIGH(f[0,0])` | `2`
`HIGH(f[0,0,0])` | error

#### The Function IM

The function `IM` can be used to obtain the imaginary part of a value of a complex number type.

Static Semantics

A call of `IM` shall have one actual parameter, which shall be an expression that is of a complex number type.

If the expression is of the complex type, the type of a call of `IM` shall be the real type; if the expression is of the long complex type, the type of the call shall be the long real type; otherwise the expression shall be of the C -type, and the type of the call shall be the R-type.

Dynamic Semantics

The value of the call `IM(z)` shall be an implementation-defined approximation to the imaginary part of `z`.

#### The Function INT

The function `INT` can be used to obtain a value of the signed type from a value of an ordinal type or a real number type.

Static Semantics

A call of `INT` shall have one actual parameter, which shall be an expression that is of an ordinal type or a real number type.

The type of a call of `INT` shall be the signed type.

Dynamic Semantics

The value of the call INT(x) shall be the same as the value of the call VAL(INTEGER,x) (see The Function VAL).

Note: An exception occurs if the value to be returned lies outside the range of the signed type.

#### The Function LENGTH

The function `LENGTH` can be used to obtain the length of a string value.

Static Semantics

A call of `LENGTH` shall have one actual parameter, which shall be an expression that is of a string literal type or is an array that contains a string value.

The type of a call of `LENGTH` shall be the unsigned type.

Dynamic Semantics

The value of the call `LENGTH(s)` shall be the number of characters in the string value `s`.

#### The Function LFLOAT

The function `LFLOAT` can be used to obtain a value of the long real type from a value of a real number type or a whole number type.

Static Semantics

A call of `LFLOAT` shall have one actual parameter, which shall be an expression that is of a real number type or a whole number type.

The type of a call of `LFLOAT` shall be the long real type.

Dynamic Semantics

The value of the call `LFLOAT(x)` shall be the same as the value of the call `VAL(LONGREAL,x)` (see The Function VAL).

Note: An exception occurs if the value of `x` lies outside the range of the long real type.

#### The Function MAX

The function `MAX` can be used to obtain the maximum value of a scalar type.

Static Semantics

A call of `MAX` shall have one actual parameter, which shall be a type parameter that denotes a scalar type.

If the type denoted by the type parameter is a real number type or a whole number type, or the host type of the denoted type is a whole number type (in the case where the denoted type is a subrange type), the type of a call of `MAX` shall be the type of a literal value of that number type; otherwise the type of the call shall be the host type of the type denoted by the type parameter.

Clarification: The function `MAX` may be applied to any scalar type (including the real number types denoted by `REAL` and `LONGREAL`).

Dynamic Semantics

The value of the call `MAX(T)` shall be the largest value of the type denoted by `T`.

Example: Result of `MAX`. Given:

        TYPE
          percentage = CARDINAL[0..100];
          countdown = INTEGER[-9..-1];
          colours = (red, yellow, green);
          coward = colours[yellow..yellow];

then:

expression | value | type
`MAX(percentage)` | `100` | Z-type
`MAX(countdown)` | `-1` | Z-type
`MAX(colours)` | `green` | `colours`
`MAX(coward)` | `yellow` | `colours`

``MAX(CARDINAL)`' and ``MAX(INTEGER)`' are also of the Z-type.

#### The Function MIN

The function `MIN` can be used to obtain the minimum value of a scalar type.

Static Semantics

A call of `MIN` shall have one actual parameter, which shall be a type parameter that denotes a scalar type.

If the type denoted by the type parameter is a real number type or a whole number type, or the host type of the denoted type is a whole number type (in the case where the denoted type is a subrange type), the type of a call of `MIN` shall be the type of a literal value of that number type; otherwise the type of the call shall be the host type of the type denoted by the type parameter.

Clarification: The function `MIN` may be applied to any scalar type (including the real number types denoted by `REAL` and `LONGREAL`).

Dynamic Semantics

The value of the call `MIN(T)` shall be the smallest value of the type denoted by `T`.

Note: The value of the call `MIN(R)`, where R denotes a real number type, is the largest negative value of that type, and not the smallest non-zero positive value of that type. The smallest non-zero positive values of the real type and the long real type are defined by the values of the constants `LowReal.small` and `LowLong.small` respectively --- see ???.

Example: Result of `MIN`. Given:

        TYPE
          percentage = CARDINAL[0..100];
          countdown = INTEGER[-9..-1];
          colours = (red, yellow, green);
          coward = colours[yellow..yellow];

then:

expression | value | type `MIN(percentage)` | `0` | Z-type
`MIN(countdown)` | `-9` | Z-type
`MIN(colours)` | `red` | `colours`
`MIN(coward)` | `yellow` | `colours`

``MIN(CARDINAL)`' and ``MIN(INTEGER)`' are also of the Z-type.

#### The Function ODD

The function `ODD` can be used to determine whether a value of a whole number type is even or odd.

Static Semantics

A call of `ODD` shall have one actual parameter, which shall be an expression that is of a whole number type.

The type of a call of `ODD` shall be the Boolean type.

Dynamic Semantics

If the absolute value of `x` is odd, the value of the call `ODD(x)` shall be the value true ; otherwise it shall be the value false .

#### The Function ORD

The function `ORD` can be used to obtain the ordinal number of a value of an ordinal type.

Static Semantics

A call of `ORD` shall have one actual parameter, which shall be an expression that is of an ordinal type.

The type of a call of `ORD` shall be the unsigned type.

Dynamic Semantics

The value of the call `ORD(x)` shall be the same as the value of the call `VAL(CARDINAL,x)` (see The Function VAL).

Note: An exception occurs if the value to be returned lies outside the range of the unsigned type.

#### The Function RE

The function `RE` can be used to obtain the real part of a value of a complex number type.

Static Semantics

A call of `RE` shall have one actual parameter, which shall be an expression that is of a complex number type.

If the expression is of the complex type, the type of a call of `RE` shall be the real type; if the expression is of the long complex type, the type of the call shall be the long real type; otherwise the expression shall be of the C -type, and the type of the call shall be the R-type.

Dynamic Semantics

The value of the call `RE(z)` shall be an implementation-defined approximation to the real part of `z`.

#### The Function SIZE

The function `SIZE` can be used to ascertain the amount of storage that is used for a variable of a particular type.

Static Semantics

A call of `SIZE` shall have one actual parameter, which shall either be a type parameter, or an entire designator that does not denote an open array parameter.

The type of a call of `SIZE` shall be the Z-type.

Change: In Programming in Modula-2 the parameter may be the identifier of a type or a variable. There is no constraint that the variable is an entire designator that does not denote an open array parameter.

Notes:

1. If the parameter to `SIZE` is a variable designator, it must be an entire designator: it cannot be a component of an array, a field of a record, or the variable referenced by a pointer variable.

2. The constraints on the parameter ensure that a call of `SIZE` is always permitted in a constant expression.

Dynamic Semantics

The value of the call `SIZE(T)`, where `T` denotes any identified type, shall be the number of storage locations (see System Storage Types) that would be occupied by a variable that is of type `T`. If `T` denotes a record type with a group or groups of variant fields, the value of the call shall be the maximum number of storage locations that could be occupied. An exception shall be raised if this number lies outside the range of the Z-type.

The value of the call `SIZE(v)`, where `v` is an entire designator of any type, shall be the same as the value of a call SIZE(T) with an actual parameter `T` that is a qualified identifier denoting the type of `v`.

Note: In calls of the form `SIZE(v)`, `v` may designate a variable of an anonymous type.

#### The Function TRUNC

The function `TRUNC` can be used to obtain a value of the unsigned type from a value of a real number type.

Static Semantics

A call of `TRUNC` shall have one actual parameter, which shall be an expression that is of a real number type.

The type of a call of `TRUNC` shall be the unsigned type.

Dynamic Semantics

The value of the call `TRUNC(x)` shall be the same as the value of the call `VAL(CARDINAL,x)` (see The Function VAL).

Note: An exception occurs if the integral part of `x` lies outside the range of the unsigned type.

#### The Function VAL

The function `VAL` can be used to obtain a value of a specified scalar type from an expression of a scalar type.

Change: The definition of `VAL` given in Programming in Modula-2 has been extended.

Static Semantics

A call of `VAL` shall have two actual parameters. The first parameter shall be a type parameter that denotes a scalar type. If the type denoted by the type parameter is a subrange type, the type of a call of `VAL` shall be the host type of the subrange type; otherwise it shall be the type denoted by the type parameter. The type of the call is called the final-type.

The second parameter shall be an expression that is of a scalar type, subject to the restriction that at least one of the following shall hold:

a) The final-type and the type of the expression are identical.

b) The final-type is a whole number type or a real number type, and the type of the expression is a whole number type or a real number type.

c) The final-type is a whole number type.

d) The type of the expression is a whole number type.

Note: In the following table,enumeration type.

the type of the type denoted by the type parameter the expression CARDINAL* INTEGER* REAL LONGREAL CHAR* BOOLEAN* the type T* CARDINAL p p p p p p p INTEGER p p p p p p p Z-type p p p p p p p REAL p p p p ? ? ? LONGREAL p p p p ? ? ? R-type p p p p ? ? ? CHARy p p ? ? p ? ? BOOLEAN p p ? ? ? p ? the type T p p ? ? ? ? p

* or a subrange of this type y or string literal type of length 0 or 1

Dynamic Semantics

The value of the call `VAL(R,x)`, where the type `R` is a real number type, shall be a value of the type `R` that is an implementation-defined approximation to the value of `x`. An exception shall be raised if the value of `x` lies outside the range of the type `R`.

The value of the call `VAL(T,x)`, where the type `T` is an ordinal type, the host type of this type is a whole number type, and the type of the expression `x` is a whole number type or a real number type, shall be the integral part of the value of `x`. An exception shall be raised if the integral part of `x` lies outside the range of the type `T`.

The value of the call `VAL(T,x)`, where the type `T` or the type of `x` (or both of these types) are not whole number types or real number types, shall be the value of the type `T` that has an ordinal number equal to the ordinal number of the value of `x`. An exception shall be raised if the value of `x` is a numerical value that is less than zero, or if the ordinal number of the value of `x` lies outside the range of the ordinal numbers of the type `T`.

Note: `VAL` does not round. If `x` is of a real number type, the expressions `VAL(INTEGER,x)` and `VAL(CARDINAL,x)` both have the value of `x` truncated.

Example: Result of `VAL`. Given:

        TYPE
          Days = (Sun, Mon, Tue, Wed, Thu, Fri, Sat);
          WeekDays = [Mon..Fri];
        VAR
          i, j, z: INTEGER;
          r: REAL;
        and:
        i := 42; j := -1; z := 0; r := -2.7;

then:

expression | value | type
`VAL(CARDINAL,i)` | `42` | `CARDINAL`
`VAL(CARDINAL,j)` | Exception |
`VAL(CARDINAL,r)` | Exception |
`VAL(INTEGER,i)` | `42` | `INTEGER`
`VAL(INTEGER,r)` | `-2` | `INTEGER`
`VAL(REAL,i)` | `42.0` | `REAL`
`VAL(REAL,TRUE)` | Error |
`VAL(LONGREAL,r)` | `-2.7` | `LONGREAL`
`VAL(CHAR,z)` | `0C` | `CHAR`
`VAL(CHAR,r)` | Error |
`VAL(BOOLEAN,0)` | `FALSE` | `BOOLEAN`
`VAL(Days,5)` | `Fri` | Days
`VAL(WeekDays,5)` | `Fri` | Days
`VAL(WeekDays,z)` | Exception |

#### Auxiliary Definitions

annotations Carry out type conversion; convert the argument to a corresponding value of another type.

annotations Return the integral part of a given numerical value.

## The Environment and Auxiliary Formal Definitions

- Environments
- Operations on the Environment
- Types
- Unit Types
- Other Type Functions
- Values Associated with a Type

### Environments

An environment associates an identifier with an entity, and with the properties of that entity. This association involves at most one of the following:

--- For an identifier that denotes a constant entity, the property is its type.

--- For an identifier that denotes a type, the entity is either a basic type or a unique type name. For an entity that is of a constructed type the environment associates the type name with the structure of that type including, for a structured (composite) type, the component type names.

--- For an identifier that denotes a variable, when checking the well-formed properties of a program, the property of the entity is its type; when giving a meaning to the program, the entity is the associated variable.

--- For an identifier that denotes a declared procedure, when checking the well-formed properties of a program, the properties of the entity are its structure and its declaration level; when giving a meaning to the program, the entity incorporates the elaborated formal parameters, and the identity of the procedure denotation (as constructed from the elaboration of the procedure declaration).

--- For an identifier that denotes a module, the entity is the environment defined by the declarations contained in the module, as restricted by any exports.

An environment contains the declaration level of the block to which it applies; the static continuations for return, exception, loopexit, and retry. and information on the protection domain, if any, that applies.

- Structures
- Expression Types
- Types for Declared Procedures
- Variables

#### Structures

annotations The structure of an enumeration type is the sequence of identifiers defined by the type. The order of the identifiers in the sequence is identical to their order in the type definition.

annotations The structure of a subrange type is the range type and a set of values defined by the lower and upper bounds of the type definition.

annotations The structure of a set type is the type name or basic type of the base type.

annotations The structure of a packedset type is the type name or basic type of the base type.

annotations The structure of a pointer type is the the type name or basic type of the bound type. The bound type is optional because forward use of a type name is allowed in the context of a pointer type.

annotations The structure of a proper procedure or proper procedure type is the type names (or basic types) of the formal parameters of the procedure.

annotations The structure of a function procedure or function procedure type is the type names (or basic types) of the formal parameters of the procedure, together with the the type names or basic types of the result. The return type is optional because forward use of a type name is allowed in the context of a procedure type.

annotations A variable can either be introduced in a variable declaration or it can be a parameter of a procedure. Thus it will either be associated with its type name or its basic type, or it can be an open array parameter. The type is optional here because forward use of a type name is allowed in the context of a procedure type.

annotations The structure of an array type is the type names (or basic types) of the index and component types.

annotations The structure of a record type is the type names (or basic types) of the components of the record.

annotations The String-type is an basic type with a structure that allows the length of a literal string to be represented. Since it is an anonymous type, it can only be the type of an expression.

#### Expression Types

annotations The result of an expression can be: --- a value of a basic type, or a value whose type has been defined in a declaration; --- a string literal; --- the nil value; --- a procedure; or --- an open array.

annotations The structure of the result of an expression can be: --- the structure of a type that has been defined in a declaration; --- the structure of a string literal; --- the structure of a procedure (which is the same as the structure of a procedure type under Structure ; or --- the structure of an open array.

#### Types for Declared Procedures

annotations ptyped is the type structure and declaration level information from the elaboration of the procedure declaration. value is the value that is assigned to procedure variables and the value that is used in procedure calls to retrieve the procedure denotation from the state; it is optional because procedure headings can appear separately from procedure declarations in definitions and in forward declarations.

annotations type corresponds to the type structure for procedure types and is used for procedure calls and for checking compat- ibility. level is the declaration level at which the procedure is declared and is used in checks of assignment comaptibility.

annotations type corresponds to the type structure for procedure types and is used for procedure calls and for checking compat- ibility. level is the declaration level at which the procedure is declared and is used in checks of assignment comaptibility.

#### Variables

annotations If the identifier is associated with an elementary variable that is of a subrange type, then the range component contains the possible set of values that can be assigned to the variable.

annotations If the identifier is associated with a pointer variable then the type of the pointer is associated with the variable so that any pointer dereferencing can be checked.

annotations The components of an array variable are all of the same type.

annotations A variant variable contains information about the explicit tag associated with the variant fields of which the variable is a component; thus before accessing the value of the variable, the tag can be checked to see if its value is such that the variant that contains the variable is active.

annotations A tag variable contains information about the variant components that are associated with it. Thus any change to the value of the tag that will cause a different component to be selected can be reflected by setting the variables of the old component to undefined.

annotations A tagged variable contains information about the implicit tag associated with the variant fields of which the variable is a component; thus before accessing the value of the variable, the tag can be checked to see if its value is such that the variant that contains the variable is active.

### Operations on the Environment

- Functions Accessing the Constants Component of the Environment
- Functions Accessing the Types Component of the Environment
- Functions Accessing the Structures Component of the Environment
- Functions Accessing the Variables Component of the Environment
- Functions Accessing the Procedures Component of the Environment
- Functions Accessing the Modules Component of the Environment
- Functions Accessing the Procedure Level Component of the Environment
- Functions Accessing the Continuations Component of the Environment
- Functions Accessing the Protection Components of the Environment
- Functions Accessing the Environment
- Operations to Update Environments

#### Functions Accessing the Constants Component of the Environment

annotations Check that a qualident denotes a constant.

annotations The result is the unique type of a qualident that denotes a constant.

annotations The result is the constant value associated with a qualident that is introduced in a constant declaration.

annotations Construct an environment by overwriting the given environment with the given constants component. Any identifiers from the given environment that do not appear in the given constants component will remain visible in the new environment.

#### Functions Accessing the Types Component of the Environment

annotations Check that a qualident denotes a type.

annotations The result is the type name or basic type associated with a qualident that denotes a type.

annotations Construct an environment by overwriting the given environment with the given types component. Any identifiers from the given environment that do not appear in the given types component will remain visible in the new environment.

#### Functions Accessing the Structures Component of the Environment

annotations The result is the structure associated with a type or with a procedure. Only constructed types, procedures, and the String-type have a structure; other types are synonyms for the basic types or the basic types themselves.

annotations The result is the structure of a qualident that denotes a type.

annotations Construct an environment by overwriting the given environment with the given structure component. Any type names from the given environment that do not appear in the given structure component will remain in the domain of the new environment.

#### Functions Accessing the Variables Component of the Environment

annotations Check if a qualident denotes a variable; this may be a field of a record inside a with statement.

annotations The result is the type name or basic type of a qualident that denotes a variable; used with environments constructed for the wf- and t- functions.

annotations The result is the variable associated with a qualident that denotes a variable; used with environments constructed for the m- functions.

annotations Construct an environment by overwriting the given environment with the given variables component. Any identifiers from the given environment that do not appear in the given variables component will remain visible in the new environment.

#### Functions Accessing the Procedures Component of the Environment

annotations Check if a qualident denotes a procedure.

annotations The result is the type of a qualident that denotes a declared procedure; this is a record comprising the structure and declaration level information.

annotations The result is the type structure for a declared procedure.

annotations The result is the declaration level of a declared procedure.

annotations Construct an environment by overwriting the given environment with the given procs component. Any identifiers from the given environment that do not appear in the given procs component will remain visible in the new environment.

#### Functions Accessing the Modules Component of the Environment

annotations Checks if a qualident denotes a module.

annotations Return the module environment associated with the qualident.

annotations Return the environment associated with the module environment.

annotations Construct an environment by overwriting the given environment with the given module component. Any identifiers from the given environment that do not appear in the given module component will remain visible in the new environment.

annotations Return the local definition module environment associated with the qualident.

#### Functions Accessing the Procedure Level Component of the Environment

annotations Return the current declaration level of the environment.

annotations Increase the declaration level of declarations by one.

#### Functions Accessing the Continuations Component of the Environment

annotations Extract the current exception handler.

#### Functions Accessing the Protection Components of the Environment

annotations If a module is declared within a protected module, and this module is not protected, the same protection applies; otherwise the protection of this module applies.

annotations Extract the module protection expression and procedures from the environment.

annotations Add the set of exported identifiers to the environment.

annotations Extract the set of exported identifiers from the environment.

#### Functions Accessing the Environment

annotations Look up a (possibly qualified) identifier in the environment, and return the associated entity and its properties.

annotations The set of visible identifiers is the set defined by the union of all of the domains of various (mapping) components of the environment. The scope of these identifiers includes the points where the environment applies.

#### Operations to Update Environments

annotations Merge two environments.

annotations Merge all the environments contained in a set of environments.

annotations Overwrite the environment ? with the environment env .

annotations visible-identifiers(restrict-environment (ids )?) = ids

annotations The identifiers are visible in the new environment, but their meanings are unknown; used in checking declare before use rules.

annotations Combine the environments of a definition module and the associated implementation module. Note that the declarations for opaque types and procedures are taken from the implementation module.

### Types

- New Type Names
- Structured (Composite) Types
- Elementary Types
- Scalar Types
- Ordinal Types
- Whole Number Types
- Number Types
- String Types
- System Storage Types

#### New Type Names

annotations Generate a type name that has not been used elsewhere in the current environment.

#### Structured (Composite) Types

A structured (composite) type is an array type or a record type.

annotations Check that a type is a structured type.

annotations Check that a type denotes an array type.

annotations Check that a type denotes a record type.

#### Elementary Types

An elementary type is either a procedure type, a pointer type, an opaque type, a set type, a packedset type, a scalar type, or a complex number type.

annotations Check that a type is an elementary type.

annotations Check that a type-name denotes a proper procedure type or a function procedure type; these are the types of procedure variables.

annotations Check that a type denotes a proper procedure type; this is the type of a procedure variable of a proper procedure structure.

annotations Check that a type denotes a function procedure type; this is the type of a procedure variable of a function procedure structure.

annotations Check that a type denotes a set type.

annotations Check that a type denotes a packedset type.

annotations Check that a type denotes a pointer type.

annotations Check that a type denotes an opaque type.

#### Scalar Types

A scalar type is either an ordinal type or a real number type.

annotations Check that a type denotes a scalar type.

#### Ordinal Types

An ordinal type is either the Boolean type, the character type, an enumeration type, a subrange type, or a whole number type; the character literal type is included since it is interpreted as a value of the character type in contexts where an ordinal type is expected.

annotations Check that a type is an ordinal type.

annotations Check that a type is the character type.

annotations Check that a type is an enumeration type.

annotations Check that an identifier is an enumeration constant and thus denotes itself.

annotations Check that a type is a subrange type.

#### Whole Number Types

A whole number type is either the unsigned type, the signed type or the type of an expression whose operands are whole number literal values.

annotations Check that a type denotes a whole number type.

annotations Check that a type denotes the unsigned type.

annotations Check that a type denotes the signed type.

annotations Check that a type denotes the Z-type.

#### Number Types

A number type is a real number type or a whole number type.

Note: A complex number type is not a `number type' as it does not permit relational operations.

annotations Check that a type denotes a real number type or a whole number type.

#### String Types

The string type is the type of a literal string; it has a structure representing the length of the literal string. Values of the string literal type of length 0 or length 1 are distinguished as values of the character literal type since the character type is assignment compatible and expression compatible with this type.

annotations Check that a type denotes a string type of length 0 or 1.

#### System Storage Types

A system storage type is either the location type, denoted by `SYSTEM.LOC`, the word type, denoted by `SYSTEM.WORD`, or the byte type, denoted by `SYSTEM.BYTE` if provided by an implementation.

annotations Check that a type denotes a system storage type.

annotations Check that a type denotes the location type.

annotations Check that a type denotes the address type.

### Unit Types

A unit type is either the range type of a subrange type, the host type of a subrange type, the base type of a set type, the base type of a packedset type, the component type of an array type, the index type of an array type, or the bound type of a pointer type.

- Range Type
- Host Type
- Base Type
- Component Type
- Index Type
- Bound Type

#### Range Type

The range type of a subrange type is the ordinal type from which the subrange type is directly derived.

annotations The result is the range type of a subrange type.

#### Host Type

The host type of a subrange type is the ordinal type from which the subrange type is indirectly derived by defining a subrange of a previously defined ordinal type. It is the Boolean type, the character type, an enumeration type, the signed type, or the unsigned type.

annotations The result is the host type of a subrange type.

#### Base Type

The base type of a set type or a packedset type is the ordinal type to which the members of the set type or packedset type directly belong.

annotations The result is the base type of a set type or a packedset type.

#### Component Type

The component type of an array type is the type of the components of an array structure.

annotations The result is the component type of an array type.

#### Index Type

The index type of an array type is the type of the index of an array structure.

annotations The result is the index type of an array type.

#### Bound Type

The bound type of a pointer type is the type of the variable pointed to by a value of the pointer type.

annotations The result is the bound type of a pointer type.

### Other Type Functions

- Formal Parameter Types
- Auxiliary Functions for Records
- Auxiliary Functions for Arrays
- Auxiliary Functions for Open Arrays
- Auxiliary Functions for Opaque Types

#### Formal Parameter Types

annotations Applied to the type of a value designator, this function returns the formal parameter structure and types for procedures, procedure constants, and procedure variables.

#### Auxiliary Functions for Records

annotations The result is a mapping whose domain is the field identifiers of the fixed part of a record together with the field identifiers of the variant component(s). In the mapping each field identifier is mapped to its declared type.

annotations Construct a mapping that is the union of the mappings constructed from each of the fields-structure components of the field-list-structure.

annotations Construct a mapping from either a fixed-fields-structure or a variant-fields-structure component of a field-list- structure.

annotations Construct a mapping whose domain is the field identifiers of all the variant components of a record, and in which each field identifier is mapped to its declared type.

annotations Construct a mapping whose domain is the tag identifier, the field identifiers of the variant components of a record and the field identifiers of the ELSE component, and in which each field identifier is mapped to its declared type.

annotations Construct a mapping that relates the identifiers belonging to every variant component of a record type with their declared types.

annotations Construct a mapping that relates the field identifiers of a particular variant component of a record type with their declared types.

#### Auxiliary Functions for Arrays

annotations Check that a type is an array type with signed index starting at zero.

annotations The result is the lower bound of an array.

annotations The result is the upper bound of an array.

#### Auxiliary Functions for Open Arrays

annotations Check that a type denotes an open array formal type.

#### Auxiliary Functions for Opaque Types

annotations The opaque types of an environment are those types whose structure is opaque.

### Values Associated with a Type

The values associated with a type are the smallest and largest values that a value of that type may assume.

annotations Return the largest value of a type.

annotations Return the largest value of an enumeration type. This is denoted by the last identifier that occurs in the sequence of identifiers of the enumeration type.

annotations Return the largest value of a subrange type.

annotations Return the smallest value of a type.

annotations Return the smallest value of an enumeration type. This is denoted by the first identifier that occurs in the sequence of identifiers of the enumeration type.

annotations Return the smallest value of a subrange type.

annotations Return the set of values associated with a type.

annotations Return the set of value associated with an enumeration type. This is the set of values containing the identifiers that occurs in the sequence of identifiers of the enumeration type.

annotations Convert a natural number into an Enumeration-value.

annotations Return the set of value associated with an subrange type.

annotations Return a sequence of values associated with a type. This sequence is ordered by the values from which it is constructed.

## The Storage Model and Auxiliary Formal Definitions

- The External Program State
- The Store
- Exceptions
- Interrupt Handlers
- Operations on Storage
- Accessing the Procedure Denotation Component of the State
- Program Initialization and Program Termination
- Exception Handling
- Interrupt Handlers
- Accessing the Protection Component of the State
- Coroutine and Continuations

### The External Program State

annotations The program-storage-pool component of an External-program-state is an implementation dependent model of storage available to a Modula-2 program that consists of a set of Locs that denotes the initial free storage available to a program. The external-store component of an External-program-state is a model of the storage locations that a Modula-2 program can have access to via an address that is calculated from the machine address component of a variable declaration (see Aliasing Machine Addresses).

- Operations to Initialize and Terminate the Program State

#### Operations to Initialize and Terminate the Program State

annotations Initializes the state with the external program state. As part of the call of read-external-program-state , the changes to the library state of abstract implementation modules, as defined by the operation read-external- < libraryname > -state , should be carried out.

annotations This operation returns the final state of any external storage and de-allocates all storage in the storage model. As part of the call of write-external-program-state , the extraction of changes to the library state of abstract implementation modules, as defined by the operation write-external- < libraryname > -state , should be carried out.

### The Store

- Storage
- Values

#### Storage

annotations The invariant requires that the storage locations allocated to a coroutine are disjoint from the storage locations used by the coroutine. The operation check-changes requires that once storage has been allocated to a coroutine, it must not be used by the coroutine that was originally allocated the storage. Taken together, this means that an implementation may re-use the storage passed to a coroutine for the workspace of that coroutine.

annotations The rest component is an implementation dependent type consisting of a set of Loc , posssibly derived from the allocated component, from which storage can be allocated.

#### Values

annotations Strictly speaking N ? Z? R ? C , however, they are shown as separate sets for clarity.

### Exceptions

annotations Each coroutine has a non-empty stack of exception contexts associated with it. The top context on the stack indicates whether the coroutine is executing in the state of normal execution, exceptional execution due to the raising of a language exception, or exceptional execution due to the raising of a user exception. The stack is initialized to indicate normal execution; a further normal execution context is pushed on the stack on the execution of a block body that has an exceptional part. If an exception is raised, the top exception context is replaced by a context that holds information about the exception.

### Interrupt Handlers

annotations Interrupt-source is an implementation defined set of values

### Operations on Storage

- Operations Accessing Storage
- Storage Aliasing
- Operations to Allocate and Deallocate Storage
- Operations to Allocate and Deallocate Storage Locations

#### Operations Accessing Storage

annotations Check the existence of a storage location.

annotations Access the value of a storage location associated with a variable.

annotations Change the value of a storage location. That storage location could be aliased with other storage locations caused by passing a variable using a variable parameter of a system storage formal type; this will cause an implementation defined change to these storage locations.

annotations Check that the locations denoted by the first parameter are not contained in storage that has been allocated to a coroutine.

#### Storage Aliasing

annotations The storage location denoted by loc is aliased with (part of ) the storage location(s) denoted by var . Thus a change to the contents of the storage location modelled by var when the value val is assigned to it may change the contents of the storage location modelled by loc | return an implementation defined value that describes any changes to the contents of the storage location loc because of the assignment.

annotations Return the set of alias pairs that could occur if two variables share storage.

annotations Update the alias information with the set of alias pairs that could occur if two variables share storage.

annotations Remove alias pairs from storage.

##### Aliasing Machine Addresses

annotations Alias a machine address with a location.

annotations Convert a machine address to a location. The value of type Loc returned by this function must be in the domain of the machine-storage component of the state.

#### Operations to Allocate and Deallocate Storage

annotations An exception is raised if there is not enough storage available.

annotations Deallocate the storage associated with a set of identifiers.

annotations De-allocate the storage of the modules in the environment.

annotations Deallocate the storage associated with a set of variables.

annotations Return the set of locations associated with a variable.

#### Operations to Allocate and Deallocate Storage Locations

annotations Generate a new storage location (one currently not in the domain of the storage map) and set its value to undefined. The choice of storage location is non-deterministic.

annotations Return an implementation dependent set of Locs derived from the storage pool.

annotations Deallocate storage defined by a set of locations --- return the set of storage locations (currently in the domain of the storage map) and return them to the storage pool.

### Accessing the Procedure Denotation Component of the State

annotations The well-formed conditions for abstract modules require that all procedure identifiers used in the program be distinct.

### Program Initialization and Program Termination

- Program Initialization
- Program Termination
- Program Halting

#### Program Initialization

annotations Set the program termination flag to signal that initialization is occurring. The main program and each coroutine will be able to enquire if it is terminating.

#### Program Termination

annotations Set this coroutine as terminating.

annotations Check if this coroutine is terminating.

annotations Check if any coroutine is terminating.

annotations Check if any coroutine is terminating.

annotations Check if the coroutine with the identifier cid is terminating.

annotations Return the next module finalization code if one exists, otherwise return nil .

annotations Implementation dependent housekeeping to complete execution of a program.

#### Program Halting

annotations Set the program termination flag to signal that termination is occuring.

annotations Check if the program is halting.

### Exception Handling

annotations An exception has no exception handler --- these are implementation dependent actions that are to be performed when the program is terminated exceptionally.

annotations Push an exception context.

annotations Pop an exception context.

annotations Read the current exception context.

annotations Read the current exception context.

annotations Return true iff the given exception context indicates the state of exceptional execution.

annotations Raise an exception under the current exception handler with the exception context.

- Allocation of Exception Sources

#### Allocation of Exception Sources

annotations Allocate a source, or return nil if no more Exception-source values are availablle.

### Interrupt Handlers

annotations Attach the calling coroutine to a source of interrupts.

annotations Detach the calling coroutine from a source of interrupts.

annotations Return the identity of the currently executing coroutine.

annotations Set a handler for an interrupt.

annotations Check that the currently executing coroutine is attached to a source of interrupts.

annotations An event connected to the coroutine calling `IOTRANSFER` will cause the coroutine to resume at the statement following the call to `IOTRANSFER` and place the identity of the coroutine that was interrupted in the first argument.

annotations Return the handlers of the program from the program state.

### Accessing the Protection Component of the State

annotations Read the state and return the current protection of the caller.

annotations Read the state and return true iff the parameter is less restrictive than the current protection of the caller.

annotations Add the new protection to the state.

### Coroutine and Continuations

- Operations on Continuations

#### Operations on Continuations

annotations Continue with the continuation cont .

annotations Initialize a coroutine by adding to the coroutine environment.

annotations Resume a coroutine by saving the current execution of the coroutine that is currently being executed in the envi- ronment, and continuing the execution of the coroutine to be resumed.

annotations Allocate an unused coroutine identifier.

annotations Construct coroutine storage and add it to the state. The storage consists of an empty protection stack and the storage for the variables and control information for a coroutine.

annotations Add the storage for a coroutine to the state.