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
[edit | edit source]Static 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
[edit | edit source]If 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 | edit source]- 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
[edit | edit source]If 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
[edit | edit source]example: 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
[edit | edit source]In 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.
[edit | edit source]A 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 | edit source]- [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;).