Chapter 7: Debugging Open PL/I Programs

This chapter describes CodeWatch features that relate to debugging PL/I programs and contains a sample command-line debugging session of an Open PL/I program. At the end of this chapter, the listing of the program used in the sample debugging session is provided. The source of the sample program is also available on the release media.

Program Blocks

Program blocks are units of code that provide scope and context for the debugger. An Open PL/I program block is a procedure block or a BEGIN block.

Block Names

A procedure block is referred to by the name of that procedure. A begin block is referred to by its label (if present) or by the string %BEGIN followed immediately by the line number on which the block begins. For example, an unlabeled begin block that starts on line 119 of the source file is referred to as %BEGIN119.

Referencing Nested Blocks

Open PL/I program blocks may be nested. Rules for naming nested blocks are as follows:

  1. If a block defined within the compilation unit is contained within or contains the debugger's current evaluation environment, the block may be referred to simply by its name. The name may need to be qualified to make it unique within the external procedure.

    If the block contains the debugger's current evaluation environment, the search for the referenced block begins from the current environment and continues through each successive containing (parent) block until the referenced block is found.

  2. If a block is in some other external procedure, it must be qualified with at least the external procedure name, and it may require further qualification. Furthermore, a fully qualified name to a block in some other external procedure may be the same as a partially qualified block name in the current procedure. To force the debugger to search outside the current procedure, qualify the block name with %EXTERN. (This is seldom necessary if ambiguous naming is avoided.)

    For example:

    A: proc;        /* 1 */        B: proc;             /* 8 */
      B: proc;      /* 2 */          C: proc;           /* 9 */
        C: proc;    /* 3 */            D: proc;         /* 10 */
          D: proc;  /* 4 */            end D;
          end D;                     end C;
        end C;                         B: proc;         /* 11 */
      end B;                             A: proc;       /* 12 */
      C: proc:      /* 5 */                A: proc      /* 13 */
        B: proc;    /* 6 */                  B: proc;   /* 14 */
          C:proc;   /* 7 */                  end B;
          end C;                           end A;
        end B;                           end A;
      end C;                           end B;
    end A;                          end B;

The following describes how each block can be referenced given the current evaluation environment in the external procedure %EXTERN.A (block 1).

Block     
Reference
   1 A or %EXTERN.A
   2 A.B, B, or %EXTERN.A.B
   3 B.C, A.B.C, or %EXTERN.A.B.C.
   4 D, C.D, B.C.D, A.B.C.D, %EXTERN.A.B.C.D, B.D, A.B.D, %EXTERN.A.B.D, A.D, or %EXTERN.A.D
   5 C, A.C, or %EXTERN.A.C
   6 C.B, A.C.B, or %EXTERN.A.C.B
   7 C.C, C.B.C, A.C.C, %EXTERN.A.C.C, A.C.B.C, or %EXTERN.A.C.B.C
   8 %EXTERN.B
   9 %EXTERN.B.C
 10 %EXTERN.B.D, or %EXTERN.B.C.D
 11 B.B or %EXTERN.B.B
 12 B.B.A or %EXTERN.B.B.A
 13 B.A.AB.B.A.A, %EXTERN.B.A.A, or %EXTERN.B.B.A.A
 14 B.B.B B.A.B B.A.A.B, B.B.A.B, %EXTERN.B.B.B, %EXTERN.B.A.B, %EXTERN.B.A.A.B, %EXTERN.B.B.A.B, or%EXTERN.B.B.A.A.B
Table 7-1: How Blocks can be Referenced in Open PL/I

If the current evaluation environment is in the internal procedure block %EXTERN.A.B.C.D (block 4), the following is true in the debugger:

B refers to block 2
B.C refers to block 3
C refers to block 3
%EXTERN.B.A is an ambiguous reference (block 12 or 13)
%EXTERN.B.B.A       refers to block 12
%EXTERN.B.C refers to block 9

If the current evaluation environment is in the external procedure block %EXTERN.B (block 8), the following is true in the debugger:

A.B.C.D      refers to block 1
A is an ambiguous reference (block 12 or 13)
B refers to block 11
B.A refers to block 12
A.B refers to block 14
B.A.B refers to block 14

Built-in Function Support

The following PL/I built-in functions are supported by CodeWatch:

ADD COLLATE HBOUND NULL
ADDR COPY HIGH RANK
BINARY DECIMAL LBOUND SUBSTR
BIT DIMENSION     LENGTH TRIM
BYTE FIXED LOW UNSPEC
CHARACTER     FLOAT MULTIPLY     VERIFY

The following abbreviations for PL/I built-in functions are recognized:

Referencing Arrays and Aggregate Structures

Arrays and aggregate structures can be referenced in their entirety by referring to them by their array or structure name, or individual subfields or members can be referenced using the conventional PL/I syntax, as in REC_NAME.FIELD. A subfield can be referenced directly as long as its name is unique.

A specified range of an array can be evaluated using the following command-line syntax:

EVALUATE array-name [m:n]

or

EVALUATE array-name (m:n)

where m is the starting point of the array range and n is the ending point of the array range.

An asterisk (*) specifies that all elements of a dimension are to be evaluated. For example:

EVALUATE array-name[*,3:5]

or

EVALUATE array-name(*,3:5)

displays the third through fifth columns of all the rows in a two-dimensional array.

Specifying only the array name for PL/I will cause the evaluation of every element of every dimension of the array. Similarly, specifying a structure, record, or group name will cause the evaluation of every member of the group.

