To demonstrate how the Debugger can be used, take the example of an internal office program called BIRTHDAY. The BIRTHDAY program asks users for their birthdays and then tells them how many days they have until their next birthday. The program works fine for the programmer:
>RUN BP BIRTHDAY |
The screen is cleared and the following prompt appears (with the underline representing the position of the cursor.) :
ENTER YOUR BIRTHDAY: MM/DD/YY |
A date is entered:
ENTER YOUR BIRTHDAY: 6/4/65 |
The program converts the date and then prints out how many days there are until the programmer’s next birthday.
ENTER YOUR BIRTHDAY: 04 JUN 1965 ON 06/04/1990, IN 319 DAYS, YOU WILL BE 25 YEARS OLD.
> |
The programmer was satisfied by this performance, since the tricky part of the program was to make sure that it did not report a birthday that had already passed (e.g., IN -46 DAYS, YOU WILL BE 24).
Since the test above was performed in July and the date entered was in June, the tricky part seemed to have been solved.
Later the same day, however, it was reported that the program did not work. In particular, when supplied a date in September, the program still jumped ahead a year:
ENTER YOUR BIRTHDAY: 3 SEP 1961 ON 09/03/1990, IN 410 DAYS, YOU WILL BE 29 YEARS OLD. |
The programmer quickly examined the source code but could not find an error. However, using the Debugger, perhaps the user can discover something the programmer could not.
First, run the program with the D option, which forces the program to enter the Debugger before executing line 1.
>RUN BP BIRTHDAY (D) |
Before the program begins execution, the Debugger is invoked and E1 is printed, signifying that it stopped before executing line 1. The asterisk (*) is the Debugger prompt.
*E1 * |
The first thing is to examine the source code. Before you can access the source code, you need to turn trace on with the T command.
*T<ENTER> |
The source code is now available for listing by the Debugger with the L command. Since it is a short program, L can be used with the * option, specifying that the entire source code item should be printed.
*L* 001 PROMPT " " 002 DIM BIRTHDAY(3), TODAY(3) 003 EQUATE TRUE TO 1, 004 FALSE TO 0, 005 BIRTH.MONTH TO BIRTHDAY(1), 006 BIRTH.DATE TO BIRTHDAY(2), 007 BIRTH.YEAR TO BIRTHDAY(3), 008 THIS.MONTH TO TODAY(1), 009 THIS.DATE TO TODAY(2), 010 THIS.YEAR TO TODAY(3) 011 012 INCREMENT = FALSE 013 PRINT @(-1) : "ENTER YOUR BIRTHDAY:": 014 INPUT @(20,0) BIRTHDAY.INT "D" 015 TODAY.INT = DATE() 016 TODAY.EXT = OCONV(TODAY.INT,"D/") 017 MATPARSE TODAY FROM TODAY.EXT,"/" 018 BIRTHDAY.EXT = OCONV(BIRTHDAY.INT,"D/") 019 MATPARSE BIRTHDAY FROM BIRTHDAY.EXT,"/" 020 IF THIS.MONTH > BIRTH.MONTH THEN 021 INCREMENT = TRUE 022 END 023 IF (THIS.MONTH = BIRTH.MONTH OR THIS.DATE BIRTH.DATE) THEN 024 INCREMENT = TRUE 025 END 026 IF INCREMENT THEN 027 THIS.YEAR += 1 028 END 029 AGE = THIS.YEAR - BIRTH.YEAR 030 NEXT.BIRTHDAY = BIRTH.MONTH : "/" : BIRTH.DATE : "/" : THIS.YEAR 031 NEXT.BIRTHDAY.INT = ICONV(NEXT.BIRTH-DAY,"D") 032 DAYS.TO.BIRTHDAY = NEXT.BIRTHDAY.INT - TODAY.INT 033 IF DAYS.TO.BIRTHDAY = 0 THEN 034 PRINT 035 PRINT "HAPPY BIRTHDAY!" 036 PRINT "TODAY, " : TODAY.EXT : ", YOU ARE " : AGE : " YEARS OLD" 037 END ELSE 038 PRINT 039 PRINT "ON ":NEXT.BIRTHDAY:", IN ": DAYS.TO.BIRTHDAY :" DAYS,": 040 PRINT " YOU WILL BE ":AGE:" YEARS OLD." 041 END 042 STOP 043 END
* |
At first glance, it is obvious that the problem lies in the variable THIS.YEAR: THIS.YEAR is being incremented when it should not be. Before you start editing the program, however, use the Debugger to confirm your suspicions.
To examine the value of THIS.YEAR at the end of the program, the user needs to set up a breakpoint so that variables can be examined before the program ends. A breakpoint condition is a condition that invokes the Debugger whenever it is true.
The B command is used to assign a breakpoint condition. You can choose to break when the THIS.YEAR variable is equal to 1990.
*BTHIS.YEAR=1990<ENTER> + |
The breakpoint condition says to transfer into the Debugger when the variable THIS.YEAR is equal to 1990. The plus sign (+) is printed after pressing the ENTER key to signify that the breakpoint was accepted into the breakpoint table.
Enter THIS.YEAR as a trace variable. A trace variable is a variable that is printed whenever a breakpoint is encountered. Enter it into the trace table with the T command:
*TTHIS.YEAR<ENTER> + |
Add to the trace table the variables THIS.MONTH, BIRTH.MONTH, THIS.DATE, and BIRTH.DATE. It is suspected that the problem may be that these variables are not being assigned correctly.
*TTHIS.MONTH<ENTER> + *TBIRTH.MONTH<ENTER> + *TTHIS.DATE<ENTER> + *TBIRTH.DATE<ENTER> + |
To display the breakpoint and trace tables, use the D command:
*D T1 THIS.YEAR T2 THIS.MONTH T3 BIRTH.MONTH T4 THIS.DATE T5 BIRTH.DATE T6 B1 THIS.YEAR=1990 B2 B3 B4
* |
The G command continues execution of the program.
*G<ENTER> |
The screen clears and the prompt is printed. Type 9/3/61 and press ENTER:
ENTER YOUR BIRTHDAY: 9/3/61 |
The program halts when the breakpoint is reached.
ENTER YOUR BIRTHDAY: 3 SEP 1961 *B1 28 END THIS.YEAR 1990 THIS.MONTH 07 BIRTH.MONTH 09 THIS.DATE 20 BIRTH.DATE 03 * |
As expected, the condition is true after line 27 has been executed. The message B1 28 means that item 1 on the breakpoint table caused the break, and the line about to be executed is line 28. (The actual text of that line is displayed in half-intensity on the terminal screen.) The current values of the trace variables are printed.
The error in the program becomes increasingly obvious as you continue in the Debugger. Since THIS.MONTH, BIRTH.MONTH, THIS.DATE, and BIRTH.DATE contain the correct data, the problem is in the way they are being compared. For THIS.MONTH to be incremented, the INCREMENT variable must be true. Confirm this by using the / command to print out the current value of INCREMENT:
*/INCREMENT |
When ENTER is pressed, the value of INCREMENT is displayed, and you are given the opportunity to change its value.
*/INCREMENT<ENTER> 1=_ |
Type 0 as the new value for INCREMENT and press ENTER.
*/INCREMENT<ENTER> 1=0<ENTER>
* |
Reset the value of THIS.YEAR to 1989.
*/THIS.YEAR<ENTER> 1990=1989<ENTER>
* |
To find out which comparison is failing, step through the crucial lines of the program this time around to see what exactly is happening. To begin the program executing again after line 19 with an execution step of 1 (an execution step is a number of lines that should be executed before returning to the Debugger). The E command should be used to specify the execution step:
*E1 |
Add the variable INCREMENT to the trace table.
*TINCREMENT<ENTER>+ |
The G command continues execution after line 19. One line executes and the program returns to the Debugger. The line about to be executed will be printed on the screen, along with any trace variables.
*G19<ENTER> *E20 IF THIS.MONTH > BIRTH.MONTH THEN THIS.YEAR 1989 THIS.MONTH 07 BIRTH.MONTH 09 THIS.DATE 20 BIRTH.DATE 03 INCREMENT 0 * |
Step through 3 more times, until you find that the INCREMENT variable has been changed.
*G *E25 END THIS.YEAR 1989 THIS.MONTH 07 BIRTH.MONTH 09 THIS.DATE 20 BIRTH.DATE 03 INCREMENT 1 * |
By stepping through the program, you will see that the INCREMENT variable is changed immediately before line 25. List lines 23 through 25 with the L command:
*L23-25 023 IF (THIS.MONTH = BIRTH.MONTH OR THIS.DATE > BIRTH.DATE) THEN 024 INCREMENT = TRUE 025 END * |
The problem is in the conditional for the IF statement. It becomes obvious that, as usual, the bug in the program is a simple logical error: the OR in line 23 should be an AND. With that simple edit, the program should run correctly.
Exit the Debugger with the END command, edit the source item, and recompile. The output now reads:
ENTER YOUR BIRTHDAY: 3 SEP 1961 ON 09/03/1989, IN 45 DAYS, YOU WILL BE 28 YEARS OLD.
> |
It seems as if the bug is gone, for now. However, you are not confident that the program will still behave correctly at the end of the year. Using the Debugger, you can change the value of the variable TODAY.INT in the program and see whether the program still works.
Run the program again with the D option, use the T command to turn trace on, and set a breakpoint to stop executing before line 16. (The $ symbol on the breakpoint table represents the current line number.) Then continue execution with the G command.
>RUN BP BIRTHDAY (D)
*E1 *T<ENTER> *B$=16<ENTER> + *G<ENTER> |
You will be prompted for a birthday. After entering a date, press ENTER. The program will halt before executing line 16.
ENTER YOUR BIRTHDAY 03 SEP 1961 *B1 16 TODAY.EXT = OCONV(TODAY.INT,”D/”) * |
Before line 16 is executed, reassign the value of the TODAY.INT variable with the / command. Then type the G command to continue execution.
*/TODAY.INT<ENTER> 7872=8036<ENTER>
*G<ENTER> |
8036 is the internal value of December 31, 1989 and the program runs successfully:
ON 09/03/1989, IN 246 DAYS, YOU WILL BE 29 YEARS OLD. > |
Now that you have an idea of what the Debugger can do and why you would use it, you can go over the specifics of its operation.
See Also
Debugger Commands: Quick Reference