ppc64: Don't set Kp bit on SLB
[openbios/afaerber.git] / forth / bootstrap / bootstrap.fs
blob08683f08ce4d190b1ccf1b2e878a21ad6b0375db
1 \ tag: bootstrap of basic forth words
2 \
3 \ Copyright (C) 2003-2005 Stefan Reinauer, Patrick Mauritz
4 \
5 \ See the file "COPYING" for further information about
6 \ the copyright and warranty status of this work.
7 \
9 \
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,
13 \ vocabulary support)
17 \ often used constants (reduces dictionary size)
20 1 constant 1
21 2 constant 2
22 3 constant 3
23 -1 constant -1
24 0 constant 0
26 0 value my-self
29 \ 7.3.5.1 Numeric-base control
32 : decimal 10 base ! ;
33 : hex 16 base ! ;
34 : octal 8 base ! ;
35 hex
38 \ vocabulary words
41 variable current forth-last current !
43 : last
44 current @
47 variable #order 0 #order !
49 defer context
50 0 value vocabularies?
53 \ 7.3.7 Flag constants
56 1 1 = constant true
57 0 1 = constant false
60 \ 7.3.9.2.2 Immediate words (part 1)
63 : (immediate) ( xt -- )
64 1 - dup c@ 1 or swap c!
67 : (compile-only)
68 1 - dup c@ 2 or swap c!
71 : immediate
72 last @ (immediate)
75 : compile-only
76 last @ (compile-only)
79 : flags? ( xt -- flags )
80 /n /c + - c@ 7f and
83 : immediate? ( xt -- true|false )
84 flags? 1 and 1 =
87 : compile-only? ( xt -- true|false )
88 flags? 2 and 2 =
91 : [ 0 state ! ; compile-only
92 : ] -1 state ! ;
97 \ 7.3.9.2.1 Data space allocation
100 : allot here + here! ;
101 : , here /n allot ! ;
102 : c, here /c allot c! ;
104 : align
105 /n here /n 1 - and - \ how many bytes to next alignment
106 /n 1 - and allot \ mask out everything that is bigger
107 ; \ than cellsize-1
109 : null-align
110 here dup align here swap - 0 fill
113 : w,
114 here 1 and allot \ if here is not even, we have to align.
115 here /w allot w!
118 : l,
119 /l here /l 1 - and - \ same as in align, with /l
120 /l 1 - and \ if it's /l we are already aligned.
121 allot
122 here /l allot l!
127 \ 7.3.6 comparison operators (part 1)
130 : <> = invert ;
134 \ 7.3.9.2.4 Miscellaneous dictionary (part 1)
137 : (to) ( xt-new xt-defer -- )
138 /n + !
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
148 : noop ;
150 defer environment?
151 : no-environment?
152 2drop false
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
164 \ following:
165 \ 0 - orig
166 \ 1 - dest
167 \ 2 - do-sys
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 ( -- )
177 state @ 0 = (if)
178 here tmp-comp-buf @ here! , \ save here and switch to tmp directory
179 1 , \ DOCOL
180 depth tmp-comp-depth ! \ save control depth
182 (then)
185 : execute-tmp-comp ( -- )
186 depth tmp-comp-depth @ =
187 (if)
188 -1 tmp-comp-depth !
189 ['] (semis) ,
190 tmp-comp-buf @
191 dup @ here!
192 0 state !
193 /n + execute
194 (then)
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
206 : (begin) ;
207 : (again) ;
208 : (until) ;
209 : (while) ;
210 : (repeat) ;
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 )
218 2 >r
219 (resolve-begin)
220 \ Find topmost control stack entry with a type of 1 (dest)
221 r> dup dup pick 1 = if
222 \ Move it to the top
223 roll
224 swap 1 - roll
225 \ Resolve it
226 (resolve-dest)
227 1 \ force exit
228 else
229 drop
230 2 + >r
232 then
233 (resolve-until)
236 : begin
237 setup-tmp-comp
238 ['] (begin) ,
239 here
241 ; immediate
243 : again
244 ['] (again) ,
245 ['] dobranch ,
246 resolve-dest
247 execute-tmp-comp
248 ; compile-only
250 : until
251 ['] (until) ,
252 ['] do?branch ,
253 resolve-dest
254 execute-tmp-comp
255 ; compile-only
257 : while
258 setup-tmp-comp
259 ['] (while) ,
260 ['] do?branch ,
261 here 0 0 , 2swap
262 ; immediate
264 : repeat
265 ['] (repeat) ,
266 ['] dobranch ,
267 resolve-dest resolve-orig
268 execute-tmp-comp
269 ; compile-only
273 \ 7.3.8.4 Counted loops
276 variable leaves 0 leaves !
278 : resolve-loop
279 leaves @
280 begin
281 ?dup
282 while
283 dup @ \ leaves -- leaves *leaves )
284 swap \ -- *leaves leaves )
285 here over - \ -- *leaves leaves here-leaves
286 swap ! \ -- *leaves
287 repeat
288 here nip - ,
289 leaves !
292 : do
293 setup-tmp-comp
294 leaves @
295 here 2
296 ['] (do) ,
297 0 leaves !
298 ; immediate
300 : ?do
301 setup-tmp-comp
302 leaves @
303 ['] (?do) ,
304 here 2
305 here leaves !
307 ; immediate
309 : loop
310 ['] (loop) ,
311 resolve-loop
312 execute-tmp-comp
313 ; immediate
315 : +loop
316 ['] (+loop) ,
317 resolve-loop
318 execute-tmp-comp
319 ; immediate
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 ;
329 : leave
330 ['] unloop ,
331 ['] dobranch ,
332 leaves @
333 here leaves !
335 ; immediate
337 : ?leave if leave then ;
340 \ 7.3.8.2 Case statement
343 : case
344 setup-tmp-comp
346 ; immediate
348 : endcase
349 ['] drop ,
350 0 ?do
351 ['] then execute
352 loop
353 execute-tmp-comp
354 ; immediate
356 : of
357 1 + >r
358 ['] over ,
359 ['] = ,
360 ['] if execute
361 ['] drop ,
363 ; immediate
365 : endof
367 ['] else execute
369 ; immediate
372 \ 7.3.8.5 Other control flow commands
375 : exit r> drop ;
379 \ 7.3.4.3 ASCII constants (part 1)
382 20 constant bl
383 07 constant bell
384 08 constant bs
385 0d constant carret
386 0a constant linefeed
390 \ 7.3.1.1 - stack duplication
392 : tuck swap over ;
393 : 3dup 2 pick 2 pick 2 pick ;
396 \ 7.3.1.2 - stack removal
398 : clear 0 depth! ;
399 : 3drop 2drop drop ;
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 ;
423 : 1+ 1 + ;
424 : 1- 1 - ;
425 : 2+ 2 + ;
426 : 2- 2 - ;
427 : even 1+ -2 and ;
428 : bounds over + swap ;
431 \ 7.3.2.2 bitwise logical operators
433 : << lshift ;
434 : >> rshift ;
435 : 2* 1 lshift ;
436 : u2/ 1 rshift ;
437 : 2/ 1 >>a ;
438 : not invert ;
441 \ 7.3.2.3 double number arithmetic
444 : s>d dup 0 < ;
445 : dnegate 0 0 2swap d- ;
446 : dabs dup 0 < if dnegate then ;
447 : um/mod mu/mod drop ;
449 \ symmetric division
450 : sm/rem ( d n -- rem quot )
451 over >r >r dabs r@ abs um/mod r> 0 <
453 negate
454 then
455 r> 0 < if
456 negate swap negate swap
457 then
460 \ floored division
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
464 then
465 r> drop
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 ;
475 : mod /mod drop ;
476 : / /mod nip ;
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
523 : /c* /c * ;
524 : /w* /w * ;
525 : /l* /l * ;
526 : /n* /n * ;
527 : ca+ /c* + ;
528 : wa+ /w* + ;
529 : la+ /l* + ;
530 : na+ /n* + ;
531 : ca1+ /c + ;
532 : wa1+ /w + ;
533 : la1+ /l + ;
534 : na1+ /n + ;
535 : aligned /n 1- + /n negate and ;
536 : char+ ca1+ ;
537 : cell+ na1+ ;
538 : chars /c* ;
539 : cells /n* ;
540 /n constant cell
543 \ 7.3.6 Comparison operators
546 : <= > not ;
547 : >= < not ;
548 : 0= 0 = ;
549 : 0<= 0 <= ;
550 : 0< 0 < ;
551 : 0<> 0 <> ;
552 : 0> 0 > ;
553 : 0>= 0 >= ;
554 : u<= u> not ;
555 : u>= u< not ;
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 )
569 >r 0 -rot r>
570 bounds ?do
571 dup c@ i c@ - dup if
572 < if 1 else -1 then swap leave
573 then
574 drop ca1+
575 loop
576 drop
579 \ compare two string
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 )
585 3drop
586 false
587 else ( str1 str2 len2 )
588 comp
590 then
593 \ : +! tuck @ + swap ! ;
594 : off false swap ! ;
595 : on true swap ! ;
596 : blank bl fill ;
597 : erase 0 fill ;
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)
615 variable catchframe
616 0 catchframe !
618 : catch
619 my-self >r
620 depth >r
621 catchframe @ >r
622 rdepth catchframe !
623 execute
624 r> catchframe !
625 r> r> 2drop 0
628 : throw
629 ?dup if
630 catchframe @ rdepth!
631 r> catchframe !
632 r> swap >r depth!
633 drop r>
634 r> ['] my-self (to)
635 then
639 \ 7.3.3.2 memory allocation
642 include memory.fs
646 \ 7.3.4.4 Console output (part 1)
649 defer emit
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 ;
661 \ 7.3.4.1 Text Input
664 0 value source-id
665 0 value ib
666 variable #ib 0 #ib !
667 variable >in 0 >in !
669 : source ( -- addr len )
670 ib #ib @
673 : /string ( c-addr1 u1 n -- c-addr2 u2 )
674 tuck - -rot + swap
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 @ *
693 pockets @ +
694 whichpocket @ 1 + numpockets mod
695 whichpocket !
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 )
703 swap 0 do
704 over i + c@
705 over dup bl = if <= else = then if
706 2drop i dup dup leave
707 \ i nip nip true exit \ replaces above
708 then
709 loop
711 \ drop drop false
714 : parse ( delim text<delim> -- str len )
715 >r \ save delimiter
716 ib >in @ +
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
720 r> drop
721 exit
722 then
723 2dup r> \ ib+offs len-offset ib+offs len-offset delim
724 findchar if \ look for the delimiter.
725 nip dup 1+
726 else
728 then
729 >in +!
730 \ dup -1 = if drop 0 then \ workaround for negative length
733 : skipws ( -- )
734 ib span @ ( -- ib recvchars )
735 begin
736 dup >in @ > if ( -- recvchars>offs )
737 over >in @ +
738 c@ bl <=
739 else
740 false
741 then
742 while
743 1 >in +!
744 repeat
745 2drop
748 : parse-word ( < >text< > -- str len )
749 skipws bl parse
752 : word ( delim <delims>text<delim> -- pstr )
753 pocket >r parse dup r@ c! bounds r> dup 2swap
755 char+ i c@ over c!
756 loop
757 drop
760 : ( 29 parse 2drop ; immediate
761 : \ span @ >in ! ; immediate
766 \ 7.3.4.7 String literals
769 : ",
770 bounds ?do
771 i c@ c,
772 loop
775 : (") ( -- addr len )
776 r> dup
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 )
783 state @ if
784 ['] (") , dup , ", null-align
785 else
786 pocket swap
787 dup >r
788 0 ?do
789 over i + c@ over i + c!
790 loop
791 nip r>
792 then
795 : s"
796 22 parse handle-text
797 ; immediate
802 \ 7.3.4.4 Console output (part 2)
805 : ."
806 22 parse handle-text
807 ['] type
808 state @ if
810 else
811 execute
812 then
813 ; immediate
815 : .(
816 29 parse handle-text
817 ['] type
818 state @ if
820 else
821 execute
822 then
823 ; immediate
828 \ 7.3.4.8 String manipulation
831 : count ( pstr -- str len ) 1+ dup 1- c@ ;
833 : pack ( str len addr -- pstr )
834 2dup c! \ store len
835 1+ swap 0 ?do
836 over i + c@ over i + c!
837 loop nip 1-
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 )
844 begin
845 dup 0<> if \ len != 0 ?
846 2dup 1- +
847 c@ bl =
848 else
849 false
850 then
851 while
853 repeat
858 \ 7.3.4.5 Output formatting
861 : cr linefeed emit ;
862 : (cr carret emit ;
863 : space bl emit ;
864 : spaces 0 ?do space loop ;
865 variable #line 0 #line !
866 variable #out 0 #out !
870 \ 7.3.9.2.3 Dictionary search
873 \ helper functions
875 : lfa2name ( lfa -- name len )
876 1- \ skip flag byte
877 begin \ skip 0 padding
878 1- dup c@ ?dup
879 until
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 )
886 0 do
887 2dup i + c@ upc ( str1 str2 byteX )
888 swap i + c@ upc ( str1 str2 byte1 byte2 )
889 <> if
890 0 leave
891 then
892 loop
893 if -1 else drop 0 then
894 swap drop
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 )
901 comp-nocase
902 else
903 drop drop drop false \ if len does not match, string does not match
904 then
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 )
911 @ >r
913 begin
914 2dup r@ dup if comp-word dup false = then
915 while
916 r> @ >r drop
917 repeat
919 r@ if \ successful?
920 -rot 2drop r> cell+ swap
921 else
922 r> drop drop drop false
923 then
927 : $find ( name-str name-len -- xt true | name-str name-len false )
928 vocabularies? if
929 #order @ 0 ?do
930 i cells context + @
931 find-wordlist
932 ?dup if
933 unloop exit
934 then
935 loop
936 false
937 else
938 forth-last find-wordlist
939 then
942 \ look up a word in the current wordlist
943 : $find1 ( name-str name-len -- xt true | name-str name-len false )
944 vocabularies? if
945 current @
946 else
947 forth-last
948 then
949 find-wordlist
954 parse-word $find 0= if
955 type 3a emit -13 throw
956 then
959 : [']
960 parse-word $find 0= if
961 type 3a emit -13 throw
962 then
963 state @ if
964 ['] (lit) , ,
965 then
966 ; immediate
968 : find ( pstr -- xt n | pstr false )
969 dup count $find \ pstr xt true | pstr name-str name-len false
971 nip true
972 over immediate? if
973 negate \ immediate returns 1
974 then
975 else
976 2drop false
977 then
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
990 : postpone
991 parse-word $find if
992 dup immediate? not if
993 ['] (lit) , , ['] ,
994 then
996 else
997 s" undefined word " type type cr
998 then
999 ; immediate
1003 \ 7.3.9.2.4 Miscellaneous dictionary (part 2)
1006 variable #instance
1008 : instance ( -- )
1009 true #instance !
1012 : #instance-base
1013 my-self dup if @ then
1016 : #instance-offs
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
1030 swap na1+ @ + @
1031 else
1032 3 /n* + @
1033 then
1034 else
1035 na1+ @
1036 then
1039 : (ito) ( xt-new xt-defer -- )
1040 #instance-base ?dup if
1041 swap na1+ @ + !
1042 else
1043 3 /n* + !
1044 then
1047 : to
1048 ['] ' execute
1049 dup @ instance-cfa?
1050 state @ if
1051 swap ['] (lit) , , if ['] (ito) else ['] (to) then ,
1052 else
1053 if (ito) else /n + ! then
1054 then
1055 ; immediate
1057 : is ( xt "wordname<>" -- )
1058 parse-word $find if
1059 (to)
1060 else
1061 s" could not find " type type
1062 then
1066 \ 7.3.4.2 Console Input
1069 defer key?
1070 defer key
1072 : accept ( addr len -- len2 )
1073 tuck 0 do
1075 dup linefeed = if
1076 space drop drop drop i 0 leave
1077 then
1078 dup emit over c! 1 +
1079 loop
1080 drop ( cr )
1083 : expect ( addr len -- )
1084 accept span !
1089 \ 7.3.4.3 ASCII constants (part 2)
1092 : handle-lit
1093 state @ if
1094 2 = if
1095 ['] (lit) , ,
1096 then
1097 ['] (lit) , ,
1098 else
1099 drop
1100 then
1103 : char
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
1110 : control
1111 char bl 1- and 1 handle-lit
1112 ; immediate
1117 \ 7.3.8.6 Error handling (part 2)
1120 : abort
1121 -1 throw
1124 : abort"
1125 ['] if execute
1126 22 parse handle-text
1127 ['] type ,
1128 ['] (lit) ,
1129 -2 ,
1130 ['] throw ,
1131 ['] then execute
1132 ; compile-only
1135 \ 7.5.3.1 Dictionary search
1138 \ this does not belong here, but its nice for testing
1140 : words ( -- )
1141 last
1142 begin @
1143 ?dup while
1144 dup lfa2name
1146 \ Don't print spaces for headerless words
1147 dup if
1148 type space
1149 else
1150 type
1151 then
1153 repeat
1158 \ 7.3.5.4 Numeric output primitives
1161 false value capital-hex?
1163 : pad ( -- addr ) here 100 + aligned ;
1165 : todigit ( num -- ascii )
1166 dup 9 > if
1167 capital-hex? not if
1168 20 +
1169 then
1170 7 +
1171 then
1172 30 +
1175 : <# pad dup ! ;
1176 : hold pad dup @ 1- tuck swap ! c! ;
1177 : sign
1178 0< if
1179 2d hold
1180 then
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 ;
1190 : u#> 0 #> ;
1191 : (u.) <# u#s u#> ;
1194 \ 7.3.5.3 Numeric output
1197 : . (.) type space ;
1198 : s. . ;
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 ! ;
1205 : .s
1206 3c emit depth dup (.) type 3e emit space
1209 depth i - 1- pick .
1210 loop
1215 \ 7.3.5.2 Numeric input
1218 : digit ( char base -- n true | char false )
1219 swap dup upc dup
1220 41 5a ( A - Z ) between if
1222 else
1223 dup 39 > if \ protect from : and ;
1224 -rot 2drop false exit
1225 then
1226 then
1228 30 ( number 0 ) - rot over swap 0 swap within if
1229 nip true
1230 else
1231 drop false
1232 then
1235 : >number
1236 begin
1237 dup
1238 while
1239 over c@ base @ digit 0= if
1240 drop exit
1241 then >r 2swap r> swap base @ um* drop rot base @ um* d+ 2swap
1242 1 /string
1243 repeat
1246 : numdelim?
1247 dup 2e = swap 2c = or
1251 : $dnumber?
1252 0 0 2swap dup 0= if
1253 2drop 2drop 0 exit
1254 then over c@ 2d = dup >r negate /string begin
1255 >number dup 1 >
1256 while
1257 over c@ numdelim? 0= if
1258 2drop 2drop r> drop 0 exit
1259 then 1 /string
1260 repeat if
1261 c@ 2e = if
1262 true
1263 else
1264 2drop r> drop 0 exit
1265 then
1266 else
1267 drop false
1268 then over or if
1269 r> if
1270 dnegate
1271 then 2
1272 else
1273 drop r> if
1274 negate
1275 then 1
1276 then
1280 : $number ( )
1281 $dnumber?
1282 case
1283 0 of true endof
1284 1 of false endof
1285 2 of drop false endof
1286 endcase
1289 : d#
1290 parse-word
1291 base @ >r
1293 decimal
1295 $number if
1296 s" illegal number" type cr 0
1297 then
1298 r> base !
1299 1 handle-lit
1300 ; immediate
1302 : h#
1303 parse-word
1304 base @ >r
1308 $number if
1309 s" illegal number" type cr 0
1310 then
1311 r> base !
1312 1 handle-lit
1313 ; immediate
1315 : o#
1316 parse-word
1317 base @ >r
1319 octal
1321 $number if
1322 s" illegal number" type cr 0
1323 then
1324 r> base !
1325 1 handle-lit
1326 ; immediate
1330 \ 7.3.4.7 String Literals (part 2)
1334 pocket dup
1335 begin
1336 span @ >in @ > if
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 )
1341 1 >in +!
1342 28 = \ is nextchar a parenthesis?
1343 span @ >in @ > \ more input?
1345 else
1346 false
1347 then
1348 while
1349 29 parse \ parse everything up to the next ')'
1350 bounds ?do
1351 i c@ 10 digit if
1352 i 1+ c@ 10 digit if
1353 swap 4 lshift or
1354 else
1355 drop
1356 then
1357 over c! 1+
1359 else
1360 drop 1
1361 then
1362 +loop
1363 repeat
1364 over -
1365 handle-text
1366 ; immediate
1370 \ 7.3.3.1 Memory Access (part 2)
1373 : dump ( addr len -- )
1374 over + swap
1376 do i u. space
1377 10 0 do
1378 j i + c@
1379 dup 10 / todigit emit
1380 10 mod todigit emit
1381 space
1382 i 7 = if space then
1383 loop
1384 3 spaces
1385 10 0 do
1386 j i + c@
1387 dup 20 < if drop 2e then \ non-printables as dots?
1388 emit
1389 loop
1391 10 +loop
1397 \ 7.3.9.1 Defining words
1400 : header ( name len -- )
1401 dup if \ might be a noname...
1402 2dup $find1 if
1403 drop 2dup type s" isn't unique." type cr
1404 else
1405 2drop
1406 then
1407 then
1408 null-align
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
1411 null-align
1412 80 here 1- c! \ write flags byte
1413 here last @ , latest ! \ write backlink and set latest
1418 parse-word header
1419 1 , ]
1422 : :noname
1423 0 0 header
1424 here
1425 1 , ]
1429 ['] (semis) , reveal ['] [ execute
1430 ; immediate
1432 : constant
1433 parse-word header
1434 3 , , \ compile DOCON and value
1435 reveal
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 !
1442 , , \ offset size
1445 : instance? ( -- flag )
1446 #instance @ dup if
1447 false #instance !
1448 then
1451 : value
1452 parse-word header
1453 instance? if
1454 /n b , instance, , \ DOIVAL
1455 else
1456 3 , ,
1457 then
1458 reveal
1461 : variable
1462 parse-word header
1463 instance? if
1464 /n c , instance, 0 ,
1465 else
1466 4 , 0 ,
1467 then
1468 reveal
1471 : $buffer: ( size str len -- where )
1472 header
1473 instance? if
1474 /n over /n 1- and - /n 1- and + \ align buffer size
1475 dup c , instance, \ DOIVAR
1476 else
1478 then
1479 here swap
1480 2dup 0 fill \ zerofill
1481 allot
1482 reveal
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< > -- )
1498 parse-word header
1499 instance? if
1500 2 /n* d , instance, \ DOIDEFER
1501 ['] (undefined-idefer)
1502 else
1504 ['] (undefined-defer)
1505 then
1507 ['] (semis) ,
1508 reveal
1511 : alias ( new-name< >old-name< > -- )
1512 parse-word
1513 parse-word $find if
1514 -rot \ move xt behind.
1515 header
1516 1 , \ fixme we want our own cfa here.
1517 , \ compile old name xt
1518 ['] (semis) ,
1519 reveal
1520 else
1521 s" undefined word " type type space
1522 2drop
1523 then
1526 : $create
1527 header 6 ,
1528 ['] noop ,
1529 reveal
1532 : create
1533 parse-word $create
1536 : (does>)
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
1540 \ new word's CFA
1543 : does>
1544 ['] (does>) , \ compile does handling
1545 1 , \ compile docol
1546 ; immediate
1548 0 constant struct
1550 : field
1551 create
1552 over ,
1554 does>
1558 : 2constant
1559 create , ,
1560 does> 2@ reveal
1564 \ initializer for the temporary compile buffer
1567 : init-tmp-comp
1568 here 200 allot tmp-comp-buf !
1571 \ the end