JRT Pascal User's Guide version 3.0 NOT FOR SALE -140- 13. Debugging Pascal programs Debugging computer programs is the process of correcting "bugs" in a program so that it will perform as desired. There are two phases of debugging: correcting syntax errors in a program in order to obtain an error-free compile, and correcting errors which occur during the running of the program after a clean compile. Referencing an undeclared variable is an example of the first kind of error. Dividing by zero is an example of the second kind. This section is primarily concerned with the second kind of error - those that occur during program testing. JRT Pascal provides several facilities to simplify the location and the correction of run-time errors. The debugging philosophy is to provide the programmer with as much relevant information as possible in a clearly formatted display. The run-time system detects errors at two levels of severity - errors and warnings. When warnings occur, a message is issued and processing continues. When an error occurs, processing must terminate. Error and warning messages are all presented in verbal format - there are no number or letter codes to look up. These messages are stored on a disk file so that main storage is not wasted. 13.1 Trace options JRT Pascal allows a trace of the program line numbers while a program is running. This trace may be turned on or off by the program itself. The range of line numbers to be traced may also be set by the program. A trace of procedure names can also be produced. On entry to each procedure, the name and activation count is displayed. On exit, the name of the procedure is displayed. This feature can also be turned on or off under program control. The Exec interrupt mode can be entered by a control-n command while a program is running. In this mode, the traces and line number range can be modified. Other system status information can also be displayed. When in interrupt mode, entering a space character will cause a list of valid commands to be displayed. Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -141- Exec interrupt allows asynchronous control of the trace facility. Programmed control is also supported with the SYSTEM builtin procedure. An interactive external procedure to control these trace facilities at run-time is provided. The DEBUG procedure is described in section 13.2 of this manual. To use these traces, the %LTRACE and %PTRACE compiler directives must be inserted in the program. It is recommended that the first line of a program being tested contains both directives, so that the entire program will be subject to tracing. An additional advantage is that when these options are present, if an error or warning occurs, the line number and the latest procedure name will be displayed with the error message. The coding of these directives and use of the SYSTEM builtin procedure to control the traces are described in the section on compiler directives (section 3 of this manual). 13.2 DEBUG procedure The DEBUG external procedure allows the control of the dynamic trace facilities while a program is being tested. The procedure and line traces can be turned on or off and the line range can be set by commands entered from the console. The file DEBUG.INT on the distribution disk is the compiled external procedure module. To reference an external procedure from a Pascal program, it is necessary to declare it: PROCEDURE DEBUG; EXTERN; The procedure can be called from an number of places in the test program by inserting a procedure call statement: DEBUG; Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -142- When it is activated, DEBUG will interact with the programmer to modify the current trace operations. Listing of DEBUG.PAS: extern procedure debug; var reply : char; lower, upper : integer; begin (* debug *) writeln; write('Activate line trace? y/n : '); readln(reply); if upcase(reply) = 'Y' then begin write('Range of lines? lower,upper : '); readln(lower,upper); system( ltrace ); system( lrange,lower,upper ); end else system( noltrace ); write('Activate procedure trace? y/n : '); readln(reply); if upcase(reply) = 'Y' then system( ptrace ) else system( noptrace ); writeln; end; (* debug *). Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -143- 13.3 System status display When an error is detected, an error message is displayed on the console. The current line number and last entered procedure name may also be displayed (see section 13.1). A system status display is also created. This display contains useful information about the current state of the run-time system. The system status display shows nine fields of information. If external procedures are present, the external procedure table is also formatted and displayed. System status display addr :54F5 prog :3BA7 size :4815 base :83BC cur :89AC tos :8A33 low :A8B9 compr:0002 purge:0000 Most of these values indicate the use of storage in the run-time system. Storage management is discussed fully in section 11 of this manual. A simplified map of storage is presented here: ------------------------- I CP/M I I-----------------------I I DYNAMIC STORAGE I I I low---> I-----------------------I I I I unused I I I tos---> I-----------------------I I I cur---> I DATA STACK I I I base--> I-----------------------I I I I PASCAL CODE I <--addr (of error) I I prog--> I-----------------------I I I I EXEC run-time I I system I 100h--> I-----------------------I I reserved area I ------------------------- Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -144- 1. addr - the address at which the error occurred. This may be in the Pascal code area or in the dynamic storage area if the error was in an external procedure. 2. prog - the starting address of the main Pascal program. 3. size - the size of the main program module. 4. base - the base or bottom of the data stack. 5. cur - the address of the current procedure activation block. 6. tos - top of stack. This is the address just past the end of the data stack. 7. low - the lowest address occupied by any dynamic storage block. 8. compr - a count of the number of times storage has been auto-compressed. 9. purge - a count of the number of external procedures that have been purged from dynamic storage due to short-on-storage condition. Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -145- The system status display may contain one additional line of input/output information. The name of the most recently referenced file, a status byte and the current default disk will be displayed if files have been used by the program. @:SAMPLE PAS 88 A If the file was opened without specifying a disk letter then @ is shown, otherwise the disk letter. The status byte contains several flag bits: bit meaning --- --------- 80 file is open 40 random mode - not sequential 20 text mode - not binary 10 EOLN flag set 08 input - not output or random 04 EOF flag set Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -146- Formatted external procedure table exproc name addr use cnt time stat ACCTPAY1 C2AE 0000 0004 30 ACCTPAY2 3E22 0000 0165 74 GENLEDG1 0001 0000 0000 00 ACCTREC1 3F55 0001 014E F4 ACCTREC2 440C 0001 015A F4 SORT 0001 0000 0000 00 +INVENTRY 503A 0001 020D F4 CHECKS 5052 0000 0103 30 1. exproc name - the name of the external procedure or function. A plus sign indicates the external procedure which was most currently entered or exited. This is not necessarily the currently active procedure. 2. addr - the address in main storage of the external procedure module. If this value is 0001 then the module is not currently in main storage. 3. use cnt - a count of the number of times the procedure is CURRENTLY active. Usually this will be 0000 (not active) or 0001 (active). It will be greater that 0001 only if the procedure is called recursively. 4. time - in order to determine which procedure was least-recently-used, the run-time system maintains a pseudo-timer which is incremented once on each entry to or exit from an external procedure. The field contains the value of the pseudo-timer the last time the procedure was entered or exited. 5. stat - a status indicator with several flag bits: bit meaning --- -------- 80 procedure is currently active 40 procedure was linked with main program 20 procedure is currently in storage 10 procedure file control block is open 04 procedure address is real, not virtual Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -147- 13.4 Run-time messages The run-time system provides several messages to aid in the correction of error or exceptional conditions. In addition to these general messages, about 75 more specific messages of 1 to 4 lines to text are provided to describe particular error conditions. The general run-time messages are all prefixed with a % character. These messages are listed here: %Entry - indicated entry to a procedure when procedure trace is active. Procedure name and activation count are listed. External procedures are indicated by an asterisk before the name. %Error - fatal error detected by run-time system. Program terminates. %Exit - indicates exit from procedure when procedure trace is active. Procedure name is listed. External procedures are indicated by an asterisk before the name. %Extern - indicates that error occurred while attempting to load an external procedure module. The procedure name is listed. %Input error - indicates a format error when reading console input, such as entering a character string when an integer was expected. %Line - indicates line number where error occurred. The module must have been compiled with %LTRACE option. %Main - error occurred in main program BEGIN-END block, not in procedure. Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -148- %Proc - error occurred in procedure, not in main program BEGIN-END block. %Trace - line number trace indicator. %Warning - non-fatal error condition. Processing continues. Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -149- 13.5 Common Problems A. General difficulties 1. The master disks accidently got erased by a program... MAKE BACKUP COPIES OF JRT PASCAL when you first get it. May we suggest: Remember the Master Disk, to keep it wholly. As a read-only disk, please. 2. The disks will not boot up when on is put in drive A: and the system is reset... After you copy JRT Pascal to your own working disks, put a copy of your operating system (using SYSGEN or whatever YOUR operating system calls it) on the working disks. We cannot put your operating system on disks we distribute. 3. With CP/M 1.4, CDOS or the equivalents, CUSTOMIZ, LINKER and random I/O in general will not work.... Sorry about that, but to get random I/O on 8 megabyte files, CP/M 2.2 would be required. LINKER is never required for JRT Pascal. The function of CUSTOMIZ can be performed by two simple patches in DDT. This involves patching the disk search list in EXEC.COM and JRTPAS3.COM. Both of these list are at 0155h and consist of up to four upper case letters followed by a Z. A>DDT EXEC.COM -S155 0155 41 41 0156 42 42 0157 4A 5A (an upper case Z) 0158 00 . -G0 A>SAVE 93 EXEC.COM For JRTPAS3.COM, the SAVE command line is A>SAVE 85 JRTPAS3.COM 4. The diagnostic "JRTPAS3?" or "SOURCE FILE NOT FOUND" comes up... CP/M needs to know the drive on which the file JRTPAS3.COM is located, if it is not on the current default drive. JRTPAS3 needs to know the drive on which the source file to be compiled is located. Further, that source file must have a '.PAS' suffix on the name. So, for example, you may need to type B:JRTPAS3 B:PGM if the default drive is A: and both JRTPAS3.COM and PGM.PAS are on the B: drive. Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -150- 5. The compiler and everything else does not fit on one disk... There are many possible ways to set JRT Pascal up when you have a system with small drive capabilities. One is: On disk A: On disk B: -EXEC.COM -JRTPAS3.COM -your editor -PASCAL0.INT (ED, WordStar, etc.) -PASCAL1.INT -the PASCAL SOURCE program -PASCAL2.INT being developed -PASCAL3.INT -perhaps PASCAL.LIB -PASCAL4.INT -PASCAL.LIB You Osborne owners may have to do some shuffling until you find the arrangement that works best for you. For example, the compiler disk could be on drive A:, which would alternate with the WordStar disk as necessary (with appropriate Control-C's after disk changes). The source and object programs could then stay on B:, perhaps with EXEC.COM and another copy of PASCAL.LIB. Be sure there is a copy of your operating system on each disk you put in drive A:. 6. The compiler (or run-time) USED to work, but now it doesn't... Use EXEC VERIFY to check the compiler and/or run time files again. Even if the sums agree, a file or files may have gotten shuffled by a malfunctioning program, hardware errors, or bad diskette handling. If necessary, go back to the original master disks (write-protect labels, right?) and copy the needed files to a NEW diskette. If necessary, act as if you had just gotten JRT Pascal (square-1). 7. EXEC VERIFY does not even work... Make sure that EXEC.COM, VERIFY.INT, and PASCAL.LIB are MOUNTED on your disk system, and that you told CP/M the right drive for EXEC.COM and that you gave EXEC the right location for VERIFY.INT. You may need to use B:EXEC B:VERIFY if the files are on B:. Remember when you run EXEC.COM that PASCAL.LIB must be present on one of the drives in the "disk search list" (usually A: or B:). 8. BDOS errors show up when a DIR is requested of a master disk... Make sure that your system is expecting a disk in the format provided. For example, single density 8" disks: Some operating systems cannot sense a density change once they have determined "the format for that drive". A system reset may be needed. Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -151- B. Compiler Errors 1. String literal too long... Somewhere in the program, a literal string does not have a closing or opening single quote. This error is caught by the lexical scanner before the program is listed. (Most editors make it easy to search for all lines with single quotes.) 2. Block structure invalid (and other strange diagnostics)... Perhaps the program is attempting to declare or use a reserved word. The list of reserved words in JRT Pascal is somewhat longer than standard. For example, LENGTH and POS are reserved. 3. Compiler acts like something is not there... Many versions of WordStar set the high-order bit of the 'current' character when a file is closed, even when editing in non-document form. ALWAYS end a WordStar edit with (^QC) before (^KD). Also, use PIP newfile.PAS=oldfile.PAS[Z] to clear off parity bits. 4. Compiler "goes away"... Hit system reset, then look for undeclared variables, types, or constants in the next line listed. Also check for ; or , used inappropriately. Look for unbalanced parenthesis. 5. Out of memory... Split the program into a main program and external procedures so that each portion is 600 to 1200 lines long. (Maximum length depends on the program and the available memory.) 6. Array out of bounds at end of compilation... External procedure names can be 8 characters long and should not contain $ or _ characters, since the exproc name is turned into a CP/M file name. Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -152- C. Run-time Errors 1. Object file not found... Make sure that the source program is compiled successfully, and that the appropriate drive is indicated on the file name, as EXEC B:PGM. 2. Library not present... PASCAL.LIB must be present on one of the drives in the "disk search list" (usually A: or B:). 3. Files never get written to... CLOSE(file_variable) is required after files have been written, so that CP/M performs a proper close on the file. Otherwise, the file size will be the next lower multiple of 16K in size, usually zero. 4. Reading characters from a file, most of the characters in a word get skipped... The difference between binary and text modes are significant. If you want every character in a file, use binary in the reset of open statement. 5. Reading from a file in binary mode, end of file is hard to determine... Control-Z (1ah) marks the end of a text file (unless the real end of file on a 128 byte boundary occurs). Test for both character =CHR(26) and EOF. For binary records, a special record consisting of all 255 (0ffh) or all EOF's (1ah) may be needed to mark the end of the file, since CP/M only keeps track of 128-byte sectors. 6. External procedures get all mixed up... Declare external procedures properly. When external procedures refer to other external procedures, the declaration order count must match those in the main program: If your main has FUNCTION COS(R : REAL): REAL; EXTERN; FUNCTION SIN(R : REAL): REAL; EXTERN; and your exproc has declared only FUNCTION SIN(R : REAL): REAL; EXTERN; lo and behold, the exproc will get a value of 1.0 if it passes 0.0 to what it thinks is SIN. The exproc will have actually called COS. Internally, external procedures refer to other external procedures by number. 'Dummy' declarations such as PROCEDURE X1; EXTERN; can be used as place holders, as long as the names are unique. The name used in the MAIN program will be used to find the external procedure on the disk. 7. Values are not returned correctly from external functions (or arguments are not passed correctly to external procedures)... Make sure the declaration of arguments in the calling program match those in the external procedure. If a VAR is missing in one and Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -153- present in another, you could have trouble. 8. Control-C does not stop a program (or control-N does not stop it either)... Use control-N to cause an execution interrupt (you can either exit the program with Z or continue with R, as appropriate). Use %LTRACE or $L when compiling the program to allow execution interrupts and also error diagnostics with line numbers. Copy compliments of Merle Schnick SECTION 13: Debugging cution interrupts and also error diagnostics with line numbers.