The Ada Joint Program Office does not guarantee the accuracy of this file, as compared with the contents of ANSI/MIL-STD-1815A-1983, the Reference Manual for the Ada Programming Language. If errors or discrepancies are found in this machine-readable version, please forward comments via the Defense Data Network (DDN) to: ACTION@AJPO.SEI.CMU.EDU or via conventional mail to Ada Information Clearinghouse 3D139 (1211 S. Fern, C-107) The Pentagon Washington, D.C. 20301-3081 ----------------------------------------------------------------------- Copyright 1980, 1982, 1983 owned by the United States Government as represented by the Under Secretary of Defense, Research and Engineering. All rights reserved. Provided that notice of copyright is included on the first page, this document may be copied in its entirety without alteration or as altered by (1) adding text that is clearly marked as an insertion; (2) shading or highlighting existing text; (3) deleting examples. Permission to publish other excerpts should be obtained from the Ada Joint Program Office, OUSDRE (R&AT), The Pentagon, Washington, DC 20301-2081, U.S.A. 10. Program Structure and Compilation Issues The overall structure of programs and the facilities for separate compilation are described in this chapter. A program is a collection of one or more compilation units submitted to a compiler in one or more compilations. Each compilation unit specifies the separate compilation of a construct which can be a subprogram declaration or body, a package declaration or body, a generic declaration or body, or a generic instantiation. Alternatively this construct can be a subunit, in which case it includes the body of a subprogram, package, task unit, or generic unit declared within another compilation unit. References: compilation 10.1, compilation unit 10.1, generic body 12.2, generic declaration 12.1, generic instantiation 12.3, package body 7.1, package declaration 7.1, subprogram body 6.3, subprogram declaration 6.1, subunit 10.2, task body 9.1, task unit 9 10.1 Compilation Units - Library Units The text of a program can be submitted to the compiler in one or more compilations. Each compilation is a succession of compilation units. compilation ::= {compilation_unit} compilation_unit ::= context_clause library_unit | context_clause secondary_unit library_unit ::= subprogram_declaration | package_declaration | generic_declaration | generic_instantiation | subprogram_body secondary_unit ::= library_unit_body | subunit library_unit_body ::= subprogram_body | package_body The compilation units of a program are said to belong to a program library. A compilation unit defines either a library unit or a secondary unit. A secondary unit is either the separately compiled proper body of a library unit, or a subunit of another compilation unit. The designator of a separately compiled subprogram (whether a library unit or a subunit) must be an identifier. Within a program library the simple names of all library units must be distinct identifiers. The effect of compiling a library unit is to define (or redefine) this unit as one that belongs to the program library. For the visibility rules, each library unit acts as a declaration that occurs immediately within the package STANDARD. The effect of compiling a secondary unit is to define the body of a library unit, or in the case of a subunit, to define the proper body of a program unit that is declared within another compilation unit. A subprogram body given in a compilation unit is interpreted as a secondary unit if the program library already contains a library unit that is a subprogram with the same name; it is otherwise interpreted both as a library unit and as the corresponding library unit body (that is, as a secondary unit). The compilation units of a compilation are compiled in the given order. A pragma that applies to the whole of a compilation must appear before the first compilation unit of that compilation. A subprogram that is a library unit can be used as a main program in the usual sense. Each main program acts as if called by some environment task; the means by which this execution is initiated are not prescribed by the language definition. An implementation may impose certain requirements on the parameters and on the result, if any, of a main program (these requirements must be stated in Appendix F). In any case, every implementation is required to allow, at least, main programs that are parameterless procedures, and every main program must be a subprogram that is a library unit. Notes: A simple program may consist of a single compilation unit. A compilation need not have any compilation units; for example, its text can consist of pragmas. The designator of a library function cannot be an operator symbol, but a renaming declaration is allowed to rename a library function as an operator. Two library subprograms must have distinct simple names and hence cannot overload each other. However, renaming declarations are allowed to define overloaded names for such subprograms, and a locally declared subprogram is allowed to overload a library subprogram. The expanded name STANDARD.L can be used for a library unit L (unless the name STANDARD is hidden) since library units act as declarations that occur immediately within the package STANDARD. References: allow 1.6, context clause 10.1.1, declaration 3.1, designator 6.1, environment 10.4, generic declaration 12.1, generic instantiation 12.3, hiding 8.3, identifier 2.3, library unit 10.5, local declaration 8.1, must 1.6, name 4.1, occur immediately within 8.1, operator 4.5, operator symbol 6.1, overloading 6.6 8.7, package body 7.1, package declaration 7.1, parameter of a subprogram 6.2, pragma 2.8, procedure 6.1, program unit 6, proper body 3.9, renaming declaration 8.5, simple name 4.1, standard package 8.6, subprogram 6, subprogram body 6.3, subprogram declaration 6.1, subunit 10.2, task 9, visibility 8.3 10.1.1 Context Clauses - With Clauses A context clause is used to specify the library units whose names are needed within a compilation unit. context_clause ::= {with_clause {use_clause}} with_clause ::= with unit_simple_name {, unit_simple_name}; The names that appear in a context clause must be the simple names of library units. The simple name of any library unit is allowed within a with clause. The only names allowed in a use clause of a context clause are the simple names of library packages mentioned by previous with clauses of the context clause. A simple name declared by a renaming declaration is not allowed in a context clause. The with clauses and use clauses of the context clause of a library unit apply to this library unit and also to the secondary unit that defines the corresponding body (whether such a clause is repeated or not for this unit). Similarly, the with clauses and use clauses of the context clause of a compilation unit apply to this unit and also to its subunits, if any. If a library unit is named by a with clause that applies to a compilation unit, then this library unit is directly visible within the compilation unit, except where hidden; the library unit is visible as if declared immediately within the package STANDARD (see 8.6). Dependences among compilation units are defined by with clauses; that is, a compilation unit that mentions other library units in its with clauses depends on those library units. These dependences between units are taken into account for the determination of the allowed order of compilation (and recompilation) of compilation units, as explained in section 10.3, and for the determination of the allowed order of elaboration of compilation units, as explained in section 10.5. Notes: A library unit named by a with clause of a compilation unit is visible (except where hidden) within the compilation unit and hence can be used as a corresponding program unit. Thus within the compilation unit, the name of a library package can be given in use clauses and can be used to form expanded names; a library subprogram can be called; and instances of a library generic unit can be declared. The rules given for with clauses are such that the same effect is obtained whether the name of a library unit is mentioned once or more than once by the applicable with clauses, or even within a given with clause. Example 1 : A main program: The following is an example of a main program consisting of a single compilation unit: a procedure for printing the real roots of a quadratic equation. The predefined package TEXT_IO and a user-defined package REAL_OPERATIONS (containing the definition of the type REAL and of the packages REAL_IO and REAL_FUNCTIONS) are assumed to be already present in the program library. Such packages may be used by other main programs. with TEXT_IO, REAL_OPERATIONS; use REAL_OPERATIONS; procedure QUADRATIC_EQUATION is A, B, C, D : REAL; use REAL_IO, -- achieves direct visibility of GET and PUT for REAL TEXT_IO, -- achieves direct visibility of PUT for strings and of NEW_LINE REAL_FUNCTIONS; -- achieves direct visibility of SQRT begin GET(A); GET(B); GET(C); D := B**2 - 4.0*A*C; if D < 0.0 then PUT("Imaginary Roots."); else PUT("Real Roots : X1 = "); PUT((-B - SQRT(D))/(2.0*A)); PUT(" X2 = "); PUT((-B + SQRT(D))/(2.0*A)); end if; NEW_LINE; end QUADRATIC_EQUATION; Notes on the example: The with clauses of a compilation unit need only mention the names of those library subprograms and packages whose visibility is actually necessary within the unit. They need not (and should not) mention other library units that are used in turn by some of the units named in the with clauses, unless these other library units are also used directly by the current compilation unit. For example, the body of the package REAL_OPERATIONS may need elementary operations provided by other packages. The latter packages should not be named by the with clause of QUADRATIC_EQUATION since these elementary operations are not directly called within its body. References: allow 1.6, compilation unit 10.1, direct visibility 8.3, elaboration 3.9, generic body 12.2, generic unit 12.1, hiding 8.3, instance 12.3, library unit 10.1, main program 10.1, must 1.6, name 4.1, package 7, package body 7.1, package declaration 7.1, procedure 6.1, program unit 6, secondary unit 10.1, simple name 4.1, standard predefined package 8.6, subprogram body 6.3, subprogram declaration 6.1, subunit 10.2, type 3.3, use clause 8.4, visibility 8.3 10.1.2 Examples of Compilation Units A compilation unit can be split into a number of compilation units. For example, consider the following program. procedure PROCESSOR is SMALL : constant := 20; TOTAL : INTEGER := 0; package STOCK is LIMIT : constant := 1 TABLE : array (1 .. LIMIT) of INTEGER; procedure RESTART; end STOCK; package body STOCK is procedure RESTART is begin for N in 1 .. LIMIT loop TABLE(N) := N; end loop; end; begin RESTART; end STOCK; procedure UPDATE(X : INTEGER) is use STOCK; begin ... TABLE(X) := TABLE(X) + SMALL; ... end UPDATE; begin ... STOCK.RESTART; -- reinitializes TABLE ... end PROCESSOR; The following three compilation units define a program with an effect equivalent to the above example (the broken lines between compilation units serve to remind the reader that these units need not be contiguous texts). Example 2 : Several compilation units: package STOCK is LIMIT : constant := 1 TABLE : array (1 .. LIMIT) of INTEGER; procedure RESTART; end STOCK; ------------------------------------------------- package body STOCK is procedure RESTART is begin for N in 1 .. LIMIT loop TABLE(N) := N; end loop; end; begin RESTART; end STOCK; ------------------------------------------------- with STOCK; procedure PROCESSOR is SMALL : constant := 20; TOTAL : INTEGER := 0; procedure UPDATE(X : INTEGER) is use STOCK; begin ... TABLE(X) := TABLE(X) + SMALL; ... end UPDATE; begin ... STOCK.RESTART; -- reinitializes TABLE ... end PROCESSOR; Note that in the latter version, the package STOCK has no visibility of outer identifiers other than the predefined identifiers (of the package STANDARD). In particular, STOCK does not use any identifier declared in PROCESSOR such as SMALL or TOTAL; otherwise STOCK could not have been extracted from PROCESSOR in the above manner. The procedure PROCESSOR, on the other hand, depends on STOCK and mentions this package in a with clause. This permits the inner occurrences of STOCK in the expanded name STOCK.RESTART and in the use clause. These three compilation units can be submitted in one or more compilations. For example, it is possible to submit the package specification and the package body together and in this order in a single compilation. References: compilation unit 10.1, declaration 3.1, identifier 2.3, package 7, package body 7.1, package specification 7.1, program 10, standard package 8.6, use clause 8.4, visibility 8.3, with clause 10.1.1 10.2 Subunits of Compilation Units A subunit is used for the separate compilation of the proper body of a program unit declared within another compilation unit. This method of splitting a program permits hierarchical program development. body_stub ::= subprogram_specification is separate; | package body package_simple_name is separate; | task body task_simple_name is separate; subunit ::= separate (parent_unit_name) proper_body A body stub is only allowed as the body of a program unit (a subprogram, a package, a task unit, or a generic unit) if the body stub occurs immediately within either the specification of a library package or the declarative part of another compilation unit. If the body of a program unit is a body stub, a separately compiled subunit containing the corresponding proper body is required. In the case of a subprogram, the subprogram specifications given in the proper body and in the body stub must conform (see 6.3.1). Each subunit mentions the name of its parent unit, that is, the compilation unit where the corresponding body stub is given. If the parent unit is a library unit, it is called the ancestor library unit. If the parent unit is itself a subunit, the parent unit name must be given in full as an expanded name, starting with the simple name of the ancestor library unit. The simple names of all subunits that have the same ancestor library unit must be distinct identifiers. Visibility within the proper body of a subunit is the visibility that would be obtained at the place of the corresponding body stub (within the parent unit) if the with clauses and use clauses of the subunit were appended to the context clause of the parent unit. If the parent unit is itself a subunit, then the same rule is used to define the visibility within the proper body of the parent unit. The effect of the elaboration of a body stub is to elaborate the proper body of the subunit. Notes: Two subunits of different library units in the same program library need not have distinct identifiers. In any case, their full expanded names are distinct, since the simple names of library units are distinct and since the simple names of all subunits that have a given library unit as ancestor unit are also distinct. By means of renaming declarations, overloaded subprogram names that rename (distinct) subunits can be introduced. A library unit that is named by the with clause of a subunit can be hidden by a declaration (with the same identifier) given in the proper body of the subunit. Moreover, such a library unit can even be hidden by a declaration given within a parent unit since a library unit acts as if declared in STANDARD; this however does not affect the interpretation of the with clauses themselves, since only names of library units can appear in with clauses. References: compilation unit 10.1, conform 6.3.1, context clause 10.1.1, declaration 3.1, declarative part 3.9, direct visibility 8.3, elaboration 3.9, expanded name 4.1.3, generic body 12.2, generic unit 12, hidden declaration 8.3, identifier 2.3, library unit 10.1, local declaration 8.1, name 4.1, occur immediately within 8.1, overloading 8.3, package 7, package body 7.1, package specification 7.1, program 10, program unit 6, proper body 3.9, renaming declaration 8.5, separate compilation 10.1, simple name 4.1, subprogram 6, subprogram body 6.3, subprogram specification 6.1, task 9, task body 9.1, task unit 9.1, use clause 8.4, visibility 8.3, with clause 10.1.1 10.2.1 Examples of Subunits The procedure TOP is first written as a compilation unit without subunits. with TEXT_IO; procedure TOP is type REAL is digits 10; R, S : REAL := 1.0; package FACILITY is PI : constant := 3.14159_26536; function F(X : REAL) return REAL; procedure G(Y, Z : REAL); end FACILITY; package body FACILITY is -- some local declarations followed by function F(X : REAL) return REAL is begin -- sequence of statements of F ... end F; procedure G(Y, Z : REAL) is -- local procedures using TEXT_IO ... begin -- sequence of statements of G ... end G; end FACILITY; procedure TRANSFORM(U : in out REAL) is use FACILITY; begin U := F(U); ... end TRANSFORM; begin -- TOP TRANSFORM(R); ... FACILITY.G(R, S); end TOP; The body of the package FACILITY and that of the procedure TRANSFORM can be made into separate subunits of TOP. Similarly, the body of the procedure G can be made into a subunit of FACILITY as follows. Example 3: procedure TOP is type REAL is digits 10; R, S : REAL := 1.0; package FACILITY is PI : constant := 3.14159_26536; function F(X : REAL) return REAL; procedure G(Y, Z : REAL); end FACILITY; package body FACILITY is separate; -- stub of FACILITY procedure TRANSFORM(U : in out REAL) is separate; -- stub of TRANSFORM begin -- TOP TRANSFORM(R); ... FACILITY.G(R, S); end TOP; ------------------------------------------------- separate (TOP) procedure TRANSFORM(U : in out REAL) is use FACILITY; begin U := F(U); ... end TRANSFORM; ------------------------------------------------- separate (TOP) package body FACILITY is -- some local declarations followed by function F(X : REAL) return REAL is begin -- sequence of statements of F ... end F; procedure G(Y, Z : REAL) is separate; -- stub of G end FACILITY; ------------------------------------------------- with TEXT_IO; separate (TOP.FACILITY) -- full name of FACILITY procedure G(Y, Z : REAL) is -- local procedures using TEXT_IO ... begin -- sequence of statements of G ... end G; In the above example TRANSFORM and FACILITY are subunits of TOP, and G is a subunit of FACILITY. The visibility in the split version is the same as in the initial version except for one change: since TEXT_IO is only used within G, the corresponding with clause is written for G instead of for TOP. Apart from this change, the same identifiers are visible at corresponding program points in the two versions. For example, all of the following are (directly) visible within the proper body of the subunit G: the procedure TOP, the type REAL, the variables R and S, the package FACILITY and the contained named number PI and subprograms F and G. References: body stub 10.2, compilation unit 10.1, identifier 2.3, local declaration 8.1, named number 3.2, package 7, package body 7.1, procedure 6, procedure body 6.3, proper body 3.9, subprogram 6, type 3.3, variable 3.2.1, visibility 8.3, with clause 10.1.1 10.3 Order of Compilation The rules defining the order in which units can be compiled are direct consequences of the visibility rules and, in particular, of the fact that any library unit that is mentioned by the context clause of a compilation unit is visible in the compilation unit. A compilation unit must be compiled after all library units named by its context clause. A secondary unit that is a subprogram or package body must be compiled after the corresponding library unit. Any subunit of a parent compilation unit must be compiled after the parent compilation unit. If any error is detected while attempting to compile a compilation unit, then the attempted compilation is rejected and it has no effect whatsoever on the program library; the same holds for recompilations (no compilation unit can become obsolete because of such a recompilation). The order in which the compilation units of a program are compiled must be consistent with the partial ordering defined by the above rules. Similar rules apply for recompilations. A compilation unit is potentially affected by a change in any library unit named by its context clause. A secondary unit is potentially affected by a change in the corresponding library unit. The subunits of a parent compilation unit are potentially affected by a change of the parent compilation unit. If a compilation unit is successfully recompiled, the compilation units potentially affected by this change are obsolete and must be recompiled unless they are no longer needed. An implementation may be able to reduce the compilation costs if it can deduce that some of the potentially affected units are not actually affected by the change. The subunits of a unit can be recompiled without affecting the unit itself. Similarly, changes in a subprogram or package body do not affect other compilation units (apart from the subunits of the body) since these compilation units only have access to the subprogram or package specification. An implementation is only allowed to deviate from this rule for inline inclusions, for certain compiler optimizations, and for certain implementations of generic program units, as described below. - If a pragma INLINE is applied to a subprogram declaration given in a package specification, inline inclusion will only be achieved if the package body is compiled before units calling the subprogram. In such a case, inline inclusion creates a dependence of the calling unit on the package body, and the compiler must recognize this dependence when deciding on the need for recompilation. If a calling unit is compiled before the package body, the pragma may be ignored by the compiler for such calls (a warning that inline inclusion was not achieved may be issued). Similar considerations apply to a separately compiled subprogram for which an INLINE pragma is specified. - For optimization purposes, an implementation may compile several units of a given compilation in a way that creates further dependences among these compilation units. The compiler must then take these dependences into account when deciding on the need for recompilations. - An implementation may require that a generic declaration and the corresponding proper body be part of the same compilation, whether the generic unit is itself separately compiled or is local to another compilation unit. An implementation may also require that subunits of a generic unit be part of the same compilation. Examples of Compilation Order: (a) In example 1 (see 10.1.1): The procedure QUADRATIC_EQUATION must be compiled after the library packages TEXT_IO and REAL_OPERATIONS since they appear in its with clause. (b) In example 2 (see 10.1.2): The package body STOCK must be compiled after the corresponding package specification. (c) In example 2 (see 10.1.2): The specification of the package STOCK must be compiled before the procedure PROCESSOR. On the other hand, the procedure PROCESSOR can be compiled either before or after the package body STOCK. (d) In example 3 (see 10.2.1): The procedure G must be compiled after the package TEXT_IO since this package is named by the with clause of G. On the other hand, TEXT_IO can be compiled either before or after TOP. (e) In example 3 (see 10.2.1): The subunits TRANSFORM and FACILITY must be compiled after the main program TOP. Similarly, the subunit G must be compiled after its parent unit FACILITY. Notes: For library packages, it follows from the recompilation rules that a package body is made obsolete by the recompilation of the corresponding specification. If the new package specification is such that a package body is not required (that is, if the package specification does not contain the declaration of a program unit), then the recompilation of a body for this package is not required. In any case, the obsolete package body must not be used and can therefore be deleted from the program library. References: compilation 10.1, compilation unit 10.1, context clause 10.1.1, elaboration 3.9, generic body 12.2, generic declaration 12.1, generic unit 12, library unit 10.1, local declaration 8.1, name 4.1, package 7, package body 7.1, package specification 7.1, parent unit 10.2, pragma inline 6.3.2, procedure 6.1, procedure body 6.3, proper body 3.9, secondary unit 10.1, subprogram body 6.3, subprogram declaration 6.1, subprogram specification 6.1, subunit 10.2, type 3.3, variable 3.2.1, visibility 8.3, with clause 10.1.1 10.4 The Program Library Compilers are required to enforce the language rules in the same manner for a program consisting of several compilation units (and subunits) as for a program submitted as a single compilation. Consequently, a library file containing information on the compilation units of the program library must be maintained by the compiler or compiling environment. This information may include symbol tables and other information pertaining to the order of previous compilations. A normal submission to the compiler consists of the compilation unit(s) and the library file. The latter is used for checks and is updated for each compilation unit successfully compiled. Notes: A single program library is implied for the compilation units of a compilation. The possible existence of different program libraries and the means by which they are named are not concerns of the language definition; they are concerns of the programming environment. There should be commands for creating the program library of a given program or of a given family of programs. These commands may permit the reuse of units of other program libraries. Finally, there should be commands for interrogating the status of the units of a program library. The form of these commands is not specified by the language definition. References: compilation unit 10.1, context clause 10.1.1, order of compilation 10.3, program 10.1, program library 10.1, subunit 10.2, use clause 8.4, with clause 10.1.1 10.5 Elaboration of Library Units Before the execution of a main program, all library units needed by the main program are elaborated, as well as the corresponding library unit bodies, if any. The library units needed by the main program are: those named by with clauses applicable to the main program, to its body, and to its subunits; those named by with clauses applicable to these library units themselves, to the corresponding library unit bodies, and to their subunits; and so on, in a transitive manner. The elaboration of these library units and of the corresponding library unit bodies is performed in an order consistent with the partial ordering defined by the with clauses (see 10.3). In addition, a library unit mentioned by the context clause of a subunit must be elaborated before the body of the ancestor library unit of the subunit. An order of elaboration that is consistent with this partial ordering does not always ensure that each library unit body is elaborated before any other compilation unit whose elaboration necessitates that the library unit body be already elaborated. If the prior elaboration of library unit bodies is needed, this can be requested by a pragma ELABORATE. The form of this pragma is as follows: pragma ELABORATE (library_unit_simple_name {, library_unit_simple_name}); These pragmas are only allowed immediately after the context clause of a compilation unit (before the subsequent library unit or secondary unit). Each argument of such a pragma must be the simple name of a library unit mentioned by the context clause, and this library unit must have a library unit body. Such a pragma specifies that the library unit body must be elaborated before the given compilation unit. If the given compilation unit is a subunit, the library unit body must be elaborated before the body of the ancestor library unit of the subunit. The program is illegal if no consistent order can be found (that is, if a circularity exists). The elaboration of the compilation units of the program is performed in some order that is otherwise not defined by the language. References: allow 1.6, argument of a pragma 2.8, compilation unit 10.1, context clause 10.1.1, dependence between compilation units 10.3, elaboration 3.9, illegal 1.6, in some order 1.6, library unit 10.1, name 4.1, main program 10.1, pragma 2.8, secondary unit 10.1, separate compilation 10.1, simple name 4.1, subunit 10.2, with clause 10.1.1 10.6 Program Optimization Optimization of the elaboration of declarations and the execution of statements may be performed by compilers. In particular, a compiler may be able to optimize a program by evaluating certain expressions, in addition to those that are static expressions. Should one of these expressions, whether static or not, be such that an exception would be raised by its evaluation, then the code in that path of the program can be replaced by code to raise the exception; the same holds for exceptions raised by the evaluation of names and simple expressions. (See also section 11.6.) A compiler may find that some statements or subprograms will never be executed, for example, if their execution depends on a condition known to be FALSE. The corresponding object machine code can then be omitted. This rule permits the effect of conditional compilation within the language. Note: An expression whose evaluation is known to raise an exception need not represent an error if it occurs in a statement or subprogram that is never executed. The compiler may warn the programmer of a potential error. References: condition 5.3, declaration 3.1, elaboration 3.9, evaluation 4.5, exception 11, expression 4.4, false boolean value 3.5.3, program 10, raising of exceptions 11.3, statement 5, static expression 4.9, subprogram 6