8 ')' parse 2drop ; immediate
11 source nip >in ! ; immediate
13 \ cr .( hi - doing some test )
14 \ t{ 3 4 + -> 7 }t \ pass
15 \ t{ 3 -> }t \ wrong number of results
16 \ t{ 3 4 + -> 8 }t \ incorrect result
19 postpone branch here 0 , ; immediate
22 postpone ?branch here 0 , ; immediate
25 here swap ! ; immediate
27 : ELSE ( c:orig1 -- c:orig2 )
28 postpone AHEAD swap postpone THEN ; immediate
33 : WHILE ( c: orig -- c:dest c:orig )
34 postpone IF swap ; immediate
37 postpone branch , ; immediate
40 postpone ?branch , ; immediate
42 : REPEAT ( c:orig c:dest -- )
43 postpone AGAIN postpone THEN ; immediate
45 \ are these necessary?
46 \ you can use the phrase dup x = IF drop instead of x case? IF or x OF
47 : case? ( n1 n2 -- true | n1 false )
48 over = dup IF nip THEN ;
50 : OF ( n1 n2 -- n1 | )
51 postpone case? postpone IF ; immediate
53 : s" ( ccc" -- c-addr u ) \ compile only
57 here over 1+ allot place ; immediate
68 : Constant ( x <name> -- )
72 false invert Constant true
75 : on ( addr -- ) true swap ! ;
76 : off ( addr -- ) false swap ! ;
79 : fill ( c-addr u x -- )
89 : erase ( c-addr u -- ) 0 fill ;
90 : blank ( c-addr u -- ) bl fill ;
92 \ : xor ( x1 x2 -- x3 )
93 \ 2dup or >r invert swap invert or r> and ;
95 \ t{ 15 10 xor -> 5 }t
96 \ t{ 21845 dup xor -> 0 }t \ $5555
97 \ t{ 21845 dup 2* xor -> 65535 }t
105 : 2>r ( x1 x2 -- r:x1 r:x2 )
106 swap r> swap >r swap >r >r ;
108 : 2r> ( r:x1 r:x2 -- x1 x2 )
109 r> r> swap r> swap >r swap ;
111 : 2r@ ( r:x1 r:x2 -- r:x1 r:x2 x1 x2 )
112 r> r> r> 2dup >r >r swap rot >r ;
114 : 2>r-test ( x1 x2 -- x1 x2 ) 2>r r> r> swap ;
115 t{ 3 4 2>r-test -> 3 4 }t
117 : 2r>-test ( x1 x2 -- x1 x2 ) swap >r >r 2r> ;
118 t{ 3 4 2r>-test -> 3 4 }t
120 : 2r@-test ( x1 x2 -- x1 x2 ) 2>r 2r@ 2r> 2drop ;
121 t{ 3 4 2r@-test -> 3 4 }t
124 : n>r ( x1 ... xn -- r: xn ... x1 n )
126 BEGIN ( xn ... x1 n n' )
128 WHILE ( xn ... x1 n n' )
129 rot r> swap >r >r ( xn ... n n' ) ( R: ... x1 )
130 1- ( xn ... n n' ) ( R: ... x1 )
134 : nr> ( R: x1 .. xn n -- xn .. x1 n )
135 \ Pull N items and count off the return stack.
144 : n>r-test ( x1 x2 -- n x1 x2 ) 2 n>r r> r> r> ;
145 t{ 3 4 n>r-test -> 2 3 4 }t
147 : nr>-test ( x1 x2 -- x1 x2 n ) >r >r 2 >r nr> ;
148 t{ 3 4 nr>-test -> 3 4 2 }t
150 : 2rot ( x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2 )
151 2>r 2swap 2r> 2swap ;
153 t{ 1 2 3 4 5 6 2rot -> 3 4 5 6 1 2 }t
156 : lshift ( x u -- ) BEGIN ?dup WHILE swap 2* swap 1- REPEAT ;
158 \ if we don't have u2/ but only 2* and 0< we need to implement u2/ with a loop. Candidate for primitive
160 0 8 cells 1- \ for every bit
164 >r 2* over 0< IF 1+ THEN >r 2* r> r> 1-
168 t{ -1 u2/ dup 1+ u< -> -1 }t
169 t{ -1 u2/ 10 + dup 10 + u< -> -1 }t
172 : rshift ( x u -- ) BEGIN ?dup WHILE swap u2/ swap 1- REPEAT ;
174 : s>d ( n -- d ) dup 0< ;
176 t{ 1 3 lshift -> 8 }t
177 \ t{ 48 3 rshift -> 6 }t
179 : <> ( x1 x2 -- f ) = 0= ;
181 t{ 'x' 'u' <> -> -1 }t
185 : pick ( xn ... xi ... x0 i -- xn ... xi ... x0 xi )
187 t{ 10 20 30 1 pick -> 10 20 30 20 }t
189 : recursive ( -- ) reveal ; immediate
191 : roll ( xn-1 ... x0 i -- xn-1 ... xi-1 xi+1 ... x0 xi )
192 recursive ?dup IF swap >r 1- roll r> swap THEN ;
194 t{ 10 20 30 1 roll -> 10 30 20 }t
196 | Variable (to) (to) off
201 (to) @ IF ! (to) off ELSE @ THEN ;
203 : to ( x <name> -- ) (to) on ;
206 t{ val 42 to val val -> 5 42 }t
209 \ : u< ( u1 u2 -- f )
210 \ over 0< IF dup 0< IF < exit THEN \ both large
211 \ 2drop false exit THEN \ u1 is larger
212 \ dup 0< IF 2drop true exit THEN \ u2 is larger
217 : within ( test low high -- flag )
220 t{ 2 3 5 within -> false }t
221 t{ 3 3 5 within -> true }t
222 t{ 4 3 5 within -> true }t
223 t{ 5 3 5 within -> false }t
224 t{ 6 3 5 within -> false }t
227 : n' parse-name find-name ;
234 \ : test s" xlerb" evaluate ;
237 2dup xor 0< >r abs swap abs um* drop r> IF negate THEN ;
239 : fac ( n -- ) recursive
240 dup 0= IF drop 1 exit THEN
245 : fib ( n1 -- n2 ) recursive
248 dup 1- fib swap 2 - fib + ;
252 : sqr ( u -- u^2 ) dup * ;
254 : u/ ( u1 u2 -- u3 ) >r 0 r> um/mod nip ;
261 \ x = (x + n//x) // 2
262 r@ over u/ + u2/ ( xi xi+1 )
263 2dup over 1+ over = >r = r> or
271 swap sqr swap sqr + sqrt ;
274 t{ 65535 dup * sqrt -> 65535 }t
278 \ remove headers from dictionary
279 | : unlink-header ( addr name -- ) \ 2dup ." unlink " . .
280 dup >r ( _link ) @ swap ! r> dispose ;
282 : remove-headers ( -- )
287 dup headerless? IF over >r unlink-header r> ELSE nip THEN ( addr )
292 | : hidden-word ." still there - " ;
294 : visible-word ( -- ) hidden-word hidden-word ;
296 : save-mem ( c-addr1 u1 -- c-addr2 u2 )
297 dup >r allocate throw swap over r@ cmove r> ;
300 ')' parse save-mem ; immediate
304 \ : Marker ( <name> -- )
305 \ Create here , hp @ , Does> 2@ here - allot hp ! ;
306 \ Cannot access hp what about dictionary headers?
310 : package ( <name> -- ) parse-name 2drop ;
311 : private ( -- ) heads off ;
312 : public ( -- ) heads on ;
313 : end-package ( -- ) remove-headers ;
324 t{ s( abc) s( abc) compare -> 0 }t
325 t{ s( abc) s( ab) compare -> 1 }t
326 t{ s( ab) s( abc) compare -> -1 }t
327 t{ s( abc) s( def) compare -> -1 }t
328 t{ s( def) s( abc) compare -> 1 }t
330 : Defer ( <name> -- )
331 Create 0 , Does> @ execute ;
333 Defer %defer ' %defer >body 2 cells - @ Constant dodefer
334 ' %defer >body 1 cells - @ Constant dodoes
337 \ highly implementation specific
338 : backpatch1 ( xt1 xt2 -- ) >body >r
340 [ ' exit ] Literal >body 1 cells - r> cell+ ! ;
342 : dp! ( addr -- ) here - allot ;
344 : backpatch ( xt1 xt2 -- )
345 here >r >body dp! compile, postpone exit r> dp! ;
347 : hallo ." original" ;
350 : abc ." backpatched" ;
352 ' abc ' hallo backpatch
359 postpone >r ; immediate
367 postpone drop ; immediate
369 : cntdwn 65535 FOR r@ . NEXT ;
376 : testall ( -- ) \ see if sqrt works for all 32 bit numbers
378 t{ r@ Β² β βΌ r@ }t
391 Variable voc-link 0 voc-link !
393 : Vocabulary ( <name> -- )
394 wordlist Create here voc-link @ , voc-link ! last @ , ,
395 Does> 2 cells + @ >r get-order nip r> swap set-order ;
398 dup forth-wordlist = IF drop ." Forth " exit THEN
403 2dup 2 cells + @ = IF nip cell+ @ _name count type space exit THEN
408 ' .voc ' .wordlist backpatch
411 : recurse ( -- ) last @ _xt @ compile, ; immediate
413 : cntd ( n -- ) ?dup 0= ?exit dup . 1- recurse '.' emit ;
415 \ division / /mod fm/mod sm/rem mod
417 : s>d ( n -- d ) dup 0< ;
419 : dnegate ( d1 -- d2 ) ; \ define w/o carry
421 : sm/rem ( d1 n1 -- n2 n3 ) ;
424 t{ 10 s>d 3 sm/rem -> 1 3 }t
425 t{ -10 s>d 3 sm/rem -> -1 -3 }t
426 t{ 10 s>d -3 sm/rem -> 1 -3 }t
427 t{ -10 s>d -3 sm/rem -> -1 3 }t
430 \ number output: <# # #s #> sign hold holds base . u. .r u.r
435 : hold ( c -- ) -1 hld +! hld @ c! ;
437 \ : holds ( c-addr u -- ) recursive
438 \ dup 0= IF 2drop exit THEN
439 \ over c@ >r 1 /string holds r> hold ;
441 : holds ( c-addr u -- )
442 BEGIN dup WHILE 1- 2dup + c@ hold REPEAT 2drop ;
444 : mu/mod ( d n1 -- rem d.quot )
445 >r 0 r@ um/mod r> swap >r um/mod r> ;
447 : <# ( -- ) pad hld ! ;
450 base @ mu/mod rot 9 over < IF [ 'A' '9' 1+ - ] Literal + THEN '0' + hold ;
452 : #s ( ud1 -- d.0 ) BEGIN # 2dup or 0= UNTIL ;
454 : #> ( ud -- c-addr u ) 2drop hld @ pad over - ;
456 : sign ( n -- ) 0< IF '-' hold THEN ;
458 : decimal ( -- ) 10 base ! ; decimal
459 : hex ( -- ) 16 base ! ;
461 | : (.) ( n -- ) dup abs 0 <# #s rot sign #> ;
462 : dot ( n -- ) (.) type space ; ' dot ' . backpatch
463 : .r ( n l -- ) >r (.) r> over - 0 max spaces type ;
465 | : (u.) ( u -- ) 0 <# #s #> ;
466 : u. ( u -- ) (u.) type space ;
467 : u.r ( u l -- ) >r (u.) r> over - 0 max spaces type ;
469 : at-xy ( u1 u2 -- ) \ col row
471 esc ." [" 1+ 0 u.r ." ;" 1+ 0 u.r ." H"
482 : white ( -- ) esc ." [37m" ;
483 : blue-bg ( -- ) esc ." [44m" ;
485 : save-cursor-position ( -- ) 27 emit '7' emit ;
486 : restore-cursor-position ( -- ) 27 emit '8' emit ;
489 132 Value terminal-width
492 status-line IF scroll-up THEN
493 save-cursor-position blue-bg white
495 0 status-line 1 max at-xy ( clreol ) terminal-width spaces
496 0 status-line 1 max at-xy
498 ." | free: " unused u.
501 ." | " depth 0= IF ." β
" ELSE .s THEN
503 normal restore-cursor-position
505 0 status-line 1 - at-xy clreol
506 0 status-line 2 - at-xy
509 : +status ( -- ) [ ' show-status ] Literal [ ' .status >body ] Literal ! ;
510 : -status ( -- ) [ ' noop ] Literal [ ' .status >body ] Literal ! ;
513 only Forth also definitions
516 : only ( -- ) only root ;
521 : definitions definitions ;
528 only Forth also definitions
530 : mod ( u1 u2 -- u3 ) 0 swap um/mod drop ;
533 dup 2 = IF drop true exit THEN
534 dup 2 mod 0= IF drop false exit THEN
538 2dup mod 0= IF 2drop false exit THEN
545 1 BEGIN over WHILE 1+ dup prime? IF swap 1- swap THEN REPEAT nip ;
547 cr cr cr .( The ) 10001 dup . .( st prime is ) th.prime .
550 \ cooperative multi tasker
551 \ -------------------------
553 Variable up \ user pointer
555 : up@ ( -- x ) up @ ;
556 : up! ( x -- ) up ! ;
559 Create , Does> @ up@ + ;
561 : his ( task addr -- ) up@ - + ;
564 1 cells over + swap User task-state
565 1 cells over + swap User task-link
566 1 cells over + swap User error#
567 1 cells over + swap User sp-save
568 1 cells over + swap User rp-save
569 1 cells over + swap User frame-save
574 rp@ rp-save ! sp@ sp-save ! frame @ frame-save !
575 BEGIN task-link @ up! task-state @ UNTIL
576 sp-save @ sp! rp-save @ rp! frame-save @ frame ! ;
580 operator , \ task-link to itself
588 : task ( stacksize rstacksize -- tid )
591 task-link @ , r@ task-link !
593 over here + 2 cells + , ( sp-save )
594 + dup here + cell+ , ( rp-save )
595 allot \ allocate stack and return stack
598 : wake ( tid -- ) task-state his on ;
599 : sleep ( tid -- ) task-state his off ;
600 : stop ( -- ) up@ sleep pause ;
602 : task-push ( x tid -- ) \ push x on tids stack
603 sp-save his dup >r @ 1 cells - dup r> ! !
606 : task-rpush ( x tid -- ) \ push x on tids return-stack
607 rp-save his dup >r @ 1 cells - dup r> ! !
610 | : (activate) ( xt -- )
611 catch error# ! stop ;
613 : activate ( xt tid -- )
614 \ put xt on stack of tid
616 \ put (activate)'s body on return stack
617 [ ' (activate) >body ] Literal r@ task-rpush
621 100 cells 100 cells task Constant t1
623 Variable counter 0 counter !
625 BEGIN 1 counter +! pause AGAIN ;
627 ' do-counter t1 activate
629 \ : multi-key ( -- c )
630 \ BEGIN pause key? UNTIL key ;
632 100 cells 100 cells task Constant counter-display
634 : ctr ( -- x ) counter @ 13 rshift ;
637 0 OF ." π" exit THEN
638 1 OF ." π" exit THEN
639 2 OF ." π" exit THEN
640 3 OF ." π" exit THEN
641 4 OF ." βΊοΈ" exit THEN
642 5 OF ." π" exit THEN
643 6 OF ." π" exit THEN
644 7 OF ." π" exit THEN ;
649 BEGIN pause ctr over - UNTIL drop
650 save-cursor-position blue reverse
651 11 status-line dup 1 = IF 1- THEN at-xy
652 ctr 3 rshift 7 and .emoji
653 14 status-line dup 1 = IF 1- THEN at-xy
654 ctr 0 999 um/mod drop 3 u.r
655 normal restore-cursor-position
657 ' .counter counter-display activate
659 : multikey ( -- c) BEGIN key? 0= WHILE pause REPEAT key ;
661 : multi ( -- ) [ ' multikey ] Literal [ ' getkey >body ] Literal ! ;
662 : single ( -- ) [ ' key ] Literal [ ' getkey >body ] Literal ! ;
664 : stars ( n -- ) ?dup IF 1- FOR '*' emit NEXT THEN ;
667 cr .( Adjust your terminal to have ) status-line 1+ . .( lines.)
669 -77 Constant UTF-8-err
671 128 Constant max-single-byte
673 : u8@+ ( u8addr -- u8addr' u )
674 count dup max-single-byte u< ?exit \ special case ASCII
675 dup 194 u< IF UTF-8-err throw THEN \ malformed character
677 BEGIN dup r@ and WHILE r@ xor
678 6 lshift r> 5 lshift >r >r count
679 dup 192 and 128 <> IF UTF-8-err throw THEN
683 : u8!+ ( u u8addr -- u8addr' )
684 over max-single-byte u< IF swap over c! 1+ exit THEN \ special case ASCII
686 BEGIN 2dup swap u< WHILE
687 u2/ >r dup 63 and 128 or swap 6 rshift r>
688 REPEAT 127 xor 2* or r>
689 BEGIN over 128 u< 0= WHILE swap over c! 1+ REPEAT nip ;
691 cr s( Ξ) 2dup type .( has codepoint ) drop u8@+ . drop
693 cr 916 pad u8!+ pad swap over - type
695 t{ s( Ξ) drop u8@+ nip -> 916 }t
696 t{ 916 pad u8!+ pad - pad c@ pad 1+ c@ -> 2 206 148 }t
700 echo on cr cr .( Welcome! ) input-echo on