7 ')' parse 2drop ; immediate
10 source nip >in ! ; immediate
12 \ cr .( hi - doing some test )
13 \ t{ 3 4 + -> 7 }t \ pass
14 \ t{ 3 -> }t \ wrong number of results
15 \ t{ 3 4 + -> 8 }t \ incorrect result
18 postpone branch here 0 , ; immediate
21 postpone ?branch here 0 , ; immediate
24 here swap ! ; immediate
26 : ELSE ( c:orig1 -- c:orig2 )
27 postpone AHEAD swap postpone THEN ; immediate
32 : WHILE ( c: orig -- c:dest c:orig )
33 postpone IF swap ; immediate
36 postpone branch , ; immediate
39 postpone ?branch , ; immediate
41 : REPEAT ( c:orig c:dest -- )
42 postpone AGAIN postpone THEN ; immediate
44 \ are these necessary?
45 \ you can use the phrase dup x = IF drop instead of x case? IF or x OF
46 : case? ( n1 n2 -- true | n1 false )
47 over = dup IF nip THEN ;
49 : OF ( n1 n2 -- n1 | )
50 postpone case? postpone IF ; immediate
61 : Constant ( x <name> -- )
65 false invert Constant true
68 : on ( addr -- ) true swap ! ;
69 : off ( addr -- ) false swap ! ;
72 : fill ( c-addr u x -- )
82 : erase ( c-addr u -- ) 0 fill ;
83 : blank ( c-addr u -- ) bl fill ;
91 : 2>r ( x1 x2 -- r:x1 r:x2 )
92 swap r> swap >r swap >r >r ;
94 : 2r> ( r:x1 r:x2 -- x1 x2 )
95 r> r> swap r> swap >r swap ;
97 : 2r@ ( r:x1 r:x2 -- r:x1 r:x2 x1 x2 )
98 r> r> r> 2dup >r >r swap rot >r ;
100 : 2>r-test ( x1 x2 -- x1 x2 ) 2>r r> r> swap ;
101 t{ 3 4 2>r-test -> 3 4 }t
103 : 2r>-test ( x1 x2 -- x1 x2 ) swap >r >r 2r> ;
104 t{ 3 4 2r>-test -> 3 4 }t
106 : 2r@-test ( x1 x2 -- x1 x2 ) 2>r 2r@ 2r> 2drop ;
107 t{ 3 4 2r@-test -> 3 4 }t
110 : n>r ( x1 ... xn -- r: xn ... x1 n )
112 BEGIN ( xn ... x1 n n' )
114 WHILE ( xn ... x1 n n' )
115 rot r> swap >r >r ( xn ... n n' ) ( R: ... x1 )
116 1- ( xn ... n n' ) ( R: ... x1 )
120 : nr> ( R: x1 .. xn n -- xn .. x1 n )
121 \ Pull N items and count off the return stack.
130 : n>r-test ( x1 x2 -- n x1 x2 ) 2 n>r r> r> r> ;
131 t{ 3 4 n>r-test -> 2 3 4 }t
133 : nr>-test ( x1 x2 -- x1 x2 n ) >r >r 2 >r nr> ;
134 t{ 3 4 nr>-test -> 3 4 2 }t
136 : 2rot ( x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2 )
137 2>r 2swap 2r> 2swap ;
139 t{ 1 2 3 4 5 6 2rot -> 3 4 5 6 1 2 }t
142 : lshift ( x u -- ) BEGIN ?dup WHILE swap 2* swap 1- REPEAT ;
144 \ if we don't have u2/ but only 2* and 0< we need to implement u2/ with a loop. Candidate for primitive
146 0 8 cells 1- \ for every bit
150 >r 2* over 0< IF 1+ THEN >r 2* r> r> 1-
154 t{ -1 u2/ dup 1+ u< -> -1 }t
155 t{ -1 u2/ 10 + dup 10 + u< -> -1 }t
158 : rshift ( x u -- ) BEGIN ?dup WHILE swap u2/ swap 1- REPEAT ;
160 : s>d ( n -- d ) dup 0< ;
162 t{ 1 3 lshift -> 8 }t
163 \ t{ 48 3 rshift -> 6 }t
165 : <> ( x1 x2 -- f ) = 0= ;
167 t{ 'x' 'u' <> -> -1 }t
170 : pick ( xn ... xi ... x0 i -- xn ... xi ... x0 xi )
172 t{ 10 20 30 1 pick -> 10 20 30 20 }t
174 : recursive ( -- ) reveal ; immediate
176 : roll ( xn-1 ... x0 i -- xn-1 ... xi-1 xi+1 ... x0 xi )
177 recursive ?dup IF swap >r 1- roll r> swap THEN ;
179 t{ 10 20 30 1 roll -> 10 30 20 }t
181 | Variable (to) (to) off
186 (to) @ IF ! (to) off ELSE @ THEN ;
188 : to ( x <name> -- ) (to) on ;
191 t{ val 42 to val val -> 5 42 }t
194 : within ( test low high -- flag )
197 t{ 2 3 5 within -> false }t
198 t{ 3 3 5 within -> true }t
199 t{ 4 3 5 within -> true }t
200 t{ 5 3 5 within -> false }t
201 t{ 6 3 5 within -> false }t
204 : n' parse-name find-name ;
211 \ : test s" xlerb" evaluate ;
214 2dup xor 0< >r abs swap abs um* drop r> IF negate THEN ;
216 : fac ( n -- ) recursive
217 dup 0= IF drop 1 exit THEN
222 : fib ( n1 -- n2 ) recursive
225 dup 1- fib swap 2 - fib + ;
229 : sqr ( u -- u^2 ) dup * ;
231 : u/ ( u1 u2 -- u3 ) >r 0 r> um/mod nip ;
238 \ x = (x + n//x) // 2
239 r@ over u/ + u2/ ( xi xi+1 )
240 2dup over 1+ over = >r = r> or
248 swap sqr swap sqr + sqrt ;
251 t{ 65535 dup * sqrt -> 65535 }t
255 \ remove headers from dictionary
256 | : unlink-header ( addr name -- ) \ 2dup ." unlink " . .
257 dup >r ( _link ) @ swap ! r> dispose ;
259 : remove-headers ( -- )
264 dup headerless? IF over >r unlink-header r> ELSE nip THEN ( addr )
269 : clear ( -- ) remove-headers ;
271 | : hidden-word ." still there - " ;
273 : visible-word ( -- ) hidden-word hidden-word ;
275 : save-mem ( c-addr1 u1 -- c-addr2 u2 )
276 dup >r allocate throw swap over r@ cmove r> ;
279 ')' parse save-mem ; immediate
283 \ : Marker ( <name> -- )
284 \ Create here , hp @ , Does> 2@ here - allot hp ! ;
285 \ Cannot access hp what about dictionary headers?
289 : package ( <name> -- ) parse-name 2drop ;
290 : private ( -- ) heads off ;
291 : public ( -- ) heads on ;
292 : end-package ( -- ) remove-headers ;
303 t{ s( abc) s( abc) compare -> 0 }t
304 t{ s( abc) s( ab) compare -> 1 }t
305 t{ s( ab) s( abc) compare -> -1 }t
306 t{ s( abc) s( def) compare -> -1 }t
307 t{ s( def) s( abc) compare -> 1 }t
309 : Defer ( <name> -- )
310 Create 0 , Does> @ execute ;
312 Defer %defer ' %defer >body 2 cells - @ Constant dodefer
313 ' %defer >body 1 cells - @ Constant dodoes
316 \ highly implementation specific
317 : backpatch1 ( xt1 xt2 -- ) >body >r
319 [ ' exit ] Literal >body 1 cells - r> cell+ ! ;
321 : dp! ( addr -- ) here - allot ;
323 : backpatch ( xt1 xt2 -- )
324 here >r >body dp! compile, postpone exit r> dp! ;
326 : hallo ." original" ;
329 : abc ." backpatched" ;
331 ' abc ' hallo backpatch
338 postpone >r ; immediate
346 postpone drop ; immediate
348 : cntdwn 65535 FOR r@ . NEXT ;
355 : testall ( -- ) \ see if sqrt works for all 32 bit numbers
357 t{ r@ Β² β βΌ r@ }t
370 Variable voc-link 0 voc-link !
372 : Vocabulary ( <name> -- )
373 wordlist Create here voc-link @ , voc-link ! last @ , ,
374 Does> 2 cells + @ >r get-order nip r> swap set-order ;
377 dup forth-wordlist = IF drop ." Forth " exit THEN
382 2dup 2 cells + @ = IF nip cell+ @ _name count type space exit THEN
387 ' .voc ' .wordlist backpatch
390 : recurse ( -- ) last @ _xt @ compile, ; immediate
392 : cntd ( n -- ) ?dup 0= ?exit dup . 1- recurse '.' emit ;
394 \ division / /mod fm/mod sm/rem mod
396 : s>d ( n -- d ) dup 0< ;
398 : dnegate ( d1 -- d2 ) ; \ define w/o carry
400 : sm/rem ( d1 n1 -- n2 n3 ) ;
403 t{ 10 s>d 3 sm/rem -> 1 3 }t
404 t{ -10 s>d 3 sm/rem -> -1 -3 }t
405 t{ 10 s>d -3 sm/rem -> 1 -3 }t
406 t{ -10 s>d -3 sm/rem -> -1 3 }t
409 \ number output: <# # #s #> sign hold holds base . u. .r u.r
414 : hold ( c -- ) -1 hld +! hld @ c! ;
416 \ : holds ( c-addr u -- ) recursive
417 \ dup 0= IF 2drop exit THEN
418 \ over c@ >r 1 /string holds r> hold ;
420 : holds ( c-addr u -- )
421 BEGIN dup WHILE 1- 2dup + c@ hold REPEAT 2drop ;
423 : mu/mod ( d n1 -- rem d.quot )
424 >r 0 r@ um/mod r> swap >r um/mod r> ;
426 : <# ( -- ) pad hld ! ;
429 base @ mu/mod rot 9 over < IF [ 'A' '9' 1+ - ] Literal + THEN '0' + hold ;
431 : #s ( ud1 -- d.0 ) BEGIN # 2dup or 0= UNTIL ;
433 : #> ( ud -- c-addr u ) 2drop hld @ pad over - ;
435 : sign ( n -- ) 0< IF '-' hold THEN ;
437 : decimal ( -- ) 10 base ! ; decimal
438 : hex ( -- ) 16 base ! ;
440 | : (.) ( n -- ) dup abs 0 <# #s rot sign #> ;
441 : dot ( n -- ) (.) type space ; ' dot ' . backpatch
442 : .r ( n l -- ) >r (.) r> over - 0 max spaces type ;
444 | : (u.) ( u -- ) 0 <# #s #> ;
445 : u. ( u -- ) (u.) type space ;
446 : u.r ( u l -- ) >r (u.) r> over - 0 max spaces type ;
448 : at-xy ( u1 u2 -- ) \ col row
450 esc ." [" 1+ 0 u.r ." ;" 1+ 0 u.r ." H"
461 : white ( -- ) esc ." [37m" ;
462 : blue-bg ( -- ) esc ." [44m" ;
464 : save-cursor-position ( -- ) 27 emit '7' emit ;
465 : restore-cursor-position ( -- ) 27 emit '8' emit ;
468 132 Value terminal-width
471 status-line IF scroll-up THEN
472 save-cursor-position blue-bg white
474 0 status-line 1 max at-xy ( clreol ) terminal-width spaces
475 0 status-line 1 max at-xy
477 ." | free: " unused u.
480 ." | " depth 0= IF ." β
" ELSE .s THEN
482 normal restore-cursor-position
484 0 status-line 1 - at-xy clreol
485 0 status-line 2 - at-xy
488 : +status ( -- ) [ ' show-status ] Literal [ ' .status >body ] Literal ! ;
489 : -status ( -- ) [ ' noop ] Literal [ ' .status >body ] Literal ! ;
492 only Forth also definitions
495 : only ( -- ) only root ;
500 : definitions definitions ;
507 only Forth also definitions
509 : mod ( u1 u2 -- u3 ) 0 swap um/mod drop ;
512 dup 2 = IF drop true exit THEN
513 dup 2 mod 0= IF drop false exit THEN
517 2dup mod 0= IF 2drop false exit THEN
524 1 BEGIN over WHILE 1+ dup prime? IF swap 1- swap THEN REPEAT nip ;
526 cr cr cr .( The ) 10001 dup . .( st prime is ) th.prime .
529 \ cooperative multi tasker
530 \ -------------------------
532 Variable up \ user pointer
534 : up@ ( -- x ) up @ ;
535 : up! ( x -- ) up ! ;
538 Create , Does> @ up@ + ;
540 : his ( task addr -- ) up@ - + ;
543 1 cells over + swap User task-state
544 1 cells over + swap User task-link
545 1 cells over + swap User error#
546 1 cells over + swap User sp-save
547 1 cells over + swap User rp-save
548 1 cells over + swap User frame-save
553 rp@ rp-save ! sp@ sp-save ! frame @ frame-save !
554 BEGIN task-link @ up! task-state @ UNTIL
555 sp-save @ sp! rp-save @ rp! frame-save @ frame ! ;
559 operator , \ task-link to itself
567 : task ( stacksize rstacksize -- tid )
570 task-link @ , r@ task-link !
572 over here + 2 cells + , ( sp-save )
573 + dup here + cell+ , ( rp-save )
574 allot \ allocate stack and return stack
577 : wake ( tid -- ) task-state his on ;
578 : sleep ( tid -- ) task-state his off ;
579 : stop ( -- ) up@ sleep pause ;
581 : task-push ( x tid -- ) \ push x on tids stack
582 sp-save his dup >r @ 1 cells - dup r> ! !
585 : task-rpush ( x tid -- ) \ push x on tids return-stack
586 rp-save his dup >r @ 1 cells - dup r> ! !
589 | : (activate) ( xt -- )
590 catch error# ! stop ;
592 : activate ( xt tid -- )
593 \ put xt on stack of tid
595 \ put (activate)'s body on return stack
596 [ ' (activate) >body ] Literal r@ task-rpush
600 : ms ( u -- ) 1000 * usleep ;
602 100 cells 100 cells task Constant t1
604 Variable counter 0 counter !
606 BEGIN 1 counter +! pause AGAIN ;
608 ' do-counter t1 activate
610 100 cells 100 cells task Constant counter-display
612 : ctr ( -- x ) counter @ 8 rshift ;
615 0 OF ." π" exit THEN
616 1 OF ." π" exit THEN
617 2 OF ." π" exit THEN
618 3 OF ." π" exit THEN
619 4 OF ." βΊοΈ" exit THEN
620 5 OF ." π" exit THEN
621 6 OF ." π" exit THEN
622 7 OF ." π" exit THEN ;
627 BEGIN pause ctr over - UNTIL drop
628 save-cursor-position blue reverse
629 11 status-line dup 1 = IF 1- THEN at-xy
630 ctr 3 rshift 7 and .emoji
631 14 status-line dup 1 = IF 1- THEN at-xy
632 ctr 0 999 um/mod drop 3 u.r
633 normal restore-cursor-position
635 ' .counter counter-display activate
637 1000 Value cycle-time
639 : multikey ( -- c) BEGIN pause key? 0= WHILE cycle-time usleep REPEAT key ;
641 : multi ( -- ) [ ' multikey ] Literal [ ' getkey >body ] Literal ! ;
642 : single ( -- ) [ ' key ] Literal [ ' getkey >body ] Literal ! ;
644 : stars ( n -- ) ?dup IF 1- FOR '*' emit NEXT THEN ;
647 cr .( Adjust your terminal to have ) status-line 1+ . .( lines.)
649 -77 Constant UTF-8-err
651 128 Constant max-single-byte
653 : u8@+ ( u8addr -- u8addr' u )
654 count dup max-single-byte u< ?exit \ special case ASCII
655 dup 194 u< IF UTF-8-err throw THEN \ malformed character
657 BEGIN dup r@ and WHILE r@ xor
658 6 lshift r> 5 lshift >r >r count
659 dup 192 and 128 <> IF UTF-8-err throw THEN
663 : u8!+ ( u u8addr -- u8addr' )
664 over max-single-byte u< IF swap over c! 1+ exit THEN \ special case ASCII
666 BEGIN 2dup swap u< WHILE
667 u2/ >r dup 63 and 128 or swap 6 rshift r>
668 REPEAT 127 xor 2* or r>
669 BEGIN over 128 u< 0= WHILE swap over c! 1+ REPEAT nip ;
671 cr s( Ξ) 2dup type .( has codepoint ) drop u8@+ . drop
673 cr 916 pad u8!+ pad swap over - type
675 t{ s( Ξ) drop u8@+ nip -> 916 }t
676 t{ 916 pad u8!+ pad - pad c@ pad 1+ c@ -> 2 206 148 }t
680 | : ?: dup 4 u.r ." :" ;
682 | : c? dup c@ 6 u.r ;
683 | : ?:@? ?: 4 spaces @? ;
686 : s ( adr - adr+1 ) \ string
687 ?: 4 spaces c? 2 spaces dup 1+ over c@ type dup c@ + 1+ ;
689 : .name ( name -- ) ?dup IF count type exit THEN ." ???" ;
691 : n ( adr - adr' ) \ name
692 ?:@? 2 spaces dup @ addr>name .name cell+ ;
694 : d ( adr n - adr+n ) \ dump
695 2dup swap ?: swap FOR c? 1+ NEXT 2 spaces -rot type ;
697 : l ( adr - adr' ) ?: dup @ 12 ># cell+ ; \ cell
698 : c ( adr - adr+1) 1 d ; \ character
699 : b ( adr - adr') ?:@? dup @ 2 ># cell+ ; \ branch, could be relative
701 cr .( Interactive decompiler: User single letter commands n d l c b s ) cr
705 | : .hexdigit ( x -- )
706 dup 10 < IF '0' + ELSE 10 - 'A' + THEN emit ;
709 dup 240 and 4 rshift .hexdigit 15 and .hexdigit ;
712 ?dup 0= ?exit dup 8 rshift recurse .hex ;
717 | : .h ( addr len -- )
722 over c@ .hex space 1 /string
724 b/line r> - 3 * spaces ;
726 | : .a ( addr1 len1 -- )
731 over c@ dup 32 < IF drop '.' THEN emit
735 | : dump-line ( addr len1 -- addr len2 )
736 over .addr ':' emit space 2dup .h space space 2dup .a
737 dup b/line min /string
741 : dump ( addr len -- )
753 echo on cr cr .( Welcome! ) input-echo on