Kednos PL/I for OpenVMS Systems
Reference Manual


Previous Contents Index

5.6 Controlled Variables

A controlled variable is a variable whose actual storage is allocated and freed dynamically in generations, of which only the most recent is accessible to the program. Controlled variables are declared with the CONTROLLED attribute. A controlled variable can be a scalar, array, area, or major structure variable possessing any of the attributes that do not conflict with the CONTROLLED attribute. See Section 2.2.11 for information about the CONTROLLED attribute.

The CONTROLLED attribute cannot be applied to minor structures, members of structures, parameters, or descriptions in an ENTRY or RETURNS attribute.

A controlled variable has no storage assigned to it until an ALLOCATE statement allocates storage for it. Each storage assignment is a generation of the variable. Subsequent ALLOCATE statements allocate subsequent generations. At any time in the program's execution, a reference to a controlled variable is a reference to the most recent generation of that variable, that is, the generation created by the most recent ALLOCATE statement.

The FREE statement frees the most recent generation of a controlled variable. If an attempt is made to free a controlled variable for which no generation exists (or to refer to such a variable), PL/I signals the ERROR condition. The following example shows the use of controlled variables:


CONT: PROCEDURE OPTIONS (MAIN); 
 
DECLARE STR CHARACTER (10) CONTROLLED; 
 
    ALLOCATE STR; 
    STR = 'First'; 
    ALLOCATE STR; 
    STR = 'Second'; 
    ALLOCATE STR; 
    STR = 'Third'; 
    PUT SKIP LIST (STR); 
    FREE STR; 
    PUT SKIP LIST (STR); 
    FREE STR; 
    PUT SKIP LIST (STR); 
    FREE STR; 
 
END; 

The output of this program is as follows:


Third 
Second 
First 

5.6.1 Using the ALLOCATION Built-In Function

Because only the most recent generation of a controlled variable is available to a program, controlled variables provide an easy way to implement a stack. The ALLOCATE statement is equivalent to a push operation, and the FREE statement is equivalent to a pop operation. The ALLOCATION built-in function returns the number of generations of a variable, so you can use it to find out if the stack is empty. For example:


DECLARE NEXT_MOVE CHARACTER(5) CONTROLLED, 
    DIRECTIONS(4) CHARACTER(5) INITIAL( 
    'North','East','South','West'), 
    D FIXED BINARY (7); 
       .
       .
       .
    ALLOCATE NEXT_MOVE;         /* Part of a loop that reports */ 
    NEXT_MOVE = DIRECTIONS(D);  /* moves in reverse order      */ 
       .
       .
       .
    DO WHILE                    /* Print moves in correct order */ 
        (ALLOCATION(NEXT_MOVE) ^= 0); 
        PUT SKIP LIST ('Go ', NEXT_MOVE); 
        FREE NEXT_MOVE; 
    END; 

See Section 11.4.7 for more information about the ALLOCATION built-in function.

5.6.2 Using the ADDR Built-In Function

You can use a controlled variable as the argument of the ADDR built-in function. If a generation exists, ADDR returns a pointer to it. If no generation of the variable exists, ADDR returns the null pointer. Thus, you can use ADDR to preserve a pointer to a generation of a controlled variable that later becomes hidden under further generations, as in the following example:


DECLARE STOPS CHARACTER (20) VARYING CONTROLLED, 
    MIDPOINT CHARACTER (20) VARYING BASED (P), 
    P POINTER; 
       .
       .
       .
    ALLOCATE STOPS; 
    STOPS = CURRENT_LOC; 
    IF I = 5 THEN P = ADDR(STOPS); 
       .
       .
       .
    PUT SKIP LIST ( 
        'End reached!  Halfway point was', MIDPOINT); 

At a certain point during the execution of this program, the ADDR built-in function captures the address of the current generation of STOPS and assigns it to P. After more generations of STOPS have been allocated, MIDPOINT (which is based on P) has the value of that same intermediate generation of STOPS.

Note that the value of P (and therefore of MIDPOINT) is valid only so long as the intermediate generation of STOPS to which P points is allocated. As soon as that generation is freed, the value of P becomes invalid, and it must not be used in a pointer-qualified reference until it is reassigned.

A controlled variable cannot be used in a pointer-qualified reference. In the previous example, a reference like the following would be illegal:


P->STOPS 

5.7 Dynamically Allocated Variables

This section describes the mechanisms for dynamically allocating storage.

5.7.1 ALLOCATE Statement

The ALLOCATE statement obtains storage for a based or controlled variable and sets (with based variables) a locator variable equal to the address of the allocated storage. The format of the ALLOCATE statement is as follows:


allocate-item

The syntax of the allocate item is:

variable-reference [SET(locator-reference)] [IN(area-reference)] 

variable-reference

A based or controlled variable for which storage is to be allocated. The variable can be any scalar value, array, area, or major structure variable; it must be declared with the BASED or CONTROLLED attribute.

SET(locator-reference)

The specification of a pointer or offset variable (for based variables) that is assigned the value of the location of the allocated storage. If the SET option is omitted, the based variable must be declared with BASED(locator-reference); the variable designated by that locator reference is assigned the location of the allocated storage.

You cannot use the SET option to allocate controlled variables.

IN(area-reference)

The specification