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!