11.22Debugging. 4tH 4tH Forth compiler
Quảng cáo
Quảng cáo
CHAPTER 11. ADVANCED PROGRAMMING
Change it to:
32 string argument
1 args argument ~~ place
160
Now the breakpoint is enabled. It will enter a Forth-like shell just before ’PLACE’ is executed. Now a host of words are at your disposal. You can examine any region of the
Character Segment with ”DUMP” or print any string variable with ”TYPE”. 4tHs internal variables and regions are known by name, like ”PAD”, ”TIB”, ”>IN”, ”BASE” and ”OUT”.
You can examine them or any other variable by using ”?”, ”@” and ”.”.
You have a small calculator, that you can use to multiply, substract, add. You can change
’BASE’ by executing ”OCTAL”, ”HEX”, ”BINARY” or ”DECIMAL”. It also has a host of binary operators like ”OR”, ”AND”, ”XOR”, ”INVERT”, ”LSHIFT” and ”RSHIFT”. It also has stack operators like ”DUP”, ”DROP”, ”OVER” and ”SWAP”. ”CLEAR” will clear the stack for you.
You can examine both stacks. ”.S” will show you the data stack (including any rubbish you put there yourself during the debugging session) and ”R.S” will show you the return stack.
”DEPTH” and ”RDEPTH” will tell you how many items there are on the stack. When you’re done, you may leave the debugger by typing ”BYE”. Your program will continue as usual.
A word of caution : since the debugger is a 4tH program itself, it doesn’t actually freeze the virtual machine. It just seems like it is frozen. The contents of PAD may be slightly different than you expected. If you really need to examine the PAD as it was, don’t examine it directly, but use ”SPAD” to examine the ”shadow PAD”. ”SPAD” leaves the address for the ”shadow PAD” on the stack. The same goes for ”>IN”, ”BASE” and ”OUT”: never examine these by address, but always by name. Although every effort has been made to catch any errors, some extreme stress tests might fail. It is not recommended to use the debugger when stack space is very tight.
11.22
Debugging
We’ve all been there. You’ve written a non-trivial program and when you try to run it, it bombs out with an error message. Then the question arises: ”Where did I go wrong?”
This proces is called ”debugging”. Debugging is very hard without any dedicated tools.
Modern development systems include a debugger, featuring breakpoints, single stepping and variable tracking.
4tH features the following tools:
• Stack examination
• Assertions
12
• Breakpoints
13
• Decompilation
• Preprocessor
• Compiler directives
12
See section 11.20.
13
See section 11.21.
CHAPTER 11. ADVANCED PROGRAMMING 161
First of all, you need to understand how the 4tH compiler works. Initially the tokenizer collects all 4tH sources and breaks them down to tokens. A token is a word or a string.
This makes it much easier for the compiler to parse the source
14
. 4tH has a single pass compiler, so after the tokenizer has finished successfully, it will start compiling right away.
Even if the compiler encounters an error, it has actually compiled something. The point where the compiler stops gives you clues on where it went wrong. 4tH doesn’t discard this partial compilant, but keeps it in memory so you can examine it. It won’t allow any other action.
If you managed to successfully compile the source, it will pass the compilant to the virtual machine to execute it. Again, the point where the virtual machine stops is retained. Having one external editor window open with the 4tH source and another with 4tH itself is one the most comfortable ways to debug 4tH code.
If you get the dreaded I/O error 4tH is probably unable to locate an include file. You can use the preprocessor to find out where you went wrong. The preprocessor mimics the include sequence and leaves a 4tH file you can examine. You can also place an ’[ABORT]’ directive after the inclusion of each file to see when the I/O error pops up.
Tokenizer errors can also be produced by improperly formatted strings, like empty strings or missing delimiters. Highlighting editors like SciTE
15 allow you to find most of these pretty quickly. If not, you have to resort to the ’[ABORT]’ directive again because 4tH leaves no indication where you went wrong. The easiest way to track compilation errors is by decompiling the partial compilant, e.g.:
: one dup ." This is the address of TWO: " . cr drop ;
: two here one ;
: three 10 0 do [char] * emit loop cr ;
: four tree two tree ; four
Doesn’t compile. This will tell you where it went wrong:
[ 11] literal
[ 12] literal
[ 13] do
[ 14] literal
[ 15] emit
[ 16] loop
[ 17] cr
[ 18] exit
[ 19] branch
(10)
(0)
(16)
(42)
(0)
(13)
(0)
(0)
(0)
It may be a bit hard to read, but you can clearly see it went wrong shortly after the ’LOOP’.
Yes, ”TREE” is misspelled. If you are unable to locate the error, again ’[ABORT]’ can help you out - but most of the time these drastic measures are not required.
If you suspect that runtime errors may occur in a certain piece of code, you can use assertions
16 to detect them. Although a well placed breakpoint
17 may help you out, it is annoying to stop and restart the program with each interation. For that reason a simple stack dump using ”.S” may be more efficient:
14
The tokenizer ignores the source layout, which means 4tH is able to read almost any ASCII file, regardless format. The downside of it all is that 4tH can’t tell you on which line an error occurred - simply because it doesn’t tokenize or compile on a line-by-line basis.
15 http://www.scintilla.org/SciTE.html
16
See section 11.20.
17
See section 11.21.
Tải xuống
Quảng cáo