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 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.
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.
Open PL/I program blocks may be nested. Rules for naming nested blocks are as follows:
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.
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 |
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 |
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:
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.
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:
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.
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.
$ cwcmd primes
******************************************************************************
* CodeWatch, 08.00 *
* ---------------- *
* Copyright 2009 Micro Focus (IP) Limited *
******************************************************************************
Initial evaluation environment is PRIMES:(inactive)CodeWatch> FIND main
109: /* main procedure */CodeWatch> PRINT 15
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;CodeWatch> BREAK 119CodeWatch> CONTINUE *** Sieve of Eratosthenes *** Input maximum prime boundary: 10 Break at PRIMES\119
CodeWatch> P 119: do while (n > 1); CodeWatch> EVALUATE n N = 10 {fixed binary (31)}
CodeWatch> TYPE n
N fixed binary (31) automaticCodeWatch> DSTEP [P] CodeWatch> STEP Step at PRIMES\120 120: call sift(n);
CodeWatch> S IN
Step at PRIMES.SIFT\%ENTRY
77: sift: procedure (n);CodeWatch> ARGUMENTS
N = 10 {fixed binary (31)}CodeWatch> STACK /ALL
Stack contains 5 frame(s).
Current execution point is PRIMES.SIFT\%ENTRY
5: Owner is "PRIMES.SIFT"
Called from PRIMES\120
4: Owner is "PRIMES"
Main programCodeWatch> POINT 98 98: do while (k < n); CodeWatch> P 5 98: do while (k < n); 99: /* cancel all multiples */ 100: flags(k) = FALSE; 101: k = k + this_prime; 102: end;
CodeWatch> B 100 CodeWatch> C Break at PRIMES.SIFT\100
CodeWatch> TRACE STATEMENT CodeWatch> C **** PRIMES.SIFT\101 **** PRIMES.SIFT\102 **** PRIMES.SIFT\98 Break at PRIMES.SIFT\100 CodeWatch> C **** PRIMES.SIFT\101 **** PRIMES.SIFT\102 **** PRIMES.SIFT\98 Break at PRIMES.SIFT\100
CodeWatch> MACRO fig.=[FIND /IGNORE] CodeWatch> fig PRINT_OUT 105: call print_out(primes,count); /* should be count - 1 */
CodeWatch> B 105 CodeWatch> NTRACE S CodeWatch> NBREAK CodeWatch> C Break at PRIMES.SIFT\105
CodeWatch> E count
COUNT = 6 {fixed binary (31)}CodeWatch> B sift\%ENTRY CodeWatch> RELOAD Command line : "primes" Reloading..ok Initial evaluation environment is PRIMES:(inactive) CodeWatch> C *** Sieve of Eratosthenes *** Input maximum prime boundary: 10 Break at PRIMES\119 CodeWatch> C Break at PRIMES.SIFT\%ENTRY
CodeWatch> S Step at PRIMES.SIFT\85 85: do I = 1 to n; CodeWatch> P 15 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 */
CodeWatch> B 95 /IF {count > 4} /ELSE [E count] CodeWatch> C COUNT = 1 {fixed binary (31)} COUNT = 2 {fixed binary (31)} COUNT = 3 {fixed binary (31)} COUNT = 4 {fixed binary (31)} Break at PRIMES.SIFT\95
CodeWatch> NB CodeWatch> C;P Break at PRIMES.SIFT\105 105: call print_out(primes,count); /* should be count - 1 */
CodeWatch> E count COUNT 6 {fixed binary (31)} CodeWatch> LET count=count-1 CodeWatch> C Number of primes found was (prime itself) 5 1 2 3 5 7 Input maximum prime boundary: 10 Break at PRIMES\119
CodeWatch> R Command line : "primes" Reloading..ok Initial evaluation environment is PRIMES:(inactive) CodeWatch> NBREAK /ALL
CodeWatch> B 105 /SILENT [LET count=count-1;C] CodeWatch> C *** Sieve of Eratosthenes *** Input maximum prime boundary: 10 Number of primes found was (prime itself) 5 1 2 3 5 7 Input maximum prime boundary: 100 Number of primes found was 26 1 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 Input maximum prime boundary: 0 Program exited with status 0 Reloading..ok Initial evaluation environment is PRIMES:(inactive)
call print_out(primes,count);
to:
call print_out(primes,count-1);
the program will work just fine! Quit out of the debugger session.
CodeWatch> QUIT
CodeWatch Quit...Bye!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.