1 \ tag
: bootstrap
of basic forth words
3 \
Copyright (C) 2003-2005 Stefan Reinauer, Patrick Mauritz
5 \
See the file
"COPYING" for further information about
6 \
the copyright and warranty status
of this
work.
10 \ this
file contains
almost all
forth words
described
11 \ by
the open firmware
user interface. Some more complex
12 \ parts
are found
in seperate
files (memory management
,
17 \ often used constants
(reduces
dictionary size
)
29 \
7.3.5.1 Numeric-base
control
41 variable
current forth-last
current !
47 variable
#order 0 #order !
53 \
7.3.7 Flag constants
60 \
7.3.9.2.2 Immediate words (part
1)
63 : (immediate
) ( xt
-- )
64 1 - dup c
@ 1 or swap c
!
68 1 - dup c
@ 2 or swap c
!
79 : flags
? ( xt
-- flags
)
83 : immediate
? ( xt
-- true|false )
87 : compile
-only
? ( xt
-- true|false )
91 : [ 0 state
! ; compile
-only
97 \
7.3.9.2.1 Data space
allocation
100 : allot
here + here! ;
101 : , here /n allot
! ;
102 : c
, here /c allot
c! ;
105 /n
here /n
1 - and - \ how many bytes
to next
alignment
106 /n
1 - and allot \ mask out
everything that
is bigger
110 here dup align
here swap - 0 fill
114 here 1 and allot \
if here is not
even, we
have to align
.
119 /l
here /l
1 - and - \ same
as in align
, with /l
120 /l
1 - and \
if it
's /l we are already aligned.
127 \ 7.3.6 comparison operators (part 1)
134 \ 7.3.9.2.4 Miscellaneous dictionary (part 1)
137 : (to) ( xt-new xt-defer -- )
141 : >body ( xt -- a-addr ) /n 1 lshift + ;
142 : body> ( a-addr -- xt ) /n 1 lshift - ;
144 : reveal latest @ last ! ;
145 : recursive reveal ; immediate
146 : recurse latest @ /n + , ; immediate
155 ['] no
-environment
? ['] environment? (to)
159 \ 7.3.8.1 Conditional branches
162 \ A control stack entry is implemented using 2 data stack items
163 \ of the form ( addr type ). type can be one of the
169 : resolve-orig here nip over /n + - swap ! ;
170 : (if) ['] do?branch
, here 0 0 , ; compile
-only
171 : (then) resolve
-orig
; compile
-only
173 variable
tmp-comp
-depth
-1 tmp-comp
-depth
!
174 variable
tmp-comp
-buf
0 tmp-comp
-buf
!
176 : setup
-tmp-comp
( -- )
178 here tmp-comp
-buf
@ here! , \ save
here and switch
to tmp directory
180 depth
tmp-comp
-depth
! \ save
control depth
185 : execute
-tmp-comp
( -- )
186 depth
tmp-comp
-depth
@ =
197 : if setup-tmp-comp ['] do?branch
, here 0 0 , ; immediate
198 : then resolve
-orig execute
-tmp-comp
; compile
-only
199 : else ['] dobranch , here 0 0 , 2swap resolve-orig ; compile-only
202 \ 7.3.8.3 Conditional loops
205 \ some dummy words for see
212 \ resolve-dest requires a loop...
213 : (resolve-dest) here /n + nip - , ;
214 : (resolve-begin) setup-tmp-comp ['] (begin) , here 1 ; immediate
215 : (resolve
-until
) ['] (until) , ['] do?branch
, (resolve
-dest
) execute
-tmp-comp
; compile
-only
217 : resolve
-dest
( dest
origN ... orig
)
220 \
Find topmost
control stack entry
with a
type of 1 (dest
)
221 r
> dup dup pick
1 = if
267 resolve-dest resolve-orig
273 \ 7.3.8.4 Counted loops
276 variable leaves 0 leaves !
283 dup @ \ leaves -- leaves *leaves )
284 swap \ -- *leaves leaves )
285 here over - \ -- *leaves leaves here-leaves
322 \ Using primitive versions of i and j
323 \ speeds up loops by 300%
324 \ : i r> r@ swap >r ;
325 \ : j r> r> r> r@ -rot >r >r swap >r ;
327 : unloop r> r> r> 2drop >r ;
337 : ?leave if leave then ;
340 \ 7.3.8.2 Case statement
372 \
7.3.8.5 Other control flow commands
379 \
7.3.4.3 ASCII constants
(part
1)
390 \
7.3.1.1 - stack duplication
393 : 3dup 2 pick
2 pick
2 pick
;
396 \
7.3.1.2 - stack removal
402 \
7.3.1.3 - stack rearrangement
405 : 2rot >r >r 2swap r> r> 2swap ;
408 \
7.3.1.4 - return
stack
411 \
Note: these
words are not part
of the official OF specification
, however
412 \ they
are part of the ANSI DPANS94 core
extensions (see
section 6.2) and
413 \ so this
seems an appropriate
place for them
.
414 : 2>r r> -rot
swap >r >r >r ;
415 : 2r> r> r> r> rot
>r swap ;
416 : 2r@ r> r> r> 2dup >r >r rot
>r swap ;
419 \
7.3.2.1 - single
precision integer arithmetic
(part 1)
422 : u
/mod 0 swap mu
/mod drop
;
428 : bounds
over + swap ;
431 \
7.3.2.2 bitwise
logical operators
441 \
7.3.2.3 double
number arithmetic
445 : dnegate
0 0 2swap d
- ;
446 : dabs
dup 0 < if dnegate
then ;
447 : um
/mod mu
/mod drop
;
450 : sm
/rem
( d n
-- rem quot
)
451 over >r >r dabs
r@ abs
um/mod r> 0 <
456 negate
swap negate
swap
461 : fm
/mod ( d n
-- rem quot
)
462 dup >r 2dup xor
0 < >r sm
/rem
over 0 <> r> and if
463 1 - swap r> + swap exit
469 \
7.3.2.1 - single
precision integer arithmetic
(part 2)
472 : */mod ( n1 n2 n3
-- quot
rem ) >r m
* r> fm
/mod ;
473 : */ ( n1 n2 n3
-- n1
*n2
/n3
) */mod nip ;
474 : /mod >r s
>d
r> fm
/mod ;
480 \
7.3.2.4 Data type conversion
483 : lwsplit
( quad
-- w.lo
w.hi
)
484 dup ffff
and swap 10 rshift
ffff and
487 : wbsplit
( word -- b
.lo b
.hi
)
488 dup ff
and swap 8 rshift
ff and
491 : lbsplit
( quad
-- b
.lo b2 b3 b
.hi
)
492 lwsplit
swap wbsplit
rot wbsplit
495 : bwjoin
( b
.lo b
.hi
-- word )
496 ff and 8 lshift
swap ff and or
499 : wljoin
( w.lo
w.hi
-- quad
)
500 ffff and 10 lshift
swap ffff and or
503 : bljoin
( b
.lo b2 b3 b
.hi
-- quad
)
504 bwjoin
-rot bwjoin swap wljoin
507 : wbflip
( word -- word ) \ flips
bytes in a
word
508 dup 8 rshift
ff and swap ff and bwjoin
511 : lwflip
( q1
-- q2
)
512 dup 10 rshift
ffff and swap ffff and wljoin
515 : lbflip
( q1
-- q2
)
516 dup 10 rshift
ffff and wbflip
swap ffff and wbflip wljoin
520 \
7.3.2.5 address
arithmetic
535 : aligned
/n
1- + /n negate
and ;
543 \
7.3.6 Comparison operators
556 : within
>r over > swap r> >= or not ;
557 : between
1 + within
;
560 \
7.3.3.1 Memory access
563 : 2@ dup cell+ @ swap @ ;
564 : 2! dup >r ! r> cell+ ! ;
566 : <w@ w@ dup 8000 >= if 10000 - then ;
568 : comp
( str1 str2 len
-- 0|1|-1 )
572 < if 1 else -1 then swap leave
581 : $
= ( str1 len1 str2 len2
-- true|false )
582 rot ( str1 str2 len2 len1
)
583 over ( str1 str2 len2 len1 len2
)
584 <> if ( str1 str2 len2
)
587 else ( str1 str2 len2
)
593 \
: +! tuck
@ + swap ! ;
598 : wbflips
( waddr len
-- )
599 bounds
do i
w@ wbflip i
w! /w +loop
602 : lwflips
( qaddr len
-- )
603 bounds
do i l
@ lwflip i l
! /l
+loop
606 : lbflips
( qaddr len
-- )
607 bounds
do i l
@ lbflip i l
! /l
+loop
612 \
7.3.8.6 Error handling
(part 1)
639 \ 7.3.3.2 memory allocation
646 \ 7.3.4.4 Console output (part 1)
651 : type bounds ?do i c@ emit loop ;
653 \ this one obviously only works when called
654 \ with a forth string as count fetches addr-1.
655 \ openfirmware has no such req. therefore it has to go:
657 \ : type 0 do count emit loop drop ;
669 : source ( -- addr len )
673 : /string ( c-addr1 u1 n -- c-addr2 u2 )
679 \ pockets implementation for 7.3.4.1
681 100 constant pocketsize
682 4 constant numpockets
683 variable pockets 0 pockets !
684 variable whichpocket 0 whichpocket !
686 \ allocate 4 pockets to begin with
687 : init-pockets ( -- )
688 pocketsize numpockets * alloc-mem pockets !
691 : pocket ( ?? -- ?? )
692 pocketsize whichpocket @ *
694 whichpocket @ 1 + numpockets mod
698 \ span variable from 7.3.4.2
699 variable span 0 span !
701 \ if char is bl then any control character is matched
702 : findchar ( str len char -- offs true | false )
705 over dup bl = if <= else = then if
706 2drop i dup dup leave
707 \ i nip nip true exit \ replaces above
714 : parse ( delim text<delim> -- str len )
717 span @ >in @ - \ ib+offs len-offset.
718 dup 0 < if \ if we are already at the end of the string, return an empty string
719 + 0 \ move to end of input string
723 2dup r> \ ib+offs len-offset ib+offs len-offset delim
724 findchar if \ look for the delimiter.
730 \ dup -1 = if drop 0 then \ workaround for negative length
734 ib span @ ( -- ib recvchars )
736 dup >in @ > if ( -- recvchars>offs )
748 : parse-word ( < >text< > -- str len )
752 : word ( delim <delims>text<delim> -- pstr )
753 pocket >r parse dup r@ c! bounds r> dup 2swap
760 : ( 29 parse 2drop ; immediate
761 : \ span @ >in ! ; immediate
766 \ 7.3.4.7 String literals
775 : (") ( -- addr len )
777 2 cells + ( r-addr addr )
778 over cell+ @ ( r-addr addr len )
779 rot over + aligned cell+ >r ( addr len R: r-addr )
782 : handle-text ( temp-addr len -- addr len )
784 ['] (") , dup , ", null-align
789 over i
+ c@ over i
+ c!
802 \ 7.3.4.4 Console output (part 2)
828 \
7.3.4.8 String manipulation
831 : count ( pstr
-- str
len ) 1+ dup 1- c@ ;
833 : pack
( str
len addr -- pstr
)
836 over i
+ c@ over i
+ c!
840 : lcc
( char1
-- char2
) dup 41 5a between
if 20 + then ;
841 : upc
( char1
-- char2
) dup 61 7a between
if 20 - then ;
843 : -trailing
( str len1
-- str len2
)
845 dup 0<> if \
len != 0 ?
858 \
7.3.4.5 Output formatting
864 : spaces
0 ?do space
loop ;
865 variable
#line 0 #line !
866 variable
#out 0 #out !
870 \
7.3.9.2.3 Dictionary search
875 : lfa2name
( lfa
-- name
len )
877 begin \ skip
0 padding
880 7f and \ clear high bit
in length
882 tuck
- swap ( ptr
-to-len len - name
len )
885 : comp
-nocase
( str1 str2
len -- true|false )
887 2dup i
+ c@ upc
( str1 str2 byteX
)
888 swap i
+ c@ upc
( str1 str2 byte1 byte2
)
893 if -1 else drop 0 then
897 : comp
-word ( b
-str
len lfa
-- true | false )
898 lfa2name
( str
len str
len -- )
899 >r swap r> ( str str
len len )
900 over = if ( str str
len )
903 drop drop drop false \
if len does
not match, string does
not match
907 \ $find
is an fcode
word, but
we place it here since we use it for find
.
909 : find
-wordlist
( name
-str name
-len last
-- xt
true | name-str
name-len false )
914 2dup r@ dup if comp
-word dup false = then
920 -rot 2drop r> cell+ swap
922 r> drop drop drop false
927 : $find
( name-str
name-len -- xt
true | name-str
name-len false )
938 forth-last
find-wordlist
942 \ look
up a
word in the current wordlist
943 : $find1
( name-str
name-len -- xt
true | name-str
name-len false )
954 parse-word $find 0= if
955 type 3a emit -13 throw
960 parse
-word $
find 0= if
961 type 3a emit -13 throw
968 : find ( pstr -- xt n | pstr false )
969 dup count $find \ pstr xt true | pstr name-str name-len false
973 negate \ immediate returns 1
982 \ 7.3.9.2.2 Immediate words (part 2)
985 : literal ['] (lit
) , , ; immediate
986 : compile
, , ; immediate
987 : compile
r> cell+ dup @ , >r ;
988 : [compile
] ['] ' execute , ; immediate
992 dup immediate
? not if
997 s
" undefined word " type type cr
1003 \
7.3.9.2.4 Miscellaneous dictionary (part 2)
1013 my-self
dup if @ then
1017 my-self
dup if na1
+ then
1020 \
the following instance
words are used internally
1021 \
to implement
variable instantiation
.
1023 : instance
-cfa
? ( cfa
-- true | false )
1024 b e
within \ b
,c and d
are instance defining
words
1027 : behavior
( xt
-defer
-- xt
)
1028 dup @ instance-cfa
? if
1029 #instance-base ?dup if
1039 : (ito
) ( xt
-new xt
-defer
-- )
1040 #instance-base ?dup if
1051 swap ['] (lit) , , if ['] (ito
) else ['] (to) then ,
1053 if (ito) else /n + ! then
1057 : is ( xt "wordname<>" -- )
1061 s" could not find " type type
1066 \ 7.3.4.2 Console Input
1072 : accept ( addr len -- len2 )
1076 space drop drop drop i 0 leave
1078 dup emit over c! 1 +
1083 : expect ( addr len -- )
1089 \ 7.3.4.3 ASCII constants (part 2)
1104 parse-word 0<> if c@ else s" Unexpected EOL." type cr then ;
1107 : ascii char 1 handle-lit ; immediate
1108 : [char] char 1 handle-lit ; immediate
1111 char bl 1- and 1 handle-lit
1117 \ 7.3.8.6 Error handling (part 2)
1126 22 parse
handle-text
1135 \
7.5.3.1 Dictionary search
1138 \ this
does not belong here, but
its nice
for testing
1146 \
Don't print spaces
for headerless
words
1158 \
7.3.5.4 Numeric output primitives
1161 false value capital
-hex
?
1163 : pad
( -- addr ) here 100 + aligned
;
1165 : todigit
( num
-- ascii
)
1176 : hold pad
dup @ 1- tuck
swap ! c! ;
1183 : # base @ mu/mod rot todigit hold ;
1184 : #s begin # 2dup or 0= until ;
1185 : #> 2drop pad dup @ tuck - ;
1186 : (.) <# dup >r abs 0 #s r> sign #> ;
1188 : u
# base @ u/mod swap todigit hold ;
1189 : u
#s begin u# dup 0= until ;
1194 \
7.3.5.3 Numeric output
1197 : . (.) type space ;
1199 : u. (u.) type space ;
1200 : .r swap (.) rot 2dup < if over - spaces
else drop then type ;
1201 : u.r swap (u.) rot 2dup < if over - spaces
else drop then type ;
1202 : .d base
@ swap decimal
. base
! ;
1203 : .h base
@ swap hex
. base
! ;
1206 3c emit depth dup (.) type 3e emit space
1215 \
7.3.5.2 Numeric input
1218 : digit
( char base
-- n true | char false )
1220 41 5a ( A - Z ) between
if
1223 dup 39 > if \ protect
from : and ;
1224 -rot 2drop false exit
1228 30 ( number 0 ) - rot over swap 0 swap within if
1239 over c@ base
@ digit
0= if
1241 then >r 2swap r> swap base
@ um* drop rot base @ um* d
+ 2swap
1247 dup 2e = swap 2c = or
1254 then over c@ 2d = dup >r negate
/string begin
1257 over c@ numdelim
? 0= if
1258 2drop 2drop r> drop 0 exit
1264 2drop r> drop 0 exit
1285 2 of drop false endof
1296 s" illegal number" type cr 0
1309 s" illegal number" type cr 0
1322 s" illegal number" type cr 0
1330 \
7.3.4.7 String Literals (part 2)
1337 22 parse >r ( pocket pocket str R: len )
1338 over r@ move \ copy string
1339 r> + ( pocket nextdest )
1340 ib >in @ + c@ ( pocket nextdest nexchar )
1342 28 = \ is nextchar a parenthesis?
1343 span @ >in @ > \ more input?
1349 29 parse \ parse everything up to the next ')'
1370 \ 7.3.3.1 Memory Access (part 2)
1373 : dump ( addr len -- )
1379 dup 10 / todigit emit
1387 dup 20 < if drop 2e then \ non-printables as dots?
1397 \ 7.3.9.1 Defining words
1400 : header ( name len -- )
1401 dup if \ might be a noname...
1403 drop 2dup type s" isn
't unique." type cr
1409 dup -rot ", 80 or c, \ write name and len
1410 here /n 1- and 0= if 0 c, then \ pad and space for flags
1412 80 here 1- c! \ write flags byte
1413 here last @ , latest ! \ write backlink and set latest
1429 ['] (semis
) , reveal ['] [ execute
1434 3 , , \ compile DOCON and value
1438 0 value active-package
1439 : instance, ( size -- )
1440 \ first word of the device node holds the instance size
1441 dup active-package @ dup rot + active-package !
1445 : instance? ( -- flag )
1454 /n b , instance, , \ DOIVAL
1464 /n c , instance, 0 ,
1471 : $buffer: ( size str len -- where )
1474 /n over /n 1- and - /n 1- and + \ align buffer size
1475 dup c , instance, \ DOIVAR
1480 2dup 0 fill \ zerofill
1485 : buffer: ( size -- )
1486 parse-word $buffer: drop
1489 : (undefined-defer) ( -- )
1490 \ XXX: this does not work with behavior ... execute
1491 r@ 2 cells - lfa2name
1492 s" undefined defer word " type type cr ;
1494 : (undefined-idefer) ( -- )
1495 s" undefined idefer word " type cr ;
1497 : defer ( new-name< > -- )
1500 2 /n* d , instance, \ DOIDEFER
1501 ['] (undefined
-idefer
)
1504 ['] (undefined-defer)
1511 : alias
( new-name< >old
-name< > -- )
1514 -rot \ move
xt behind
.
1516 1 , \ fixme
we want
our own cfa
here.
1517 , \ compile
old name xt
1521 s" undefined word " type type space
1537 r> cell+ \ get
address of code
to execute
1538 latest @ \
backlink of just
"create"d
word
1539 cell+ cell+ ! \ write
code to execute after the
1544 ['] (does>) , \ compile
does handling
1564 \ initializer
for the temporary compile
buffer
1568 here 200 allot tmp-comp
-buf
!