1     Now that CREATE seems to work (making our new word's
     
2     dictionary entry header, we can take a look at the
     
3     rest of the words in COLON, starting with LIT.
     
4 
     5     Jones has a good explanation of LIT in the original
     
6     source. In short, it lets you get the address of a
     
7     word without executing that word. So:
     
8 
     9         LIT DOCOL COMMA
    
10 
    11     pushes the address of DOCOL on the stack for COMMA
    
12     to use.
    
13 
    14     The way it works is really clever. It basically works
    
15     just like the NEXT macro, except instead of jumping
    
16     to the address to execute it, LIT pushes the address
    
17     on the stack so it will be avaiable for the next
    
18     command.
    
19 
    20     Here's LIT:
    
21 
    22         lodsd
    
23         push eax
    
24 
    25     Here's NEXT:
    
26 
    27         lodsd
    
28         jmp [eax]
    
29 
    30     In both cases, lodsd stores the value pointed to by esi
    
31     in eax and then increments esi by 4 so it points to the
    
32     next word.
    
33 
    34     What's clever about this is that the lodsd will end up
    
35     being called twice and the word we just got the address
    
36     for will be skipped, not executed.
    
37 
    38     So here it is and the symbol pushed on the stack should
    
39     be DOCOL.
    
40 
    41 code_LIT () at nasmjf.asm:493
    
42 493         lodsd                   ; loads the value at esi into eax, incements esi
    
43 494         push eax                ; push the literal number on to stack
    
44 (gdb) info sym $eax
    
45 DOCOL in section .text of /home/dave/nasmjf/nasmjf
    
46 
    47     Cool, continuing on, NEXT calls COMMA, which just
    
48     pops the address back off the top of the stack
    
49     and then stores it at HERE. So that's how
    
50 
    51         LIT DOCOL COMMA
    
52 
    53     puts the address of DOCOL into the definition of
    
54     our new word. Neat. :-)
    
55 
    56 (NEXT macro snipped)
    
57 code_COMMA () at nasmjf.asm:590
    
58 590         pop eax                ; Code pointer to store.
    
59 591         call _COMMA
    
60 594         mov edi, [var_HERE]
    
61 595         stosd                  ; puts the value in eax at edi, increments edi
    
62 596         mov [var_HERE], edi
    
63 597         ret
    
64 
    65     Next, we'll get the address of our new word from
    
66     LATEST, fetch it,
    
67 
    68         dd LATEST, FETCH, HIDDEN ; Make the word hidden while it's being compiled.
    
69 
    70     ; FETCH (@) grabs a value from an address on the stack and
    
71     ; puts that value on the stack.
    
72     ;
    
73     ; HIDDEN toggles the hidden flag for the dictionary entry
    
74     ; at the address on the stack
    
75 
    76     And LATEST is a variable that pushes the current
    
77     word's address onto the stack.
    
78 
    79         !!!!!!!!!!!!!!!!!!!! Update !!!!!!!!!!!!!!!!!!!!
    
80         ! In log19.txt, I realize that my variable     !
    
81         ! handling is wrong. Variables should leave    !
    
82         ! their addresses on the stack, not their      !
    
83         ! values! We need FETCH to get the value from  !
    
84         ! the address!                                 !
    
85         !!!!!!!!!!!!!!!!!!!! Update !!!!!!!!!!!!!!!!!!!!
    
86 
    87     LATEST makes sense: we'll get the word's address in order
    
88     to toggle its hidden flag so a partially-compiled word
    
89     won't show up in any dictionary searches (which I guess could
    
90     happen if a word relied on a previous definition of itself?)
    
91 
    92 (NEXT macro snipped)
    
93 code_LATEST () at nasmjf.asm:771
    
94 771         push dword [var_%4]
    
95 (NEXT macro snipped)
    
96 
    97     But I confess that I don't understand why we're using FETCH
    
98     after LATEST. LATEST has the address of the current word
    
99     being compiled. FETCH pops an address and pushes the value
   
100     at that address. And the value at the beginning of every word
   
101     "header" is a link to the previous word in the dictionary's
   
102     linked list.
   
103 
   104     So won't HIDDEN be toggling the previous word, not the
   
105     current word? Doesn't FETCH return the linked word?
   
106 
   107 code_FETCH () at nasmjf.asm:630
   
108 630         pop ebx                 ; address to fetch
   
109 631         mov eax, [ebx]          ; fetch it
   
110 632         push eax                ; push value onto stack
   
111 (NEXT macro snipped)
   
112 code_HIDDEN () at nasmjf.asm:636
   
113 636         pop edi                 ; Dictionary entry, first byte is link
   
114 637         add edi, 4              ; Move to name/flags byte.
   
115 638         xor [edi], word F_HIDDEN  ; Toggle the HIDDEN bit in place.
   
116 (gdb) x/bx $edi
   
117 0x804a3b0:      0x06
   
118 (gdb) x/6c $edi + 1
   
119 0x804a3b1:      76 'L'  65 'A'  84 'T'  69 'E'  83 'S'  84 'T'
   
120 
   121     Uh, yeah, that's LATEST. Either this is a bug in the original
   
122     or I made a mistake somewhere. The later seems more likely.
   
123     This isn't a showstopper, though. Compilation can work without
   
124     it.
   
125 
   126     This next part is amazing: so to re-use all the same mechanisms
   
127     for input and word lookup, etc, FORTH just sets the state to
   
128     "compiling mode". Then "EXITs" back to input to get the rest
   
129     of the word definition.
   
130 
   131 (NEXT macro snipped)
   
132 code_RBRAC () at nasmjf.asm:613
   
133 613         mov [var_STATE], word 1   ; Set STATE to 1 (compile)
   
134 (NEXT macro snipped)
   
135 code_EXIT () at nasmjf.asm:44
   
136 44          mov %1, [ebp]
   
137 45          lea ebp, [ebp+4]
   
138 (NEXT macro snipped)
   
139 code_gtfo () at nasmjf.asm:214
   
140 214         mov ebx, 0    ; exit code
   
141 215             mov eax, 1    ; exit syscall
   
142 216         int 80h       ; call kernel
   
143 [Inferior 1 (process 2529) exited normally]
   
144 
   145     So two things to address:
   
146 
   147         1. I guess remove the FETCH (@) and see if HIDDEN hides
   
148            the correct word.
   
149         2. Add BRANCH so the interpreter an keep on getting input
   
150            for the compilation of our new word!