forked from larsbrinkhoff/lbForth
-
Notifications
You must be signed in to change notification settings - Fork 1
/
kernel.fth
323 lines (247 loc) · 8.8 KB
/
kernel.fth
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
\ -*- forth -*- Copyright 2004, 2013-2016 Lars Brinkhoff
\ This kernel, together with a target-specific nucleus, provides
\ everything needed to load and compile the rest of the system from
\ source code. And not much else. The kernel itself is compiled by
\ the metacompiler.
\ At a minimum, these 16 primitives must be provided by the nucleus:
\
\ Definitions: dodoes exit
\ Control flow: 0branch
\ Literals: (literal)
\ Memory access: ! @ c! c@
\ Arithmetic/logic: + nand
\ Return stack: >r r>
\ I/O: emit open-file read-file close-file
: noop ;
[undefined] sp@ [if]
variable SP
[then]
[undefined] rp@ [if]
variable RP
[then]
: cell cell ; \ Metacompiler knows what to do.
: cell+ cell + ;
?: sp@ SP @ cell + ;
?: sp! SP ! ;
?: rp@ RP @ cell + ;
\ rp! in core.fth
variable temp
?: drop temp ! ;
?: 2drop drop drop ;
: 3drop 2drop drop ;
?: r@ rp@ cell+ @ ;
?: swap >r temp ! r> temp @ ;
?: over >r >r r@ r> temp ! r> temp @ ;
?: rot >r swap r> swap ;
?: 2>r r> swap rot >r >r >r ;
?: 2r> r> r> r> rot >r swap ;
?: dup sp@ @ ;
?: 2dup over over ;
: 3dup >r >r r@ over 2r> over >r rot swap r> ;
?: ?dup dup if dup then ;
?: nip swap drop ;
?: invert -1 nand ;
?: negate invert 1 + ;
?: - negate + ;
?: branch r> @ >r ;
forward: <
: (+loop) r> swap r> + r@ over >r < invert swap >r ;
: unloop r> 2r> 2drop >r ;
?: 1+ 1 + ;
?: +! swap over @ + swap ! ;
?: 0= if 0 else -1 then ;
?: = - 0= ;
?: <> = 0= ;
: min 2dup < if drop else nip then ;
: bounds over + swap ;
: count dup 1+ swap c@ ;
: aligned cell + 1 - cell negate nand invert ;
?: (sliteral) r> dup @ swap cell+ 2dup + aligned >r swap ;
: i r> r@ swap >r ;
?: cr 10 emit ;
: type ?dup if bounds do i c@ emit loop else drop then ;
\ Put the xt inside the definition of EXECUTE, overwriting the last noop.
?: execute [ here cell + ] ['] noop ! then noop ;
?: perform @ execute ;
variable state
?: 0< [ 1 cell 8 * 1 - lshift ] literal nand invert if -1 else 0 then ;
?: or invert swap invert nand ;
?: xor 2dup nand 1+ dup + + + ;
?: < 2dup xor 0< if drop 0< else - 0< then ;
: cmove ( addr1 addr2 n -- ) ?dup if bounds do count i c! loop drop
else 2drop then ;
: cabs 127 over < if 256 swap - then ;
0 value latest
0 value latestxt
include dictionary.fth
: code, code! cell allot ;
: (does>) r> does! ;
0 value stdin
include target.fth
: lowercase? ( c -- flag ) dup [char] a < if drop 0 exit then [ char z 1+ ] literal < ;
: upcase ( c1 -- c2 ) dup lowercase? if [ char A char a - ] literal + then ;
: c<> ( c1 c2 -- flag ) upcase swap upcase <> ;
: name= ( ca1 u1 ca2 u2 -- flag )
2>r r@ <> 2r> rot if 3drop 0 exit then
bounds do
dup c@ i c@ c<> if drop unloop 0 exit then
1+
loop drop -1 ;
: nt= ( ca u nt -- flag ) >name name= ;
: immediate? >nfa c@ 127 swap < if 1 else -1 then ;
\ TODO: nt>string nt>interpret nt>compile
\ Forth83: >name >link body> name> link> n>link l>name
: traverse-wordlist ( wid xt -- ) ( xt: nt -- continue? )
>r >body @ begin dup while
r@ over >r execute r> swap
while >nextxt
repeat then r> 2drop ;
: ?nt>xt ( -1 ca u nt -- 0 xt i? 0 | -1 ca u -1 )
3dup nt= if >r 3drop 0 r> dup immediate? 0
else drop -1 then ;
: (find) ( ca u wl -- ca u 0 | xt 1 | xt -1 )
2>r -1 swap 2r> ['] ?nt>xt traverse-wordlist rot if 0 then ;
: search-wordlist ( ca u wl -- 0 | xt 1 | xt -1 )
(find) ?dup 0= if 2drop 0 then ;
defer abort
defer (abort")
: undef ( a u -- ) ." Undefined: " type cr abort ;
: ?undef ( a u x -- a u ) if undef then ;
: literal compile (literal) , ; immediate
: ?literal ( x -- ) state @ if [compile] literal then ;
defer number
\ Sorry about the long definition, but I didn't want to leave many
\ useless factors lying around.
: (number) ( a u -- )
over c@ [char] - = dup >r if swap 1+ swap 1 - then
0 rot rot
begin dup while
over c@ [char] 0 - -1 over < while dup 10 < while
2>r 1+ swap dup dup + dup + + dup + r> + swap r> 1 -
repeat then drop then
?dup ?undef drop r> if negate then ?literal ;
variable >in
variable input
: input@ ( u -- a ) cells input @ + ;
: 'source 0 input@ ;
: #source 1 input@ ;
: source# 2 input@ ;
: 'refill 3 input@ ;
: 'prompt 4 input@ ;
: source> 5 input@ ;
6 cells constant /input-source
create forth 2 cells allot
create compiler-words 2 cells allot
create search-paths 2 cells allot
create included-files 2 cells allot
create context 9 cells allot
: r@+ r> r> dup cell+ >r @ swap >r ;
: search-context ( a u context -- a 0 | xt ? ) >r begin r@+ ?dup while
(find) ?dup until else drop 0 then r> drop ;
: find-name ( a u -- a u 0 | xt ? ) swap over #name min context
search-context ?dup if rot drop else swap 0 then ;
: source 'source @ #source @ ;
: source? ( -- flag ) >in @ source nip < ;
: <source ( -- char|-1 ) source >in @ dup rot = if
2drop -1 else + c@ 1 >in +! then ;
: blank? 33 < ;
: skip ( "<blanks>" -- ) begin source? while
<source blank? 0= until -1 >in +! then ;
: parse-name ( "<blanks>name<blank>" -- a u ) skip source drop >in @ +
0 begin source? while 1+ <source blank? until 1 - then ;
: (previous) ['] forth context ! ;
defer also
defer previous
defer catch
create interpreters ' execute , ' number , ' execute ,
: ?exception if cr ." Exception!" cr then ;
: interpret-xt 1+ cells interpreters + @ catch ?exception ;
: [ 0 state ! ['] execute interpreters ! previous ; immediate
: ] 1 state ! ['] compile, interpreters !
also ['] compiler-words context ! ;
variable csp
: .latest latestxt >name type ;
: ?bad rot if type ." definition: " .latest cr abort then 2drop ;
: !csp csp @ s" Nested" ?bad sp@ csp ! ;
: ?csp sp@ csp @ <> s" Unbalanced" ?bad 0 csp ! ;
: ; reveal compile exit [compile] [ ?csp ; immediate
\ ----------------------------------------------------------------------
( Core extension words. )
: refill 0 >in ! 0 #source ! 'refill perform ;
: ?prompt 'prompt perform ;
: source-id source# @ ;
256 constant /file
: file-refill 'source @ /file bounds do
i 1 source-id read-file if 0 unloop exit then
0= if source nip unloop exit then
i c@ 10 = if leave then
1 #source +!
loop -1 ;
0 value file-source
: save-input >in @ input @ 2 ;
: restore-input drop input ! >in ! 0 ;
defer backtrace
: sigint cr backtrace abort ;
\ These will be set in COLD, or by the metacompiler.
0 constant sp0
0 constant rp0
0 constant dp0
variable limit
0 constant image0
0 constant latest0
defer parsed
: (parsed) ( a u -- ) find-name interpret-xt ;
: ?stack sp0 sp@ cell+ < abort" Stack underflow" ;
: interpret begin parse-name dup while parsed ?stack repeat 2drop ;
: interpreting begin refill while interpret ?prompt repeat ;
: 0source 'prompt ! 'refill ! source# ! 'source ! 0 source> ! ;
: source, ( 'source sourceid refill prompt -- )
input @ >r here input ! /input-source allot 0source r> input ! ;
: file, 0 0 ['] file-refill ['] noop source, /file allot ;
: +file here source> ! file, ;
: file> source> @ ?dup if input ! else +file then ;
: alloc-file file-source input ! begin 'source @ while file> repeat ;
: file-input ( fileid -- ) alloc-file source# ! 6 input@ 'source ! ;
: include-file ( fileid -- ) save-input drop 2>r
file-input interpreting source-id close-file drop 0 'source !
2r> 2 restore-input abort" Bad restore-input" ;
: +string 2dup 2>r + over >r swap cmove r> 2r> rot + ;
: pathname >r 2dup r> >name here 0 +string +string ;
: ?include if drop 1 else >r 2drop r> include-file 0 0 then ;
: ?open ( a u nt -- a u 1 | 0 0 ) pathname r/o open-file ?include ;
: ?error abort" File not found" ;
: search-file ['] search-paths ['] ?open traverse-wordlist ?error ;
: >current ( wl1 -- ) ( R: -- wl2 ) current @ r> 2>r current ! ;
: current> r> r> current ! >r ;
: +name ( a u wl -- ) >current header, 0 , reveal current> ;
: remember-file ['] included-files +name ;
: included 2dup remember-file search-file ;
: searched ( a u -- ) ['] search-paths +name ;
: dummy-catch execute 0 ;
defer quit
: warm
io-init
." lbForth" cr
dp0 dp !
['] noop dup is backtrace is also
['] dummy-catch is catch
['] (number) is number
['] (parsed) is parsed
['] (previous) is previous
latest0 dup to latestxt forth !
['] forth current !
here to file-source file,
0 forth cell+ !
0 compiler-words ! ['] forth compiler-words cell+ !
0 search-paths ! ['] compiler-words included-files cell+ !
0 included-files ! ['] search-paths included-files cell+ !
['] forth dup context ! context cell+ ! 0 context 2 cells + !
s" src/" searched \ UGLY HACK
sysdir searched
s" " searched
[compile] [
s" load.fth" included
." ok" cr
quit ;
\ NOTE: THIS HAS TO BE THE LAST WORD IN THE FILE!
defer turnkey ' warm is turnkey