Software Engineers Handbook/Language Dictionary/PLI/storage classes

From Wikibooks, open books for an open world
< Software Engineers Handbook‎ | Language Dictionary/PLI
Jump to: navigation, search

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]

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]

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]

  • Every declared bound, length or size of a controlled variable may be overwriten in the allocate statement.
  • Using asteriks 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]

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]

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]

In the following example the ALLOC statement ...

  • aquires 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]

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]

  • [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;).