colorful rat Ratfactor.com > Dave's Repos

nasmjf

A NASM assembler port of JONESFORTH
git clone http://ratfactor.com/repos/nasmjf/nasmjf.git

nasmjf/devlog/log10.txt

Download raw file: devlog/log10.txt

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!