collapseos/forth/icore.fs

180 lines
4.1 KiB
Forth
Raw Normal View History

( Inner core. This unit represents core definitions that
happen right after native definitions. Before core.fs.
Unlike core.fs and its followers, this unit isn't self-
sustained. Like native defs it uses the machinery of a
full Forth interpreter, notably for flow structures.
Because of that, it has to obey specific rules:
1. It cannot compile a word from higher layers. Using
immediates is fine though.
2. If it references a word from this unit or from native
definitions, these need to be properly offsetted
because their offset at compile time are not the same
as their runtime offsets.
3. Anything they refer to in the boot binary has to be
properly stabilized.
4. Make sure that the words you compile are not overridden
by the full interpreter.
)
( When referencing words from native defs or this very unit,
use this compiling word, which subtract the proper offset
from the compiled word. That proper offset is:
1. Take ROT-header addr, the first native def.
2. Subtract _bend, boot's last word.
3. That will give us the offset to subtract to get the addr
of our word at runtime.
This means, of course, that any word compiling a _c word
can't be executed immediately.
Also note that because of that "_c" mechanism, it might
take two rounds of bootstrapping before the compiled
z80c.bin file is "stabilized". That's because the 2nd time
around, the recorded offset will have changed.
)
: _c
[
' ROT
6 - ( header )
' _bend
- ( our offset )
LITN
]
' ( get word )
-^ ( apply offset )
, ( write! )
; IMMEDIATE
2020-03-29 01:11:52 +11:00
: ABORT _c (resSP) QUIT ;
2020-03-28 02:49:50 +11:00
( This is only the "early parser" in earlier stages. No need
for an abort message )
: (parse)
(parsed) NOT IF _c ABORT THEN
2020-03-28 02:49:50 +11:00
;
2020-03-28 03:36:10 +11:00
( a -- )
: (print)
BEGIN
2020-03-30 23:02:20 +11:00
_c DUP ( a a )
2020-03-28 03:36:10 +11:00
_c C@ ( a c )
( exit if null )
2020-03-30 23:02:20 +11:00
_c DUP NOT IF DROP DROP EXIT THEN
2020-03-29 01:25:02 +11:00
_c EMIT ( a )
2020-03-29 06:33:14 +11:00
1 _c + ( a+1 )
2020-03-28 03:36:10 +11:00
AGAIN
;
2020-03-29 00:19:40 +11:00
: (uflw)
2020-03-29 01:11:52 +11:00
LIT< stack-underflow _c (print) _c ABORT
2020-03-29 00:19:40 +11:00
;
2020-03-28 10:12:46 +11:00
: C,
HERE @ _c C!
2020-03-29 06:33:14 +11:00
HERE @ 1 _c + HERE !
2020-03-28 10:12:46 +11:00
;
2020-03-29 04:18:43 +11:00
( The NOT is to normalize the negative/positive numbers to 1
or 0. Hadn't we wanted to normalize, we'd have written:
32 CMP 1 - )
2020-03-29 06:33:14 +11:00
: WS? 33 _c CMP 1 _c + NOT ;
2020-03-29 04:18:43 +11:00
2020-03-29 04:02:04 +11:00
: TOWORD
BEGIN
2020-03-30 23:02:20 +11:00
C< _c DUP _c WS? NOT IF EXIT THEN DROP
2020-03-29 04:02:04 +11:00
AGAIN
;
2020-03-29 03:55:22 +11:00
( Read word from C<, copy to WORDBUF, null-terminate, and
return, make HL point to WORDBUF. )
: WORD
( JTBL+30 == WORDBUF )
[ JTBL 30 + @ LITN ] ( a )
2020-03-29 04:02:04 +11:00
_c TOWORD ( a c )
2020-03-29 03:55:22 +11:00
BEGIN
( We take advantage of the fact that char MSB is
always zero to pre-write our null-termination )
2020-03-30 22:58:16 +11:00
_c OVER ! ( a )
2020-03-29 06:33:14 +11:00
1 _c + ( a+1 )
2020-03-29 03:55:22 +11:00
C< ( a c )
2020-03-30 23:02:20 +11:00
_c DUP _c WS?
2020-03-29 03:55:22 +11:00
UNTIL
( a this point, PS is: a WS )
( null-termination is already written )
DROP DROP
[ JTBL 30 + @ LITN ]
;
2020-03-29 01:38:05 +11:00
: LITN
( JTBL+24 == NUMBER )
2020-03-29 06:33:14 +11:00
JTBL 24 _c + ,
2020-03-29 01:38:05 +11:00
,
;
2020-03-28 07:52:42 +11:00
: (entry)
HERE @ ( h )
2020-03-29 03:55:22 +11:00
_c WORD ( h s )
2020-03-28 07:52:42 +11:00
SCPY ( h )
( Adjust HERE -1 because SCPY copies the null )
HERE @ 1 _c - ( h h' )
2020-03-30 23:02:20 +11:00
_c DUP HERE ! ( h h' )
2020-03-30 23:06:11 +11:00
_c SWAP _c - ( sz )
2020-03-28 07:52:42 +11:00
( write prev value )
HERE @ CURRENT @ _c - ,
( write size )
2020-03-28 10:12:46 +11:00
_c C,
2020-03-28 07:52:42 +11:00
HERE @ CURRENT !
;
2020-03-29 03:55:22 +11:00
: INTERPRET
BEGIN
_c WORD
(find)
IF
1 FLAGS !
EXECUTE
0 FLAGS !
ELSE
(parse*) @ EXECUTE
THEN
AGAIN
;
: BOOT
LIT< (c<$) (find) IF EXECUTE ELSE DROP THEN
_c INTERPRET
;
( : and ; have to be defined last because it can't be
executed now also, they can't have their real name
right away )
: X
2020-03-28 07:52:42 +11:00
_c (entry)
2020-03-29 01:38:05 +11:00
( We cannot use LITN as IMMEDIATE because of bootstrapping
issues. JTBL+24 == NUMBER JTBL+6 == compiledWord )
[ JTBL 24 + , JTBL 6 + , ] ,
BEGIN
2020-03-29 03:55:22 +11:00
_c WORD
(find)
( is word )
2020-03-30 23:02:20 +11:00
IF _c DUP _c IMMED? IF EXECUTE ELSE , THEN
( maybe number )
2020-03-29 01:38:05 +11:00
ELSE (parse*) @ EXECUTE _c LITN THEN
AGAIN
; IMMEDIATE
: Y
2020-03-28 02:27:40 +11:00
['] EXIT ,
_c R> DROP ( exit : )
; IMMEDIATE
( Give ":" and ";" their real name )
':' ' X 4 - C!
';' ' Y 4 - C!
2020-03-28 02:27:40 +11:00