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. 5. Statements A statement defines an action to be performed; the process by which a statement achieves its action is called execution of the statement. This chapter describes the general rules applicable to all statements. Some specific statements are discussed in later chapters. Procedure call statements are described in Chapter 6 on subprograms. Entry call, delay, accept, select, and abort statements are described in Chapter 9 on tasks. Raise statements are described in Chapter 11 on exceptions, and code statements in Chapter 13. The remaining forms of statements are presented in this chapter. References: abort statement 9.10, accept statement 9.5, code statement 13.8, delay statement 9.6, entry call statement 9.5, procedure call statement 6.4, raise statement 11.3, select statement 9.7 5.1 Simple and Compound Statements - Sequences of Statements A statement is either simple or compound. A simple statement encloses no other statement. A compound statement can enclose simple statements and other compound statements. sequence_of_statements ::= statement {statement} statement ::= {label} simple_statement | {label} compound_statement simple_statement ::= null_statement | assignment_statement | procedure_call_statement | exit_statement | return_statement | goto_statement | entry_call_statement | delay_statement | abort_statement | raise_statement | code_statement compound_statement ::= if_statement | case_statement | loop_statement | block_statement | accept_statement | select_statement label ::= <> null_statement ::= null; A statement is said to be labeled by the label name of any label of the statement. A label name, and similarly a loop or block name, is implicitly declared at the end of the declarative part of the innermost block statement, subprogram body, package body, task body, or generic body that encloses the labeled statement, the named loop statement, or the named block statement, as the case may be. For a block statement without a declarative part, an implicit declarative part (and preceding declare) is assumed. The implicit declarations for different label names, loop names, and block names occur in the same order as the beginnings of the corresponding labeled statements, loop statements, and block statements. Distinct identifiers must be used for all label, loop, and block names that are implicitly declared within the body of a program unit, including within block statements enclosed by this body, but excluding within other enclosed program units (a program unit is either a subprogram, a package, a task unit, or a generic unit). Execution of a null statement has no other effect than to pass to the next action. The execution of a sequence of statements consists of the execution of the individual statements in succession until the sequence is completed, or a transfer of control takes place. A transfer of control is caused either by the execution of an exit, return, or goto statement; by the selection of a terminate alternative; by the raising of an exception; or (indirectly) by the execution of an abort statement. Examples of labeled statements: <> <> <> <> null; <> X := 1; Note: The scope of a declaration starts at the place of the declaration itself (see 8.2). In the case of a label, loop, or block name, it follows from this rule that the scope of the implicit declaration starts before the first explicit occurrence of the corresponding name, since this occurrence is either in a statement label, a loop statement, a block statement, or a goto statement. An implicit declaration in a block statement may hide a declaration given in an outer program unit or block statement (according to the usual rules of hiding explained in section 8.3). References: abort statement 9.10, accept statement 9.5, assignment statement 5.2, block name 5.6, block statement 5.6, case statement 5.4, code statement 13.8, declaration 3.1, declarative part 3.9, delay statement 9.6, entry call statement 9.5, exception 11, exit statement 5.7, generic body 12.1, generic unit 12, goto statement 5.9, hiding 8.3, identifier 2.3, if statement 5.3, implicit declaration 3.1, loop name 5.5, loop statement 5.5, package 7, package body 7.1, procedure call statement 6.4, program unit 6, raise statement 11.3, raising of exceptions 11, return statement 5.8, scope 8.2, select statement 9.7, simple name 4.1, subprogram 6, subprogram body 6.3, task 9, task body 9.1, task unit 9.1, terminate alternative 9.7.1, terminated task 9.4 5.2 Assignment Statement An assignment statement replaces the current value of a variable with a new value specified by an expression. The named variable and the right-hand side expression must be of the same type; this type must not be a limited type. assignment_statement ::= variable_name := expression; For the execution of an assignment statement, the variable name and the expression are first evaluated, in some order that is not defined by the language. A check is then made that the value of the expression belongs to the subtype of the variable, except in the case of a variable that is an array (the assignment then involves a subtype conversion as described in section 5.2.1). Finally, the value of the expression becomes the new value of the variable. The exception CONSTRAINT_ERROR is raised if the above-mentioned subtype check fails; in such a case the current value of the variable is left unchanged. If the variable is a subcomponent that depends on discriminants of an unconstrained record variable, then the execution of the assignment is erroneous if the value of any of these discriminants is changed by this execution. Examples: VALUE := MAX_VALUE - 1; SHADE := BLUE; NEXT_FRAME(F)(M, N) := 2.5; -- see 4.1.1 U := DOT_PRODUCT(V, W); -- see 6.5 WRITER := (STATUS => OPEN, UNIT => PRINTER, LINE_COUNT => 60); -- see 3.7.3 NEXT_CAR.all := (72074, null); -- see 3.8.1 Examples of constraint checks: I, J : INTEGER range 1 .. 10; K : INTEGER range 1 .. 20; ... I := J; -- identical ranges K := J; -- compatible ranges J := K; -- will raise the exception CONSTRAINT_ERROR if K > 10 Notes: The values of the discriminants of an object designated by an access value cannot be changed (not even by assigning a complete value to the object itself) since such objects, created by allocators, are always constrained (see 4.8); however, subcomponents of such objects may be unconstrained. If the right-hand side expression is either a numeric literal or named number, or an attribute that yields a result of type universal_integer or universal_real, then an implicit type conversion is performed, as described in section 4.6. The determination of the type of the variable of an assignment statement may require consideration of the expression if the variable name can be interpreted as the name of a variable designated by the access value returned by a function call, and similarly, as a component or slice of such a variable (see section 8.7 for the context of overload resolution). References: access type 3.8, allocator 4.8, array 3.6, array assignment 5.2.1, component 3.6 3.7, constraint_error exception 11.1, designate 3.8, discriminant 3.7.1, erroneous 1.6, evaluation 4.5, expression 4.4, function call 6.4, implicit type conversion 4.6, name 4.1, numeric literal 2.4, object 3.2, overloading 6.6 8.7, slice 4.1.2, subcomponent 3.3, subtype 3.3, subtype conversion 4.6, type 3.3, universal_integer type 3.5.4, universal_real type 3.5.6, variable 3.2.1 5.2.1 Array Assignments If the variable of an assignment statement is an array variable (including a slice variable), the value of the expression is implicitly converted to the subtype of the array variable; the result of this subtype conversion becomes the new value of the array variable. This means that the new value of each component of the array variable is specified by the matching component in the array value obtained by evaluation of the expression (see 4.5.2 for the definition of matching components). The subtype conversion checks that for each component of the array variable there is a matching component in the array value, and vice versa. The exception CONSTRAINT_ERROR is raised if this check fails; in such a case the value of each component of the array variable is left unchanged. Examples: A : STRING(1 .. 31); B : STRING(3 .. 33); ... A := B; -- same number of components A(1 .. 9) := "tar sauce"; A(4 .. 12) := A(1 .. 9); -- A(1 .. 12) = "tartar sauce" Notes: Array assignment is defined even in the case of overlapping slices, because the expression on the right-hand side is evaluated before performing any component assignment. In the above example, an implementation yielding A(1 .. 12) = "tartartartar" would be incorrect. The implicit subtype conversion described above for assignment to an array variable is performed only for the value of the right-hand side expression as a whole; it is not performed for subcomponents that are array values. References: array 3.6, assignment 5.2, constraint_error exception 11.1, matching array components 4.5.2, slice 4.1.2, subtype conversion 4.6, type 3.3, variable 3.2.1 5.3 If Statements An if statement selects for execution one or none of the enclosed sequences of statements, depending on the (truth) value of one or more corresponding conditions. if_statement ::= if condition then sequence_of_statements {elsif condition then sequence_of_statements} [else sequence_of_statements] end if; condition ::= boolean_expression An expression specifying a condition must be of a boolean type. For the execution of an if statement, the condition specified after if, and any conditions specified after elsif, are evaluated in succession (treating a final else as elsif TRUE then), until one evaluates to TRUE or all conditions are evaluated and yield FALSE. If one condition evaluates to TRUE, then the corresponding sequence of statements is executed; otherwise none of the sequences of statements is executed. Examples: if MONTH = DECEMBER and DAY = 31 then MONTH := JANUARY; DAY := 1; YEAR := YEAR + 1; end if; if LINE_TOO_SHORT then raise LAYOUT_ERROR; elsif LINE_FULL then NEW_LINE; PUT(ITEM); else PUT(ITEM); end if; if MY_CAR.OWNER.VEHICLE /= MY_CAR then -- see 3.8 REPORT ("Incorrect data"); end if; References: boolean type 3.5.3, evaluation 4.5, expression 4.4, sequence of statements 5.1 5.4 Case Statements A case statement selects for execution one of a number of alternative sequences of statements; the chosen alternative is defined by the value of an expression. case_statement ::= case expression is case_statement_alternative {case_statement_alternative} end case; case_statement_alternative ::= when choice {| choice } => sequence_of_statements The expression must be of a discrete type which must be determinable independently of the context in which the expression occurs, but using the fact that the expression must be of a discrete type. Moreover, the type of this expression must not be a generic formal type. Each choice in a case statement alternative must be of the same type as the expression; the list of choices specifies for which values of the expression the alternative is chosen. If the expression is the name of an object whose subtype is static, then each value of this subtype must be represented once and only once in the set of choices of the case statement, and no other value is allowed; this rule is likewise applied if the expression is a qualified expression or type conversion whose type mark denotes a static subtype. Otherwise, for other forms of expression, each value of the (base) type of the expression must be represented once and only once in the set of choices, and no other value is allowed. The simple expressions and discrete ranges given as choices in a case statement must be static. A choice defined by a discrete range stands for all values in the corresponding range (none if a null range). The choice others is only allowed for the last alternative and as its only choice; it stands for all values (possibly none) not given in the choices of previous alternatives. A component simple name is not allowed as a choice of a case statement alternative. The execution of a case statement consists of the evaluation of the expression followed by the execution of the chosen sequence of statements. Examples: case SENSOR is when ELEVATION => RECORD_ELEVATION(SENSOR_VALUE); when AZIMUTH => RECORD_AZIMUTH (SENSOR_VALUE); when DISTANCE => RECORD_DISTANCE (SENSOR_VALUE); when others => null; end case; case TODAY is when MON => COMPUTE_INITIAL_BALANCE; when FRI => COMPUTE_CLOSING_BALANCE; when TUE .. THU => GENERATE_REPORT(TODAY); when SAT .. SUN => null; end case; case BIN_NUMBER(COUNT) is when 1 => UPDATE_BIN(1); when 2 => UPDATE_BIN(2); when 3 | 4 => EMPTY_BIN(1); EMPTY_BIN(2); when others => raise ERROR; end case; Notes: The execution of a case statement chooses one and only one alternative, since the choices are exhaustive and mutually exclusive. Qualification of the expression of a case statement by a static subtype can often be used to limit the number of choices that need be given explicitly. An others choice is required in a case statement if the type of the expression is the type universal_integer (for example, if the expression is an integer literal), since this is the only way to cover all values of the type universal_integer. References: base type 3.3, choice 3.7.3, context of overload resolution 8.7, discrete type 3.5, expression 4.4, function call 6.4, generic formal type 12.1, conversion 4.6, discrete type 3.5, enumeration literal 3.5.1, expression 4.4, name 4.1, object 3.2.1, overloading 6.6 8.7, qualified expression 4.7, sequence of statements 5.1, static discrete range 4.9, static subtype 4.9, subtype 3.3, type 3.3, type conversion 4.6, type mark 3.3.2 5.5 Loop Statements A loop statement includes a sequence of statements that is to be executed repeatedly, zero or more times. loop_statement ::= [loop_simple_name:] [iteration_scheme] loop sequence_of_statements end loop [loop_simple_name]; iteration_scheme ::= while condition | for loop_parameter_specification loop_parameter_specification ::= identifier in [reverse] discrete_range If a loop statement has a loop simple name, this simple name must be given both at the beginning and at the end. A loop statement without an iteration scheme specifies repeated execution of the sequence of statements. Execution of the loop statement is complete when the loop is left as a consequence of the execution of an exit statement, or as a consequence of some other transfer of control (see 5.1). For a loop statement with a while iteration scheme, the condition is evaluated before each execution of the sequence of statements; if the value of the condition is TRUE, the sequence of statements is executed, if FALSE the execution of the loop statement is complete. For a loop statement with a for iteration scheme, the loop parameter specification is the declaration of the loop parameter with the given identifier. The loop parameter is an object whose type is the base type of the discrete range (see 3.6.1). Within the sequence of statements, the loop parameter is a constant. Hence a loop parameter is not allowed as the (left-hand side) variable of an assignment statement. Similarly the loop parameter must not be given as an out or in out parameter of a procedure or entry call statement, or as an in out parameter of a generic instantiation. For the execution of a loop statement with a for iteration scheme, the loop parameter specification is first elaborated. This elaboration creates the loop parameter and evaluates the discrete range. If the discrete range is a null range, the execution of the loop statement is complete. Otherwise, the sequence of statements is executed once for each value of the discrete range (subject to the loop not being left as a consequence of the execution of an exit statement or as a consequence of some other transfer of control). Prior to each such iteration, the corresponding value of the discrete range is assigned to the loop parameter. These values are assigned in increasing order unless the reserved word reverse is present, in which case the values are assigned in decreasing order. Example of a loop statement without an iteration scheme: loop GET(CURRENT_CHARACTER); exit when CURRENT_CHARACTER = '*'; end loop; Example of a loop statement with a while iteration scheme: while BID(N).PRICE < CUT_OFF.PRICE loop RECORD_BID(BID(N).PRICE); N := N + 1; end loop; Example of a loop statement with a for iteration scheme: for J in BUFFER'RANGE loop -- legal even with a null range if BUFFER(J) /= SPACE then PUT(BUFFER(J)); end if; end loop; Example of a loop statement with a loop simple name: SUMMATION: while NEXT /= HEAD loop -- see 3.8 SUM := SUM + NEXT.VALUE; NEXT := NEXT.SUCC; end loop SUMMATION; Notes: The scope of a loop parameter extends from the loop parameter specification to the end of the loop statement, and the visibility rules are such that a loop parameter is only visible within the sequence of statements of the loop. The discrete range of a for loop is evaluated just once. Use of the reserved word reverse does not alter the discrete range, so that the following iteration schemes are not equivalent; the first has a null range. for J in reverse 1 .. 0 for J in 0 .. 1 Loop names are also used in exit statements, and in expanded names (in a prefix of the loop parameter). References: actual parameter 6.4.1, assignment statement 5.2, base type 3.3, bound of a range 3.5, condition 5.3, constant 3.2.1, context of overload resolution 8.7, conversion 4.6, declaration 3.1, discrete range 3.6.1, elaboration 3.1, entry call statement 9.5, evaluation 4.5, exit statement 5.7, expanded name 4.1.3, false boolean value 3.5.3, generic actual parameter 12.3, generic instantiation 12.3, goto statement 5.9, identifier 2.3, integer type 3.5.4, null range 3.5, object 3.2.1, prefix 4.1, procedure call 6.4, raising of exceptions 11, reserved word 2.9, return statement 5.8, scope 8.2, sequence of statements 5.1, simple name 4.1, terminate alternative 9.7.1, true boolean value 3.5.3 3.5.4, visibility 8.3 5.6 Block Statements A block statement encloses a sequence of statements optionally preceded by a declarative part and optionally followed by exception handlers. block_statement ::= [block_simple_name:] [declare declarative_part] begin sequence_of_statements [exception exception_handler {exception_handler}] end [block_simple_name]; If a block statement has a block simple name, this simple name must be given both at the beginning and at the end. The execution of a block statement consists of the elaboration of its declarative part (if any) followed by the execution of the sequence of statements. If the block statement has exception handlers, these service corresponding exceptions that are raised during the execution of the sequence of statements (see 11.2). Example: SWAP: declare TEMP : INTEGER; begin TEMP := V; V := U; U := TEMP; end SWAP; Notes: If task objects are declared within a block statement whose execution is completed, the block statement is not left until all its dependent tasks are terminated (see 9.4). This rule applies also to a completion caused by an exit, return, or goto statement; or by the raising of an exception. Within a block statement, the block name can be used in expanded names denoting local entities such as SWAP.TEMP in the above example (see 4.1.3 (f)). References: declarative part 3.9, dependent task 9.4, exception handler 11.2, exit statement 5.7, expanded name 4.1.3, goto statement 5.9, raising of exceptions 11, return statement 5.8, sequence of statements 5.1, simple name 4.1, task object 9.2 5.7 Exit Statements An exit statement is used to complete the execution of an enclosing loop statement (called the loop in what follows); the completion is conditional if the exit statement includes a condition. exit_statement ::= exit [loop_name] [when condition]; An exit statement with a loop name is only allowed within the named loop, and applies to that loop; an exit statement without a loop name is only allowed within a loop, and applies to the innermost enclosing loop (whether named or not). Furthermore, an exit statement that applies to a given loop must not appear within a subprogram body, package body, task body, generic body, or accept statement, if this construct is itself enclosed by the given loop. For the execution of an exit statement, the condition, if present, is first evaluated. Exit from the loop then takes place if the value is TRUE or if there is no condition. Examples: for N in 1 .. MAX_NUM_ITEMS loop GET_NEW_ITEM(NEW_ITEM); MERGE_ITEM(NEW_ITEM, STORAGE_FILE); exit when NEW_ITEM = TERMINAL_ITEM; end loop; MAIN_CYCLE: loop -- initial statements exit MAIN_CYCLE when FOUND; -- final statements end loop MAIN_CYCLE; Note: Several nested loops can be exited by an exit statement that names the outer loop. References: accept statement 9.5, condition 5.3, evaluation 4.5, generic body 12.1, loop name 5.5, loop statement 5.5, package body 7.1, subprogram body 6.3, true boolean value 3.5.3 5.8 Return Statements A return statement is used to complete the execution of the innermost enclosing function, procedure, or accept statement. return_statement ::= return [expression]; A return statement is only allowed within the body of a subprogram or generic subprogram, or within an accept statement, and applies to the innermost (enclosing) such construct; a return statement is not allowed within the body of a task unit, package, or generic package enclosed by this construct (on the other hand, it is allowed within a compound statement enclosed by this construct and, in particular, in a block statement). A return statement for an accept statement or for the body of a procedure or generic procedure must not include an expression. A return statement for the body of a function or generic function must include an expression. The value of the expression defines the result returned by the function. The type of this expression must be the base type of the type mark given after the reserved word return in the specification of the function or generic function (this type mark defines the result subtype). For the execution of a return statement, the expression (if any) is first evaluated and a check is made that the value belongs to the result subtype. The execution of the return statement is thereby completed if the check succeeds; so also is the execution of the subprogram or of the accept statement. The exception CONSTRAINT_ERROR is raised at the place of the return statement if the check fails. Examples: return; -- in a procedure return KEY_VALUE(LAST_INDEX); -- in a function Note: If the expression is either a numeric literal or named number, or an attribute that yields a result of type universal_integer or universal_real, then an implicit conversion of the result is performed as described in section 4.6. References: accept statement 9.5, attribute A, block statement 5.6, constraint_error exception 11.1, expression 4.4, function body 6.3, function call 6.4, generic body 12.1, implicit type conversion 4.6, named number 3.2, numeric literal 2.4, package body 7.1, procedure body 6.3, reserved word 2.9, result subtype 6.1, subprogram body 6.3, subprogram specification 6.1, subtype 3.3, task body 9.1, type mark 3.3.2, universal_integer type 3.5.4, universal_real type 3.5.6 5.9 Goto Statements A goto statement specifies an explicit transfer of control from this statement to a target statement named by a label. goto_statement ::= goto label_name; The innermost sequence of statements that encloses the target statement must also enclose the goto statement (note that the goto statement can be a statement of an inner sequence). Furthermore, if a goto statement is enclosed by an accept statement or the body of a program unit, then the target statement must not be outside this enclosing construct; conversely, it follows from the previous rule that if the target statement is enclosed by such a construct, then the goto statement cannot be outside. The execution of a goto statement transfers control to the named target statement. Note: The above rules allow transfer of control to a statement of an enclosing sequence of statements but not the reverse. Similarly, they prohibit transfers of control such as between alternatives of a case statement, if statement, or select statement; between exception handlers; or from an exception handler of a frame back to the sequence of statements of this frame. Example: <> if A(I) < ELEMENT then if LEFT(I) /= 0 then I := LEFT(I); goto COMPARE; end if; -- some statements end if; References: accept statement 9.5, block statement 5.6, case statement 5.4, compound statement 5.1, exception handler 11.2, frame 11.2, generic body 12.1, if statement 5.3, label 5.1, package body 7.1, program unit 6, select statement 9.7, sequence of statements 5.1, statement 5.1, subprogram body 6.3, task body 9.1, transfer of control 5.1