SEE - Cute parlor trick or useful diagnostic tool?
Posted: Sat Jan 26, 2019 1:46 am
SEE is defined on some Forth systems to reconstruct ( or try to reconstruct) the source of a Forth word. This seems to me to be a cute parlor trick, especially if the Forth source is readily available.
I feel that SEE can be a useful tool if, instead of attempting to show the source of a Forth word, it shows what actually got compiled. Here are my criteria for a useful SEE:
1 Display what was compiled for Forth words and code words.
2 Recognize the built in data types ( VARIABLE , CONSTANT , 2VARIABLE , 2CONSTANT , and USER ) and display their values.
3 Display a DEFERed word's vector ( the word a DEFERed word is set to execute) .
4 Transition seamlessly from decompiling/disassembling High level code to Low level and back. For example:
Notice that in these examples DOES , the primitive compiled by DOES> and ;CODE , sets the code field of the latest word in the current vocabulary to point to the code following DOES and exits. These defining words do not transition from high level code to low level, but the decompiler does.
5 SEE is just a wrapper word for (SEE) so (SEE) can take a CFA from the data stack.
6 Know when to stop decompiling and when, or if, it should transition from high or low level to the other.
7 Defined with helper words :DIS and DIS that decompile : ( colon) definitions and code definitions respectively. In some situations, the ones that 'trip up' SEE , it is useful to decompile a Forth word starting on a word boundary, inside the body of the definition, with :DIS ,or disassemble a low level word starting on an instruction boundary, with DIS . This example is a partial disassembly of FIND , the high level word that uses (FIND) and VFIND , the find primitives.
The full disassembly of FIND for comparison:
8 A word like DONE? is included in the definition of the decompiler(s) which can pause the listing and wait if a key is pressed or return with a flag. It is possible SEE will encounter a situation that makes it keep decompiling because none of the stop criteria are met, especially if it's used to examine the code of a new construct like DOER/MAKE .
DONE? is used like this:
The loop in SOME.FORTH.WORD keeps running until the test condition is true or the C64's STOP key is pressed ( DONE? returned a TRUE, we're done. If any other key is pressed, DONE? will wait for a key press. If the stop key is pressed, a TRUE flag is returned, otherwise FALSE is returned.
A SEE written with these criteria in mind, along with DUMP , a word to display memory contents, can be a useful tool when performing a 'postmortem' after an attempt to add some new feature to one's Forth fails.
Cheers,
Jim
I feel that SEE can be a useful tool if, instead of attempting to show the source of a Forth word, it shows what actually got compiled. Here are my criteria for a useful SEE:
1 Display what was compiled for Forth words and code words.
2 Recognize the built in data types ( VARIABLE , CONSTANT , 2VARIABLE , 2CONSTANT , and USER ) and display their values.
3 Display a DEFERed word's vector ( the word a DEFERed word is set to execute) .
4 Transition seamlessly from decompiling/disassembling High level code to Low level and back. For example:
Code: Select all
SEE 2CONSTANT
2CONSTANT
2F0E CREATE
2F10 ,
2F12 ,
2F14 DOES
2F16 2429 JMP ' DOES> >BODY 15 +
2F19 2@
2F1B EXIT
OK
SEE CONSTANT
CONSTANT
23CF CREATE
23D1 ,
23D3 DOES
23D5 2 # LDY
23D7 FE )Y LDA W
23D9 PHA
23DA INY
23DB FE )Y LDA W
23DD 838 JMP PUSH
OK
SEE DEFER
DEFER
23A6 CREATE
23A8 LIT 237C
23AC ,
23AE DOES
23B0 2 # LDY
23B2 FE )Y LDA W
23B4 PHA
23B5 INY
23B6 FE )Y LDA W
23B8 FF STA W 1+
23BA PLA
23BB FE STA W
23BD 0 # LDY
23BF FD JMP W 1-
OK
5 SEE is just a wrapper word for (SEE) so (SEE) can take a CFA from the data stack.
Code: Select all
: SEE ( -- ) ' (SEE) ;
7 Defined with helper words :DIS and DIS that decompile : ( colon) definitions and code definitions respectively. In some situations, the ones that 'trip up' SEE , it is useful to decompile a Forth word starting on a word boundary, inside the body of the definition, with :DIS ,or disassemble a low level word starting on an instruction boundary, with DIS . This example is a partial disassembly of FIND , the high level word that uses (FIND) and VFIND , the find primitives.
Code: Select all
2091 :DIS
2091 CURRENT
2093 @
2095 VFIND
2097 EXIT
OK
Code: Select all
SEE FIND
FIND
2087 CONTEXT
2089 @
208B (FIND)
208D ?DUP
208F ?EXIT
2091 CURRENT
2093 @
2095 VFIND
2097 EXIT
OK
Code: Select all
: DONE? ( -- F )
?KEY DUP 0EXIT
3 = ?DUP ?EXIT
KEY 3 = ;
Code: Select all
: SOME.FORTH.WORD
BLAH BLAH BLAH
BEGIN
BLAH BLAH BLAH
TEST.CONDITION DONE? OR
UNTIL
BLAH BLAH ;
A SEE written with these criteria in mind, along with DUMP , a word to display memory contents, can be a useful tool when performing a 'postmortem' after an attempt to add some new feature to one's Forth fails.
Cheers,
Jim