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 ???.
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:
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:
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:
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.
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:
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.
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.
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:
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.
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:
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 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.
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.
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:
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.
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
Auxiliaries
annotations Construct the set of the identifiers of the definition modules that appear in a sequence of program, definition, and implementation modules.
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.
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.
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:
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.
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.
An import list may either be a simple import or an unqualified import.
Concrete Syntax
import list= simple import | unqualified import ;
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.
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.
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.
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.
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.
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:
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.
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:
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;
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 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.
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.
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 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:
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 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.
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 ;
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.
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.
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 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 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 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:
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:
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.
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.
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.
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:
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
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:
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:
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.
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.
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:
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:
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.
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:
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:
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.
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:
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.
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.
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.
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