Software Engineers Handbook/Language Dictionary/PLI/storage classes
Note: This article requires basic knowledge of PL/I which can be found in Software Engineers Handbook/Language Dictionary/PLI.
PL/I offers 4 different storage classes:
- STATIC
- AUTOMATIC (abbr: AUTO)
- CONTROLLED (abbr: CTL)
- BASED
Simplified spoken static and automatic variables will be allocated and initialised "by the machine",
controlled and based variables have to be managed "by the program(mer)".
Static and Automatic Variables
editStatic variables will be allocated and initialised at program start, they remain in storage until program termination[1].
As a consequence of this a static variable which is declared local within a procedure will not loose its value between successive invocations of this procedure.
Automatic variables which are declared global behaves like static variables.
Automatic variables which are declared local within a procedure will be allocated and initialised at every invocation of this procedure, their storage will be released if this procedure terminates.
Local variables are automatic by default[2].
example: proc options ( main ); call static_memory ( 7 ); call static_memory ( 0 ); /* output: 7 */ call auto_memory ( 7 ); call auto_memory ( 0 ); /* output: 1 */ static_memory: proc ( parm ); dcl parm bin fixed (15); dcl memory bin fixed (15) init ( 1 ) STATIC; if parm = 0 then put skip list ( memory ); else memory = parm; end static_memory; auto_memory: proc ( parm ); dcl parm bin fixed (15); dcl memory bin fixed (15) init ( 1 ); if parm = 0 then put skip list ( memory ); else memory = parm; end auto_memory; end example;
Controlled Variables
editIf a variable is declared as Controlled the declaration only describes the structure of the variable but no storage allocation will be done automatically.
The acquirement of storage for a controlled variable must be done with a ALLOCATE statement (abbr: ALLOC)[3], the deallocation has to be done with a FREE statement[4].
A controlled variable may be allocated multiple but only the actual generation of it can be directly accessed.
example: proc options ( main ); dcl number bin fixed (15) CONTROLLED; ALLOCATE number; /* create the 1st generation of number */ number = 111; put skip list ( number ); /* output: 111 */ ALLOCATE number; /* create the 2nd generation of number */ number = 222; put skip list ( number ); /* output: 222 */ FREE number; /* now 1st generation becomes actual again */ put skip list ( number ); /* output: 111 */ FREE number; /* now the value of number will be undefined */ end example;
Local variables in a procedure which are controlled remains allocated between successive invocations of this procedure.
example: proc options ( main ); call sub_proc ( 333 ); call sub_proc ( - 1 ); /* output: 333 */ sub_proc: proc ( num_val ); dcl num_val bin fixed (15); dcl num_ctl bin fixed (15) CTL; if num_val >= 0 then do; alloc num_ctl; num_ctl = num_val; end; else do; put skip list ( num_ctl ); free num_ctl; end; end sub_proc; end example;
Adjustable Bounds etc.
edit- Every declared bound, length or size of a controlled variable may be overwritten in the allocate statement.
- Using asterisks notation in a declaration forces explicid definition in the 1st allocate statement.
- Using asteriks notation in an allocate statement inherits the values of the actual generartion.
example: proc options ( main ); dcl stringlist (3) char (10) controlled; dcl single_string char (*) controlled; dcl 1 structure controlled, 2 string_1 char (10), 2 string_2 char (10); dcl allocation builtin; allocate stringlist; /* 1st generation: 3 strings of length 10 */ allocate stringlist (5); /* 2nd generation: 5 strings of length 10 */ allocate stringlist (5) char (20); /* 3rd generation: 5 strings of length 20 */ allocate stringlist (*) char (*); /* 4th generation: like 3rd generation */ do while ( allocation ( stringlist ) > 0 ); free stringlist; end; allocate single_string char (50); /* Explicid value must be given because declaration contains asteriks */ free single_string; allocate structure; /* 1st generation: length ( string_1 ) = length ( string_2 ) = 10 */ allocate 1 structure, /* 2nd generation with ... */ 2 string_1 char (70), /* length ( string_1 ) = 70 */ 2 string_2 char (80); /* length ( string_2 ) = 80 */ do while ( allocation ( structure ) > 0 ); free structure; end; end example;
Based Variables
editIf a variable is declared as Based the declaration only describes the structure of the variable but no storage allocation will be done automatically.
- The acquirement of storage for a based variable may be done with a ALLOCATE statement (abbr: ALLOC)[3], the deallocation may be done with a FREE statement[4].
- Alternatively a based variable may be mapped to still existing storage.
Mapping to Existing Storage
editexample: proc options ( main ); dcl a_char char (03); dcl b_char char (03) based ( addr ( a_char ) ); dcl c_char char (03) based ( c_pointer ); dcl d_char char (03) based ; dcl x_char char (03) based ( x_pointer ); dcl y_char char (03) based ( y_pointer ); dcl z_char char (03) based ; dcl c_pointer pointer; dcl x_pointer pointer; dcl y_pointer pointer; dcl addr builtin; a_char = 'AAA'; /* now a_char has the value 'AAA' */ b_char = 'BBB'; /* now a_char has the value 'BBB' */ c_pointer = addr ( a_char ); c_char = 'CCC'; /* now a_char has the value 'CCC' */ addr ( a_char ) -> d_char = 'DDD'; /* now a_char has the value 'DDD' */ allocate x_char; /*================================*/ x_char = 'XXX'; /* now x_char has the value 'XXX' */ y_pointer = x_pointer; y_char = 'YYY'; /* now x_char has the value 'YYY' */ addr ( y_char ) -> z_char = 'ZZZ'; /* now x_char has the value 'ZZZ' */ end example;
/* The following procedure gets a char_var variable "string" */ /* as by-reference parameter and trims all spaces from the right. */ /* Structure of a char_var variable: */ /* 2 bytes containing the string length as bin fixed (15) */ /* followed by the characters */ right_trim: proc ( string ); dcl string char (*) varying; dcl s_length bin fixed (15) based ( addr ( string ) ); dcl s_ch ( - 1 : 32767 ) char (01) based ( addr ( string ) ); do while ( s_ch ( s_length ) = ' ' ); s_length = s_length - 1; end; end right_trim;
Allocating
editIn the following example the ALLOC statement ...
- acquires storage for the variable B_VAR
- stores the address of the aquired storage in B_PTR
example: proc options ( main ); dcl B_VAR char (25) BASED ( B_PTR ); dcl B_PTR pointer; ALLOC B_VAR; ............ FREE B_VAR; end example;
A based variable may be allocated multiple times, every generation can be directly accessed through its individuell pointer.
example: proc options ( main );
dcl 1 first_item,
2 value char (01),
2 next pointer init ( null );
dcl 1 last_item like first_item based ( last_ptr );
/* "like" means: last_item has the same structure as first_item */
dcl last_ptr pointer;
dcl ( addr , null ) builtin;
last_ptr = addr ( first_item );
call append_to_simple_list ( '1' );
call append_to_simple_list ( '2' );
call append_to_simple_list ( '3' );
call append_to_simple_list ( '4' );
put skip list ( fifo_of_simple_list ); /* output: '1234' */
call free_simple_list;
append_to_simple_list: proc ( item_value );
dcl item_value char (01);
dcl 1 alloc_item like first_item based ( alloc_ptr );
dcl alloc_ptr pointer;
last_item.value = item_value;
ALLOCATE alloc_item;
last_item.next = alloc_ptr;
last_ptr = alloc_ptr;
last_item.next = null;
end append_to_simple_list;
fifo_of_simple_list: proc returns ( char (20) varying );
dcl list_sum char (20) varying;
dcl 1 read_item like first_item based ( read_ptr );
dcl read_ptr pointer;
list_sum = '';
read_ptr = addr ( first_item );
do while ( read_item.next ¬= null );
list_sum = list_sum || read_item.value;
read_ptr = read_item.next;
end;
return ( list_sum );
end fifo_of_simple_list;
free_simple_list: proc;
dcl 1 free_item like first_item based ( free_ptr );
dcl free_ptr pointer;
dcl next_ptr pointer;
next_ptr = first_item.next;
do while ( next_ptr ¬= null );
free_ptr = next_ptr;
next_ptr = free_item.next;
FREE free_item;
end;
first_item.next = null;
end free_simple_list;
end example;
Allocating with Adjustable Bounds etc.
editA based variable may be a self-defining structure, i.e. a structure for which values for bound, length or size must be defined in the allocate statement.
To make e.g. a bound adjustable its fixed value in the declaration has to replaced with
expr REFER ( structure_var )
- expr is a expression which will be calculated at allocation time and determines the storage value.
- structure_var is a variable within the based structure which stores the calculated value.
example: proc options ( main ); dcl 1 based_stru, 2 string_count bin fixed (15), 2 string_length bin fixed (15), 2 list ( alloc_count REFER ( string_count ) ) char ( alloc_length REFER ( string_length ) ); dcl alloc_count bin fixed (15); dcl alloc_length bin fixed (15); dcl length builtin; alloc_count = 5; alloc_length = 72; allocate based_stru; /* now list contains 5 strings of length 72 */ put skip list ( based_stru.string_length ); /* output will be 72, the stored calculated value. */ put skip list ( length ( based_stru.list ( 1 ) ) ); /* output will be 72, the length of an allocated string. */ end example;
example: proc options ( main ); dcl 1 based_stru, 2 rows bin fixed (15), 2 columns bin fixed (15), 2 matrix ( alloc_val * 2 REFER ( rows ) , alloc_val + 5 REFER ( columns ) ) bin fixed (15); dcl alloc_val bin fixed (15); alloc_val = 10; allocate based_stru; /* now matrix contains 20 rows and 15 columns */ end example;
Notes
edit- [1] local static variables in fetched procedures will only be allocated between the fetch and the release statement.
- [2] in PL/I default values may be altered using the DEFAULT statement.
- [3] both controlled and based variables can be allocated in the same statement (e.g.: alloc ctl_var_1 (20), ctl_var_2, based_var;).
- [4] both controlled and based variables can be freed in the same statement (e.g.: free ctl_var_1, ctl_var_2, based_var;).