Modula-2 (на английском языке) (1161147), страница 7
Текст из файла (страница 7)
You can import from the same module in multiple import declarations but you cannot import the same symbol more than once.
Local Modules
Local ModulesModulesLocalLocal modules are modules that are declared inside other modules. Local modules provide a filter for symbols. You can control which symbols from the environment are visible inside the module, and which symbols declared in the module are visible outside the module.
Local modules take the following form:
MODULE ModName [[Protection]];
{Import}
[Export]
{Declaration}
[ BEGIN
ListOfStatements
[EXCEPT
ListOfStatements]
[
FINALLY
ListOfStatements
EXCEPT
ListOfStatements
]
]
END ModName;
Imports in local modules
The import declaration takes the same form in local modules. The symbols imported, however, are not necessarily symbols from other compilation units.
The symbols imported by a local module must be visible in the block containing the module. Only those symbols imported and the standard pervasive identifiers are visible inside the module.
The export declaration
Normally, symbols declared in a module are not visible outside the module. You can use an export declaration in the module to specify those symbols that are made visible in the containing block.
The export declaration takes the following form:
EXPORT [QUALIFIED] identifier {,identifier};
Each identifier must be visible in the module, either because it is defined in the module, or because it was exported from a nested module. These identifiers, and only these identifiers, are made visible in the block containing the local module declaration.
Because the identifiers on the export list are made visible in the containing block, they must not conflict with another identifier declared in that block or exported from another local module to that block.
If you use the QUALIFIED keyword, the identifiers are not made directly visible, they must be qualified by the module name.
Module Initialization
The ListOfStatements following the BEGIN keyword up to but not including the FINALLY keyword if present, in implementation and local modules is initialization code for the module.
The initialization code for all implementation modules is executed before the start of the main program. The order of initialization cannot be guaranteed. However all modules that a module depend on are initialized before its own initialization code is executed.
If a local module is nested in a procedure, its initialization code is executed each time the procedure that contains the module is called.
If the module is local to an implementation module and not to any procedure, the initialization code is executed when the implementation module is initialized.
If the module is local to the program module, its initialization code is performed after all implementation modules and before the start of the program.
Local modules are initialized in the order that they are declared in the source file.
Module Termination
The ListOfStatements following the FINALLY keyword in implementation and local modules is termination code for the module.
The termination code for a module is not active, and will not be executed unless the initialization code completes with an unhandled exception.
The termination code for all implementation modules is executed when the program is terminated either with a call to the HALT procedure or after the last statement in the main program is executed. The order of termination is the exact reverse of the order of initialization.
If a local module is nested in a procedure, its termination code is executed each time the procedure that contains the modules finishes execution and returns to the procedure that called it.
If the module is local to an implementation module and not to any procedure, the termination code is executed when the implementation module termination code is finished executing.
Local modules are terminated in the reverse order that they are declared in the source file.
Exception handling in Module initialization and termination code
Both the initialization and termination sections can have their own unique exception handler. You should think of the BEGIN and FINALLY parts as two separate procedures.
Module Protection
Modules can have an associated protection. The module protection value is a set constant of type PROTECTION in square brackets following the module name. The protection type is defined as
32-bit mode:
PROTECTION = PACKEDSET OF CARDINAL[0..31];
16-bit mode:
PROTECTION = PACKEDSET OF CARDINAL[0..15];
Note: the Stony Brook Modula-2 runtime system does not do anything with the module protection value.
The module protection is defined as an interrupt mask. Thus the code in a module can protect itself from certain interrupts. Two pervasive constants of type PROTECTION are defined. INTERRUPTABLE and UNINTERRUPTABLE. All values of type PROTECTION satisfy the following relationship.
INTERRUPTABLE <= AnyProtectionValue <= UNINTERRUPTABLE
The current protection value can be accessed via the COROUTINES.PROT function (see ISO module COROUTINES).
Compilation units
A text which is accepted by the compiler as a unit is called a compilation unit. There are three kinds of compilation units: main modules, definition modules, and implementation modules. A main module constitutes a main program and consists of a so-called program module. In particular, it has no export list. Imported objects are defined in other (separately compiled) program parts which themselves are subdivided into two units, called definition module and implementation module.
The definition module specifies the names and properties of objects that are relevant to clients, i.e. other modules which import from it. The implementation module contains local objects and statements that need not be known to a client In particular the defInition module contains constant, type, and variable declarations, and specifications of procedure headings. The corresponding implementation module contains the complete procedure declarations, and possibly further declarations of objects not exported. Definition and implementation modules exist in pairs. Both may contain import lists, and all objects declared in the definition module are available in the corresponding implementation module without explicit import.
DefinitionModule = DEFINITION MODULE ident ";"
{import} {definition} END ident ".".
definition = CONST {ConstantDeclaration ";"} |
TYPE {ident["=" type] ";"} |
VAR {VariableDeclaration ";"} |
ProcedureHeading ";".
ProgramModule = MODULE ident [priority] ";" {import} block ident ".".
CompilationUnit = DefinitionModule | [IMPLEMENTATION] ProgramModule.
The definition module evidently represents the interface between the implementation module on one side and its clients on the other side. The definition module contains those declarations which are relevant to the client modules, and presumably no other ones. Hence, the definition module acts as the implementation module's (extended) export list, and all its declared objects are exported.
Definition modules imply the use of qualified export. Type definitions may consist of the full specification of the type (in this case its export is said to be transparent), or they may consist of the type identifier only. In this case the full specification must appear in the corresponding implementation module, and its export is said to be opaque. The type is known in the importing client modules by its name only, and all its properties are hidden. Therefore, procedures operating on operands of this type, and in particular operating on its components, must be defined in the same implementation module which hides the type's properties. Opaque export is restricted to pointers. Assignment and test for equality are applicable to all opaque types.
As in local modules, the body of an implementation module acts as an initialization facility for its local objects. Before its execution, the imported modules are initialized in the order in which they are listed. If circular references occur among modules, their order of initialization is not defined.