Support for Open PL/I Include Files

The following list describes the rules applying to CodeWatch support for Open PL/I include files. This support applies to include files that contain executable code. The rules are as follows:

Using CodeWatch with the Open PL/I Macro Preprocessor

CodeWatch can be used with PL/I programs to which the Open PL/I macro preprocessor mfpp has been applied. CodeWatch uses the original source file (rather than the expanded preprocessed output of mfpp). Stepping through macros works similarly to the include file support described for include files.

Sample CodeWatch Session Using Open PL/I

This debugging session illustrates how to use the commands and features of CodeWatch when debugging programs compiled with Open PL/I. Following the session is the source listing of the sample PL/I program. The source file for this program is also available on the CodeWatch installation media.

The sample program, primes.pl1, calculates the number of prime numbers within a given range, but it doesn't do it very well. There is a bug somewhere that causes the program to print out too many values. Observe the following output:

*** Sieve of Eratosthenes ***

Input maximum prime boundary: 
10
Number of primes found was     6
1      2      3      5      7      11

The program had been compiled using the -deb option to produce the necessary information for the debugger and the -l option to produce a listing file. It was then linked using Ipild. For example,

mfpli primes.pl1 -deb -l 
ldpli primes.o -o primes

In this sample session, comments (which are not part of the session) are the bullet items. The system prompt is $. Note that user-supplied text is in bold typewriter font. For clarity, the abbreviated form of the command is used only after the command has been previously spelled out in its entirety.

Program Listing

Compiler:  Open PL/I 08.00.B2 - Copyright (c) 2009 Micro Focus (IP) Limited
Date/Time: December 11, 2009 (15:35:27)
File:      primes.pl1
Directory: C:\Program Files\Micro Focus\Open PLI 8.0\EXAMPLES\OPEN-PLI
Options:   deb l noopt Pentium obj primes.obj list primes.lst
       1   /* Sieve of Eratosthenes: Copyright (c) 2009 Micro Focus (IP) Limited */
       2   
       3   primes: procedure options (main);
       4   
       5   %replace FALSE      by '0'B;
       6   %replace TRUE       by '1'B;
       7   
       8   %replace MAX_VALUE  by 1000;
       9   %replace MAX_PRIMES by  500;
      10   
      11   
      12   read_input: procedure (maxv);
      13   
      14       declare maxv fixed binary(31);
      15       declare instring char(4) varying;
      16   
      17       declare ok bit(1);
      18   
      19       ok = FALSE;
      20   
      21       do while (^ok);
      22           put list ('Input maximum prime boundary:');
      23           put skip;
      24           get list (instring);
      25           maxv = decimal(instring);
      26           if maxv > MAX_VALUE then do;
      27               put list ('Value too big.  Try again.');
      28               put skip;
      29           end;
      30           else do;
      31               ok = TRUE;
      32           end;
      33       end;
      34           
      35   end read_input;
      36   
      37   isprime: procedure (number,values,total) returns (fixed binary(31));
      38   
      39       declare number                fixed binary(31),
      40                   values(1:MAX_PRIMES)  fixed binary(31),
      41           total                 fixed binary(31);
      42       declare n                     fixed binary(31);
      43   
      44           do n = 1 to total;
      45           if number = values(n) then
      46                  return (number);
      47           end; 
      48   
      49           return(-1);
      50   
      51   end isprime;
      52   
      53   print_out: procedure (values,total);
      54   
      55       declare values(1:MAX_PRIMES) fixed binary(31),
      56           total                fixed binary(31);
      57   
      58       declare i fixed binary(15);
      59   
      60       put list ('Number of primes found was');
      61       if isprime (total,values,total) >= 0 then
      62           put list(' (prime itself)');
      63       put edit (total) (F(4));
      64       put skip (2);
      65   
      66       do i = 1 to total;
      67           put edit (values(i)) (F(7));
      68           if mod(i,10) = 0 then do;
      69               put skip;
      70           end;
      71       end;
      72   
      73       put skip (2);
      74   
      75   end print_out;
      76   
      77   sift: procedure (n);
      78   
      79       declare n fixed binary(31);
      80   
      81       declare (i, k, count, this_prime) fixed binary(31),
      82           flags(1:MAX_VALUE) bit(1),
      83           primes(1:MAX_PRIMES) fixed binary(31);
      84   
      85       do i = 1 to n;
      86           flags(i) = TRUE;
      87       end;
      88   
      89       count = 1;
      90       primes(1) = 1;
      91   
      92       do i = 1 to n;
      93           if flags(i) = TRUE then do;
      94               this_prime = i + 1;
      95               count = count + 1;
      96               primes(count) = this_prime;
      97               k = i + this_prime;
      98               do while (k < n);
      99                   /* cancel all multiples */
     100                   flags(k) = FALSE;
     101                   k = k + this_prime;
     102               end;
     103           end;
     104       end;
     105       call print_out(primes,count);  /* should be count - 1 */
     106   
     107   end sift;
     108   
     109       /* main procedure */
     110   
     111       declare n fixed binary(31);
     112   
     113       put skip;
     114       put list ('*** Sieve of Eratosthenes ***');
     115       put skip (2);
     116   
     117       call read_input(n);
     118   
     119       do while (n > 1);
     120           call sift(n);
     121           call read_input(n);
     122       end;
     123   
     124   end;

Copyright © 2009 Micro Focus (IP) Ltd. All rights reserved.