STOP Commands and Breakpoints
Debugger Error Messages
To be able to debug a program, you first have to move the window with the source code to the front and then select the menu option 'Debug' from the 'Program' menu. The program is then compiled in a special format, which enables the debugger to monitor and control the program execution at any time. The following potential error sources are monitored as well:
- Integer overflows with byte, integer, and long integer numbers. For example: A%=32768 or A%L=10^12 would trigger such an error.
- Floating point underflows and floating point overflows. These errors occur when the result of a calculation cannot be depicted in the applied number format (e.g., A#=10^100*10^250 or A!=10^-45).
- Divisions by zero.
- Illegal operations such as A#=LN(-1).
- BASIC stack overflow. This can happen, e.g., when sorting large fields or during recursive programming with large interleaf depths.
- In case of field variables, it is checked whether the specified indices are located in the range for which the field has been dimensioned, e.g., DIM A#(2,3):A#(3,2)=1 would trigger such an error.
If one of these errors occurs, an alert box is shown first describing the error. After leaving the alert box the Debugger Control appears. You can now open memory and variable windows and find out what caused the error. If it is not a fatal error, the program may continue; otherwise, it is always terminated when you try to continue.
Of course, there is a variety of other traps waiting for the programmer, which cannot be recognized by the debugger due to their nature (e.g., LPOKE 12,-1, or if you are using the Extension Library but have forgotten to add Extension_Init to the beginning of the program). Do not try this because it is sure to crash your computer!
For the debugger to be able to process all of these tasks, a table is created establishing a link between the source code and the object code generated by the compiler. The program can thus not be edited during the debugging phase. Therefore, do not think that your computer has crashed just because you cannot change your program any longer.
The program is started automatically after compilation is complete. The programs
generated with 'Debug' run somewhat slower than when using the menu option 'Compile
& Start' due to the many management tasks that have to be processed. However,
this should not come into play when searching for errors.
Note: If you are using the Lite or the Demo version it may be that a program can be compiled normally but cannot be debugged. The reason for this is the additional object code generated in the debugging mode, which results in a program that is too long for the Lite or Demo version.
After the debugger has started your program, a small window opens containing the Debugger Control. The window has 7 buttons, which may be used to control the progress of your program. The control options are as follows:
Your program comes to an immediate stop if you click on this button. The window with the source code also automatically scrolls to the spot where the program stopped and marks this location with a small triangle. This function can also be called by pressing [Ctrl]+[C].
Attention: If your program does not make any regular calls of COMPILER "EVENT" or EasyMesag (in the case of programming with EasyGem) the program can be stopped only by pressing [Ctrl]+[C].
This button can be selected only if a program has been stopped. When you click on this button, the program execution is continued with the command to which the small triangle is pointing.
This button can be selected only if a program has been stopped. When you click on this button, only the one command to which the small triangle is pointing is executed. If it is a procedure or function call, the program pointer jumps into the procedure or function. The same applies to GOSUB commands. Please note that functions can also occur in formulas. In that case, all functions occurring in the formula are entered into.
If the procedure or function has been supplied by a library, the debugger does not enter the subprogram. This would actually serve no purpose since the program code in the library is not listed and you cannot monitor the progress of the program as it is.
Note: A few of the library commands use callback
functions, which you have to define yourself and which are thus not located in the
library (e.g., Uwin_Open from the EasyGem Library).
If you now call library commands using [Step into], the program pointer does not
jump into the library but could land in your callback routine if this is just now
being called from within the library.
Unless you intend this action, it is better to use the button [Single Step] to avoid any such confusion.
This button can be selected only if a program has been stopped. It serves to trigger a procedure or function without having to execute all commands within the procedure or function in individual steps. To be exact, the program execution is continued until the debugger meets up with a RETURN, END_PROC, END_FN, or EXIT, which is located at the same hierarchy level as the program pointer was when this button was clicked.
After the button has been selected, the program pointer is then located directly behind the command used to call the procedure or function. The same applies if subprograms are called via GOSUB commands.
Note: If you are using this button while the program pointer is not located in a subprogram, it will have the same effect as [Continue], because no RETURN commands are located in the uppermost hierarchy level.
This button can be selected only if a program has been stopped. This function is similar to the function of the [Step into] button with the one difference that subprogram calls are always interpreted like BASIC commands and therefore is never be stopped in subprograms.
This button can be selected only if a program has been stopped. This will continue the program in slow motion. The standard settings ensures that the debugger executes max. one command per second. This interval can also be changed using the dialog box 'Debugger Settings'.
This button can always be selected. It may be used to terminate the program controlled by the debugger at any time. This closes the window for the Debugger Control automatically.
Attention: A few Omikron Basic commands wait for user input before continuing the program. Since the debugger can halt a program only in-between two commands but not actually in the middle of a command, the debugging command in these cases does not become effective until the command has been concluded.
These are the Omikron Basic commands INPUT, LINE INPUT, FORM_ALERT, and FILESELECT or FSEL INPUT, as well as the EasyGem commands Easy_Alert,Easy_Fsel, Easy_Fnav, and Pick_Color.
For example, if your program is in an INPUT instruction and you click on [Terminate], the program is not terminated until the user has exited the input instruction with [Return].
STOP Commands and Breakpoints
If you stop your program using the Debugger Control, the spot where the program stops is more or less selected at random. But there are two other possibilities, which will halt the program in a specifically selected location.
Even before starting your program with 'Debug' just insert a STOP command at the location where the program is to stop. Those who used to work with BASIC interpreters are probably familiar with this method. The STOP command halts a program without deleting variable and memory contents.You can then continue the program in a targeted manner using the Debugger Control.
Attention: The STOP command functions only if the program has been started with 'Debug'. A normally compiled program using the STOP command will lead to an error message with subsequent termination of the program.
Breakpoints are additional stopping points, which you can include in your program. Contrary to STOP commands, breakpoints cannot be set until the program has been started with 'Debug'. Just pull the source code window to the front, press the [Ctrl] key, and click on the spot in the source code where the breakpoint is to be set. A small ellipsis appears in the color of the commentary lines. As soon as the program pointer is now running across this spot, the program is halted and you can use the Debugger Control for a detailed analysis. If you click on a breakpoint again, it is removed.
You can set as many breakpoints as desired. Contrary to STOP commands, breakpoints are only effective during a debugging phase. After the program is finished they are automatically deleted. They also cannot be copied to the clipboard or saved. If you would like to insert permanent breakpoints into your program you have to use the STOP command.
Note: You cannot set breakpoints in all locations of a program because some lines, such as a commentary line, are skipped by the compiler and some BASIC commands serve only to structurize but do not generate an object code. In these cases, the breakpoint appears in the next possible location before the position on which you clicked.
Attention: If you are using the EasyGem Library
or have programmed your own event handling routine, your program cannot restore the
contents of windows once it has been halted by the debugger.
This does not apply to Omikron Basic output windows. These are managed by a small assembler program, which continues to run even when the BASIC program has been halted by the debugger.
Memory windows can be opened with the menu options carrying the same name from the 'Program' menu. Memory windows are used to view the content of RAM memory.
There is an input line in the upper left corner of the window, which may be used to specify at which logical address the memory content view is to start. The address can be prefixed and indicated in all number systems supported by Omikron Basic (e.g., $A6553 or 123456). Pushing [Return] shows the memory content starting with the specified address.
If the specified memory range does not exist, an error message appears and nothing is shown.
The type of display can be set via the Debugger Settings.
You can enter the names of variables into the variable windows. Their content is then shown in the same window. For string variables the length of the strings are indicated as well.
Only constants or individual variables may be used for the indices of field variables (e.g., A#(X,Y) or A#(1,3)). As long as a program has not been started with 'Debug' the content of variables is, of course, 0 and an empty string for strings.
The number system to display the variable content can be set with a prefix. For example, the input of $Tex$ would output the content of the string Tex$ as a byte sequence in hex numbers and not as a character string. Similarly, the input of %A would result in the variable content A as a binary number. According to the default setting, the output of numerical variables is always in the form of decimal numbers and strings are always output as character strings.Strings can also be output as a decimal byte sequence by prefixing with the number symbol "#." This is of special interest if one is interested in the ASCII values of a string.
Block functions also work in variable windows. Instead of typing in the desired variables, you can transfer them from the program window using 'Copy' and 'Paste'.
Variable windows can also be saved, reloaded, or printed. The format for saving is ASCII. If they are reloaded, the variables are assigned to the currently topmost program window.
If a variable does not exist or a field element is not located within the dimensioned range, the line is marked in red to indicate an error line (red is the default setting).
A variable window always refers to a specific program window. If the window is closed, all linked variable windows are automatically closed as well, because the variables contained in the program window are no longer defined.
Modifications to the variable windows can be set in the Debugger Settings dialog.
Of course, it is also possible to individually configure all of the important debugger functions. To configure the debugger use the dialog you find in the 'Mode' menu under 'Settings>General-Debugger'. A detailed description can be found in Chapter 3, Debugger. The dialog box can remain open while working with the debugger so that you can change the animation speed during a running animation process, for example.
Error Messages of the Debugger
The program "Program Name" has unexpectedly quit.
In some cases it can happen that a program to be debugged is terminated spontaneously. In these cases it is no longer possible to send a message to the debugger. The debugger in turn is not informed of the termination. If you now still try to apply debugger commands to the terminated program, you will receive this error message.
The addressed memory does not exist.
This error message appears if you try to display a non-existing memory range.
After we have described the debugger components, we would like to illustrate how
to use the debugger by using some examples. The sample programs are equipped with
line numbers for easier line reference. The line numbers are not required to run
the program. All variables without postfix are of the long integer type according
to the Omikron Basic editor default setting. If you have modified this setting, you
have to consider this when transferring the program code.
The examples listed here are located in the folder DEMO:Debugger (Demo).
Open a new program window and transfer the following program to an empty window using the 'Copy' and 'Paste' functions. We have added an error to example 1, which we now will find using the debugger.
Start the program first with 'Compile & Run'. The program is to calculate the prime numbers between 11 and 120, and it is assumed that the primes < 11 are already known. As you can see, the program runs normal and does not issue any error messages, but it also calculates incorrectly because the number 49 is marked as a prime even though it is divisible by 7.
Quit the program and restart it once more using the menu option 'Debug'. The program
stops on line 35 and issues the error message "integer overflow." Click
on [OK]. You are now in the debugger. The position where the program stopped is marked
with a small triangle.
To ascertain the type of error that occurred open a new variable window. Enter I, J, and Primes(J)into the window and press [Return] after each input so that the variables appear in different lines. As can be seen, I has the starting value 2, J the end value 3, and Primes(J)=0, so that the operation I MOD Primes(J) is not defined and leads to the "Integer overflow."
Just one glance at line 22 shows that an incorrect end value is specified for the control variable J in the READ loop (2 instead of 3).
Now click on [Terminate] in the Debugger Control. Then add a STOP command to line 18 and correct the wrong end value in line 22 (change 2 to 3).
Then restart the program with 'Debug'. The program is now halted directly behind the STOP command. Primes(J) is depicted as an error line in the variable window. This is because this field has not been dimensioned yet. Now advance one step at a time by clicking on [Single Step] in the Debugger Control. After the DIM command in line 20 has been executed, Primes(J)=0 is displayed correctly in the variable window. If you now proceed with the READ loop step by step until finished, you can view on the monitor how the prime numbers are read into the field Primes() one after the other. At the end of the loop, Primes(J) is again depicted as an error because J is now 4 and Primes(J) has only been dimensioned up to three.
Once you reach line 25 you can decide whether you want to execute the procedure
Display_Numbers as a command with [Single Step] or
if you would like to jump into the procedure with [Step into]. We decided to use
[Step into] to demonstrate the functions of the debugger.
Since PRINT output is directed to the Omikron Basic output window from within the procedure Display_Numbers, you should move aside the program window so that you can see the output window.
Of course, now you could execute all commands in the procedure in individual steps but since nothing spectacular is happening here we would like to take this opportunity to demonstrate another function of the debugger. Click on [Animation]. The debugger now executes all commands in slow motion. You can now track how the program pointer progresses through both of the loops and how the numbers are written to the Omikron Basic output window. Once you have seen enough, click on [Stop]. The program stops at the current location. If you now click on [Step out] all commands within the procedure are executed and the program is not stopped until line 26, behind the procedure call, has been reached.
Now keep the [Ctrl] key depressed and clicked on the FOR
in line 31 with your mouse. This sets a breakpoint in front of the FOR
depicted as an ellipsis. Click on [Continue]. The program pointer stops exactly on
the breakpoint. If you now click on [Continue] several times, you can watch how every
individual number is examined to see if it is a prime number. The variable window
now shows the variable values of I and the other
variables and track in the Omikron Basic output window how the individual numbers
are marked as non-primes.
Now keep the [Ctrl] key depressed and clicked on the breakpoint in line 31. This removes the breakpoint. Set a new breakpoint in line 43 behind the THEN. Then click on [Continue]. The program will now always stop when a new line is started.
Remove the breakpoint again and click on [Continue]. All non-primes are marked and the program is in the waiting loop in line 45.
Click on [Stop]. The program halts in the waiting loop. This works only because the waiting loop contains an EVENT call (COMPILER "EVENT" or Easy_Mesag with EasyGem programming). If your program is in a loop without any EVENT calls, you can still stop the program using [Ctrl] +[C].
Click on [Terminate]. Eratosthenes is terminated, the Debugger Control is hided, and you can edit the source code again to calculate additional prime numbers, for example.
The second example does not contain any errors and serves only to illustrate the debugger functions further. Again, open a new program window and transfer the following program to an empty window using the 'Copy' and 'Paste' functions. Then you have to load the Extension Library with the menu option 'Merge LIBRARY'.
Then start the program with 'Debug'. As expected, it stops in line 22, directly
behind the STOP command. Now progress with [Step
into] until you reach line 58. Open a new variable window and there enter $Adr.
After pressing the [Return] key, the address of the memory block allocated in line
57 is depicted in the variable window as a hex number.
Open a new memory window and then the debugger settings using 'Mode/Preferences/Debugger'. In the now opened dialog, set 'Bytes per group' to 1, 'Bytes per line' to 8, 'Display bytes as' to decimal and 'Show character string' to off. Then click on [Execute]. The content of the memory window is now depicted in the form of three-digit decimal numbers. The character string display disappears. Now transfer the value shown in the variable window for Adr to the address field of the memory window using 'Copy' and 'Paste' and confirm with [Return].
If you now proceed through the program in individual steps, you can follow in the memory window how the random numbers are written to memory.
Return to the debugger settings and set the 'Animation delay' to 100. Then confirm with [Execute]. Make sure that the memory window and the window with the BASIC program remain visible and then click on [Animation] in the Debugger Control. You can now observe how the random numbers are written to memory every tenth of a second.
Once you have seen enough, click on [Stop] and then on [Step out]. This causes you to leave the procedure, and then you are located behind the call in line 25.
Set a new breakpoint in line 39 by pressing the [Ctrl] key and click in front of Set_Print_Size with your mouse button to then continue the program. The program stops in line 39. Now click on [Step into]. Although the next item to be executed is a procedure, the program pointer jumps to the next line because the procedure Set_Print_Size is located in a library.
Now bring the Omikron Basic output window to the front. Then click on [Animation]. You can now see how the statistical data are written to the Omikron Basic output window.
This example is a very simple program to easily show which values from MOUSEBUT
and INKEY$ are returned if certain keys are pressed. Again, open a new program window
and transfer the program to an empty window using the 'Copy' and 'Paste' function.
Go to the debugger preferences and activate 'Permanently update variable windows'. Then click on [Execute]. Open a new variable window and enter the variables %Mb and %Kbrd$.
Then start the program with 'Debug'. If you now press the mouse button alone or together with any modifier key, you can immediately see in the variable window which bits are set. The same applies to all normal keys of the keyboard. The thus generated ASCII codes, virtual key codes, and modifier key codes are displayed in Kbrd$.
© 1997-2001 Berkhan-Software