1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2 ;; UrForth level
1: self
-hosting
32-bit Forth compiler
3 ;; Copyright
(C
) 2020 Ketmar Dark
// Invisible Vector
5 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
7 voc
-set
-active COMPILER
10 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
11 ;; each of these has one argument
14 value
(CTLID
-IF) (hidden
)
15 value
(CTLID
-ELSE) (hidden
)
17 value
(CTLID
-BEGIN
) (hidden
)
18 value
(CTLID
-WHILE) (hidden
)
20 value
(CTLID
-CASE
) (hidden
)
21 value
(CTLID
-OF
) (hidden
)
22 value
(CTLID
-ENDOF
) (hidden
)
23 value
(CTLID
-OTHERWISE
) (hidden
)
25 value
(CTLID
-DO) (hidden
)
26 value
(CTLID
-DO-BREAK) (hidden
)
27 value
(CTLID
-DO-CONTINUE) (hidden
)
29 value
(CTLID
-CBLOCK
) (hidden
)
30 value
(CTLID
-CBLOCK
-INTERP
) (hidden
)
32 value
(CTLID
-?
DO) (hidden
)
34 value
(CTLID
-COLON
) (hidden
)
35 value
(CTLID
-DOES
) (hidden
)
36 value
(CTLID
-SC
-COLON
) (hidden
)
39 value
(XX
-CTLID
-LAST
) (hidden
)
42 (XX
-CTLID
-LAST
) var
(XX
-CTLID
-NEXT
-USER
) (hidden
)
44 : allocate
-ctlid
( -- id
) (xx
-ctlid
-next
-user
) @
(xx
-ctlid
-next
-user
) 1+! ;
47 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
49 ;; there might be a lot of
"while" blocks
, pop them all
50 ;; compile jump back
to begin
51 : (END-BEGIN
) ( pairs
... jumpcfa
-- )
52 ;; this is done recursively
, because this way i can get rid of `par_resolve_jfwd_over_branch`
53 ;; also
, we don
't have working loops at this point, so recursion is the only choice ;-)
55 over (CTLID-BEGIN) = if
56 optimiser:jpush-branch
68 : (COMP-WHILE) ( jumpcfa )
70 >r (CTLID-BEGIN) (CTLID-WHILE) ?pairs-any-keepid r>
71 optimiser:jpush-branch
78 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
79 ;; alas, i had to use one global var
80 ;; <>0: drop when we'll see CASE
81 ;; set
to 0 by
(CTLID
-OF
) or
(CTLID
-OTHERWISE
)
82 $value
"(B/C-CASE-DROP)" 0
85 ;; workhorse
for break/continue
89 : (BREAK/CONTINUE) ( type
)
91 0 2>r
;; type and counter
92 ;; drop on case by
default
96 ;; check
for valid ctlid
97 dup
(CTLID
-DO-CONTINUE) > over
(CTLID
-IF) < or ERR
-INVALID
-BREAK-CONT ?error
98 ;; while not begin and not
do
99 dup
(CTLID
-BEGIN
) = over
(CTLID
-DO) = or not
103 ;; 2dup pardottype
"SAVE: ctlid: " dot pardottype
" addr: " udot cr
105 ;; if we
're in (CTLID-CASE) or in (CTLID-ENDOF), compile DROP
106 dup (CTLID-CASE) = if
109 ;; pardottype " compiling DROP (" dup dot pardottype ")" cr
112 ;; drop on next case by default
115 dup (CTLID-OF) = over (CTLID-OTHERWISE) = or
116 if 0 to (b/c-case-drop) endif ;; don't drop on next case by
default
117 2r
> 2swap
>r
>r
2+ 2>r
119 ;; return stack contains saved values and counter
123 1 rpick
;; peek the type
126 ;; pardottype
"DO/LOOP: continue" cr
127 ;; coninue
: jump
to (LOOP
)
128 optimiser
:jpush
-branch
133 ;; break: drop
do args
, jump over
(LOOP
)
135 ;; pardottype
"DO/LOOP: break" cr
136 compile unloop
;; remove
do args
137 optimiser
:jpush
-branch
145 1 rpick
;; i
.e
. peek the type
149 ;; pardottype
"BEGIN: continue" cr
150 dup
;; we still need the address
151 optimiser
:jpush
-branch
154 (CTLID
-BEGIN
) ;; restore ctlid
158 ;; pardottype
"BEGIN: break" cr
159 (CTLID
-BEGIN
) ;; restore ctlid
160 optimiser
:jpush
-branch
167 ;; move saved values back
to the data stack
168 r
> rdrop
;; drop type
170 ;; dup pardottype
"RESTORE " dot pardottype
"items" cr
171 begin ?dup
while r
> swap
1- repeat
173 ;; dup
. over udot cr
177 : (END-LOOP
) ( endloopcfa
)
178 ;; this is done recursively
, because this way i can get rid of `par_resolve_jfwd_over_branch`
181 \ optimiser
:jpush
-branch
;; this compiles
"(loop)" kind
, it won
't be optimised anyway
185 ;; resolve ?DO jump, if it is there
186 dup (CTLID-?DO) = if drop (resolve-j>) endif
188 ;; "continue" should be compiled before recursion, and "break" after it
190 dup (CTLID-DO-CONTINUE) = if
191 ;; patch "continue" branch
192 (CTLID-DO-CONTINUE) ?pairs
196 (CTLID-DO-BREAK) ?pairs
198 ;; here, loop branch already compiled
205 : (X-OF) ( ... word-to-compare )
208 (CTLID-CASE) (CTLID-ENDOF) ?pairs-any-keepid ;; we should be in normal CASE
209 \ compile over ;; special compare words will do this for us
210 r> compile, ;; comparator
211 \ optimiser:jpush-branch ;; there is no real reason to check such jumps; and we may have A LOT of them
218 dup (CTLID-OTHERWISE) = if
219 ;; "otherwise", no drop needed
220 (CTLID-OTHERWISE) ?pairs
221 0 ?pairs ;; check dummy argument
223 ;; no "otherwise", compile DROP
235 0 ?pairs ;; check dummy argument
242 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
245 optimiser:jpush-branch
253 optimiser:jpush-branch
259 ;; if negative (not zero)
262 optimiser:jpush-branch
268 ;; if positive (not zero)
271 optimiser:jpush-branch
277 ;; if negative or zero
280 optimiser:jpush-branch
286 ;; if positive or zero
289 optimiser:jpush-branch
296 compiler:?comp compiler:(CTLID-IF) compiler:?pairs
297 optimiser:jpush-branch
300 swap compiler:(resolve-j>)
301 compiler:(CTLID-ELSE)
306 compiler:(CTLID-IF) compiler:(CTLID-ELSE) compiler:?any-pair
307 compiler:(resolve-j>)
313 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
315 ;; you can use as many "while" blocks as you want to
316 ;; any loop can be finished with AGAIN/REPEAT/UNTIL
317 ;; "BREAK" and "CONTINUE" cannot be used inside conditionals yet
323 compiler:(CTLID-BEGIN)
326 ;; repeats while the condition is false
329 ['] 0branch compiler
:(end-begin
)
332 ;; repeats
while the condition is true
335 ['] tbranch compiler:(end-begin)
338 ;; repeats while the number if positive
341 ['] +0branch compiler
:(end-begin
)
344 ;; repeats
while the number
if negative
347 ['] -0branch compiler:(end-begin)
350 ;; repeats while the number if positive or zero
353 ['] +branch compiler
:(end-begin
)
356 ;; repeats
while the number
if negative or zero
359 ['] -branch compiler:(end-begin)
364 ['] branch compiler
:(end-begin
)
370 ['] 0branch compiler:(comp-while)
374 ['] tbranch compiler
:(comp
-while)
378 ['] +0branch compiler:(comp-while)
382 ['] -0branch compiler
:(comp
-while)
386 ['] +branch compiler:(comp-while)
390 ['] -branch compiler
:(comp
-while)
395 1 compiler
:(break/continue)
399 0 compiler
:(break/continue)
402 ;; this has
to be here
406 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
409 ;; addr
(CTLID
-OF
) -- when in
"OF"
410 ;; addr
(CTLID
-ENDOF
) -- when
"ENDOF" compiled
411 ;; 0 (CTLID
-OTHERWISE
) -- when
"OTHERWISE" compiled
412 ;; note that
"(CTLID-ENDOF)"s will be accumulated
, and resolved in
"ENDCASE"
417 0 compiler
:(CTLID
-CASE
) ;; with dummy argument
420 : OF
['] forth:(of=) compiler:(x-of) ; immediate
421 : NOT-OF ['] forth
:(of
<>) compiler
:(x
-of
) ; immediate
422 : <OF
['] forth:(of<) compiler:(x-of) ; immediate
423 : <=OF ['] forth
:(of
<=) compiler
:(x
-of
) ; immediate
424 : >OF
['] forth:(of>) compiler:(x-of) ; immediate
425 : >=OF ['] forth
:(of
>=) compiler
:(x
-of
) ; immediate
426 : U
<OF
['] forth:(of-U<) compiler:(x-of) ; immediate
427 : U<=OF ['] forth
:(of
-U
<=) compiler
:(x
-of
) ; immediate
428 : U
>OF
['] forth:(of-U>) compiler:(x-of) ; immediate
429 : U>=OF ['] forth
:(of
-U
>=) compiler
:(x
-of
) ; immediate
430 : &OF
['] forth:(of-and) compiler:(x-of) ; immediate
431 : AND-OF ['] forth
:(of
-and
) compiler
:(x
-of
) ; immediate
432 : ~AND
-OF
['] forth:(of-~and) compiler:(x-of) ; immediate
433 : WITHIN-OF ['] forth
:(of
-within
) compiler
:(x
-of
) ; immediate
434 : UWITHIN
-OF
['] forth:(of-uwithin) compiler:(x-of) ; immediate
435 : BOUNDS-OF ['] forth
:(of
-bounds
) compiler
:(x
-of
) ; immediate
438 compiler
:?comp compiler
:(CTLID
-OF
) compiler
:?pairs
439 optimiser
:jpush
-branch
442 swap compiler
:(resolve
-j
>)
443 compiler
:(CTLID
-ENDOF
)
447 compiler
:(CTLID
-CASE
) compiler
:(CTLID
-ENDOF
) compiler
:?pairs
-any
-keepid
448 0 compiler
:(CTLID
-OTHERWISE
)
457 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
467 ['] (loop) compiler:(end-loop)
472 ['] (+loop
) compiler
:(end-loop
)
477 optimiser
:jpush
-branch
485 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
486 ;; "FOR" is
for loops with
"step by 1", from
0
489 optimiser
:jpush
-branch