1     Now we come to a bit of a challenge. The method of
     
2     starting JonesFORTH with the rest of the language
     
3     implementation *and* still allowing user input on
     
4     STDIN is quite clever:
     
5 
     6         cat jonesforth.f - | ./jonesforth 
     
7 
     8     That is, have cat read the FORTH source file and then
     
9     whatever is supplied on STDIN (using the standard
    
10     '-' parameter to indicate STDIN in place of a file)
    
11     and pipe the lot to the jonesforth executable.
    
12 
    13     Unfortunately, it crashes my port:
    
14 
    15 eeepc:~/nasmjf$ cat jonesforth/jonesforth.f - | ./nasmjf
    
16 
    17 Segmentation fault
    
18 
    19     So we have a problem.
    
20 
    21     And this is turning out to be hard to test.
    
22 
    23     Well, it seems there are a couple routes I could take
    
24     here:
    
25 
    26     1. Hand-type the contents of jonesforth.f and see what
    
27        causes the crash. I'm okay with the effort - I plan
    
28        to go through that source line-by-line to understand
    
29        it anyway. But the problem is: how do I incrementally
    
30        save what I've typed so far?
    
31 
    32     2. Use divide-and-conquer to find out how much of
    
33        'jonesforth.f' I can run before we get a crash. That
    
34        would probably work - but it's going to be an annoying
    
35        process and I'll be working blind.
    
36 
    37     3. Figure out how to read in 'jonesforth.f' on startup
    
38        as part of the executable. This will allow debugging
    
39        in GDB to continue (no doubt I could figure out some
    
40        arcane way of redirecting or piping that to STDIN
    
41        while in a GDB session or attach to the process or
    
42        something...but I'm not enthusiastic about figuring
    
43        that out. I'd rather write code.)
    
44 
    45     As you can likely guess, I'm going with Option 3. I'm going
    
46     to have the nasmjf executabe read 'jonesforth.f' upon
    
47     startup. The plan is something like this:
    
48 
    49     A. Open the file using syscalls
    
50     B. Read into a fixed-size reserved buffer
    
51     C. Keep track of line numbers for reference?
    
52     D. Feed the source into the interpreter somehow
    
53     E. Now I can debug the crash?
    
54     F. When EOF reached, close the file and start accepting
    
55        interpreter input from STDIN again.
    
56 
    57     The only challenging part, it seems to me, is D: feeding the
    
58     file into the interpreter. Words like KEY are currently
    
59     hard-coded to read from STDIN, right? So maybe I need a global
    
60     switch to read from my line buffer instead?
    
61 
    62     Let's get started!
    
63 
    64     For A, I've got this near the top:
    
65 
    66         SECTION .bss
    
67         line_buffer:  resb 1024 ; for storing source lines from file
    
68 
    69     Then
    
70 
    71         SECTION .data
    
72         jfsource:   db "jonesforth/jonesforth.f", 0h
    
73 
    74     And then reading the file - another snippet adapted from
    
75     asmtutor.com!
    
76 
    77 
    78 Breakpoint 1, _start () at nasmjf.asm:82
    
79 82          cld    ; Clear the "direction flag" which means the string instructions (such
    
80       ...
    
81 118         mov ecx, 0                ; read only flag for open
    
82 119         mov ebx, jfsource
    
83 120         mov eax, __NR_open
    
84 121         int 80h                   ; fd now in eax
    
85 124         mov edx, 1024              ; amt to read
    
86 125         mov ecx, line_buffer       ; address of .bss reserved space
    
87 126         mov ebx, eax               ; fd from pushed eax above
    
88 127         mov eax, __NR_read
    
89 128         int 80h
    
90 (gdb) x/s (int)&line_buffer
    
91 0x804db30 <line_buffer>:        "\\ -*- text -*-\n\\\tA sometimes minimal FORTH
    
92 compiler and tutorial for Linux / i386 systems. -*- asm -*-\n\\\tBy Richard W.M.
    
93 Jones <rich@annexia.org> http://annexia.org/forth\n\\\tThis is PUBLIC DOMAIN"...
    
94 
    95     Awesome! Of course it works. It's a trivial operation, even
    
96     in assembly.
    
97 
    98     Anyway, now to figure out how to feed the source into the
    
99     interpreter.
   
100 
   101     Weeks have passed. Progress has gone at a snail's pace and
   
102     I've often fallen asleep with barely a single assembly
   
103     instruction written.
   
104 
   105     Nevertheless, I think I'm getting close.
   
106 
   107     TIME PASSES...
   
108 
   109     Okay, a month later and I've got it reading a test.f file
   
110     to make sure I can read in N lines of a Forth source file
   
111     when the interpreter starts and then hand input back to
   
112     the keyboard.
   
113 
   114     Here's the entirety of test.f:
   
115 
   116         1 .
   
117         2 .
   
118         3 .
   
119         4 .
   
120         5 .
   
121         6 .
   
122         7 .
   
123         8 .
   
124 
   125     So it's just Forth for printing the line number on each line
   
126     so I can see if it correctly stops after six lines.
   
127 
   128         jfsource: db "test.f" , 0h
   
129         %assign __lines_of_jf_to_read 6
   
130 
   131     What does it look like when it runs? Let's find out:
   
132 
   133 123456
   
134 
   135     Yay! It reads and executes six lines, then waits for user input.
   
136     Perfect!
   
137 
   138     This took about a month because of a ton of stupid bugs, off-by-
   
139     one errors, and that sort of thing. But mostly because I was
   
140     really tired and kept falling asleep.
   
141 
   142     Anyway, now I can read N lines of jonesforth.f and test it out
   
143     a bit at a time!
   
144 
   145     Next night: okay, here goes nothing:
   
146 
   147         jfsource:   db "jonesforth/jonesforth.f", 0h
   
148         %assign __lines_of_jf_to_read 52
   
149 
   150     This reads to line 52 of jonesforth.f, which is a bunch of comments
   
151     and a definiton of / and MOD:
   
152 
   153         : / /MOD SWAP DROP ;
   
154         : MOD /MOD DROP ;
   
155 
   156 10 5 / .
   
157 2
   
158 10 5 MOD .
   
159 0
   
160 10 3 / .
   
161 3
   
162 10 3 MOD .
   
163 1
   
164 
   165     Wow, that actually works! So now I can start logging my
   
166     progress as I load and test more of the FORTH portion of
   
167     the JonesFORTH implementation.
   
168 
   169     Now I'm loading to line 70, which contains definitions for
   
170     some more handy primitives.
   
171 
   172     I'll test them out now:
   
173 
   174 3 5 . SPACE .
   
175 5 3
   
176 
   177 3 5 . CR .
   
178 5
   
179 3
   
180 
   181 3 NEGATE .
   
182 4294967293
   
183 
   184 TRUE .
   
185 1
   
186 FALSE .
   
187 0
   
188 TRUE NOT .
   
189 0
   
190 FALSE NOT .
   
191 1
   
192 
   193     Heh, I'll just trust at the negaative value is correct for
   
194     now.
   
195 
   196     So, this is great. I'll just keep working my way down
   
197     jonesforth.f until I've tested everything and/or reproduced
   
198     the crash I was experiencing before.