Copyright Bill Muench All rights reserved.
Permission is granted for non-commercial use, provided this notice is included.
Contact Bill Muench concerning commercial use.

CR .( eForth library )
CR ( Copyright Bill Muench All rights reserved. )

( Bill Muench \ OntoLogic )
(             \ Santa Cruz  CA  95065 )

( 971005 move to CORE 0= BOUNDS NIP [CHAR] )
( 950512 change 2LITERAL  add ?LEAVE )
( 950411 change DU. FIND remove DDEFER DVALUE DV! )
(        fix VALUE TO COMPILE )
(        move to CORE ['] )
( 941015 fix FIND per jfox )
(        add SEARCH-WORDLIST WORD )
( 930307 start library collection )

MARKER E4.LIB
BASE @ !CSP
DECIMAL

( =========================================================== )

' .S 'OK ! ( prompt option )

( =========================================================== )

: UNUSED ( -- u ) DP 2@ - ; \ ???

: _C" ( -- a ) _" ; COMPILE-ONLY
: C" ( "ccc" -- ) ['] _C" COMPILE,  ,C" ; IMMEDIATE

( =========================================================== )

: ?#S ( base -- n )
  BASE @ >R  BASE !       ( save and set radix )
  -1 0 <# #S #> SWAP DROP ( save only count )
  R> BASE ! ;             ( restore radix )

: BINARY ( -- ) 2 BASE ! ;

: [COMPILE] ( 'name' -- ) ' COMPILE, ; IMMEDIATE

( numeric overrides ========================================== )

: X# ( -- ) ( 'ccc' -- n | d )
  DOES> C@           ( new radix )
  BASE @ >R  BASE !  ( save and set radix )
  PARSE-WORD         ( get a u of string )
  ['] EVALUATE CATCH ( convert to number, set trap )
  R> BASE !  THROW ; ( restore radix before error control )

CREATE B# ( 'ccc' -- n | d )  2 C, X# IMMEDIATE
CREATE O# ( 'ccc' -- n | d )  8 C, X# IMMEDIATE
CREATE D# ( 'ccc' -- n | d ) 10 C, X# IMMEDIATE
CREATE H# ( 'ccc' -- n | d ) 16 C, X# IMMEDIATE
CREATE T# ( 'ccc' -- n | d ) 36 C, X# IMMEDIATE

: .X ( -- ) DOES> C@ BASE @ >R BASE ! U. R> BASE ! ;

CREATE .B ( n -- )  2 C, .X
CREATE .O ( n -- )  8 C, .X
CREATE .D ( n -- ) 10 C, .X
CREATE .H ( n -- ) 16 C, .X
CREATE .T ( n -- ) 36 C, .X

( =========================================================== )

: @EXECUTE ( a -- ) @ ?DUP IF EXECUTE THEN ;

: DEFER ( 'name' -- ) CREATE 0 , DOES> @EXECUTE ;
: VALUE ( n 'name' -- ) CREATE , DOES> @ ;

: !TO ( n xt -- ) >BODY ! ;
: TO ( n 'name' -- )
  '  STATE @ ( compiling ? )
  IF [COMPILE] LITERAL  ['] !TO COMPILE,  EXIT
  THEN !TO ; IMMEDIATE

( =========================================================== )

: BLANK ( a u -- ) BL FILL ;
: ERASE ( a u -- ) 0 FILL ;

0       CONSTANT FALSE
0 DUP = CONSTANT TRUE

: 0> ( n -- ) NEGATE 0< ;
: 0<> ( n -- f ) IF -1 EXIT THEN 0 ; \ 0= INVERT ;

: <> ( n n -- f ) = 0= ;
: > ( n n -- f ) SWAP < ;
: U> ( u u -- f ) SWAP U< ;

: 1+ ( n -- n ) 1 + ;
: 1- ( n -- n ) 1 - ;

: 2+ ( n -- n ) 2 + ;
: 2- ( n -- n ) 2 - ;

: 2* ( n -- n ) 2 * ;
: 2/ ( n -- n ) 2 / ;

: TUCK ( n1 n2 -- n2 n1 n2 ) SWAP OVER ;
: -ROT ( n1 n2 n3 -- n3 n1 n2 ) SWAP >R SWAP R> ;

: UMIN ( u u -- u ) 2DUP U< IF   BEGIN DROP ;
: UMAX ( u u -- u ) 2DUP U< UNTIL THEN SWAP DROP ;

( double number extensions ================================== )

: 2LITERAL ( d -- ) SWAP  [COMPILE] LITERAL  [COMPILE] LITERAL ; IMMEDIATE
: 2CONSTANT ( d 'name' -- ) CREATE , , DOES> 2@ ;
: 2VARIABLE ( 'name' -- ) CREATE 2 CELLS ALLOT ;

: 2>R ( n1 n2 -- ) ( R: -- n1 n2 )
  SWAP R>  SWAP >R  SWAP >R  >R ; COMPILE-ONLY

: 2R> ( -- n1 n2 ) ( R: n1 n2 -- )
  R>  R> SWAP  R> SWAP  >R  SWAP ; COMPILE-ONLY

: 2R@ ( -- n1 n2 ) ( R: n1 n2 -- n1 n2 )
  R>  R> R@  SWAP >R  SWAP R@  SWAP >R ; COMPILE-ONLY

: 2SWAP ( d1 d2 -- d2 d1 ) ROT >R ROT R> ;
: 2OVER ( d1 d2 -- d1 d2 d1 ) >R >R 2DUP R> R> 2SWAP ;
: 2ROT ( d1 d2 d3 -- d2 d3 d1 ) 2>R 2SWAP 2R> 2SWAP ;

: D0< ( d -- f ) SWAP DROP 0< ;
: D0> ( d -- f ) DNEGATE D0< ;
: D- ( d d -- d ) DNEGATE D+ ;
: D0= ( d -- f ) OR 0= ;
: D= ( d d -- f ) D- D0= ;

: D< ( d d -- f ) ROT 2DUP XOR IF SWAP 2SWAP 2DROP < ;
: DU< ( ud ud -- f )
  ROT 2DUP XOR IF SWAP 2SWAP THEN THEN 2DROP U< ;

: DMIN ( d d -- d ) 2OVER 2OVER D< IF   BEGIN 2DROP ;
: DMAX ( d d -- d ) 2OVER 2OVER D< UNTIL THEN 2SWAP 2DROP ;

: M+ ( d n -- d ) S>D D+ ;
: M- ( d n -- d ) S>D D- ;

: M* ( n n -- d )
  2DUP XOR 0< >R  ABS SWAP ABS UM*  R> IF DNEGATE THEN ;

: M/ ( d n -- q ) FM/MOD SWAP DROP ;

: */MOD ( n n n -- r q ) >R M* R> FM/MOD ;
: */ ( n n n -- q ) */MOD SWAP DROP ;

: MU/MOD ( ud u -- ur udq ) >R 0 R@ UM/MOD R> SWAP >R UM/MOD R> ;

: D2* ( d -- d ) 2DUP D+ ;
: DU2/ ( ud -- ud ) 2 MU/MOD ROT DROP ;
: D2/ ( d -- d ) DUP >R 1 AND DU2/  R> 2/ OR ;

: DU.R ( ud n -- ) >R <# #S #> R> S.R ;
: DU. ( ud -- ) 0 DU.R SPACE ;

( ============================================================ )

: 3* ( n -- n ) DUP DUP + + ;
: 4* ( n -- n ) DUP + DUP + ;

( ??? ======================================================= )

: TU* ( ud u -- ut ) DUP >R SWAP >R UM* 0 R> R> UM* D+ ;
: TU/MOD ( ut u -- ur udq ) DUP >R UM/MOD R> SWAP >R UM/MOD R> ;

: M*/MOD ( ud u u -- ur udq ) >R TU*  R> TU/MOD ;
: M*/ ( ud u u -- ud ) M*/MOD ROT DROP ;

( implementation defined ==================================== )

: MSB> ( hl -- zh ) 8 RSHIFT ; \ ???
: >MSB ( hl -- lz ) 8 LSHIFT ; \ ???

: LSB ( hl -- zl ) >MSB MSB> ;
: JOIN ( zl zh -- hl ) >MSB SWAP LSB OR ;
: SPLIT ( hl -- zl zh ) DUP LSB SWAP MSB> ;
: FLIP ( hl -- lh ) SPLIT SWAP JOIN ;

( =========================================================== )

: WWORDS ( 'ccc' -- ) ( try WWORDS A B C D E F )
  BEGIN WORDS SOURCE SWAP DROP >IN @ = UNTIL ;

( =========================================================== )

: ROLL ( n ... +n -- ... n ) ( never never ROLL )
  ?DUP IF SWAP >R 1 - RECURSE R> SWAP THEN ;

: -ROLL ( ... n +n -- n ... ) ( never never never -ROLL )
  ?DUP IF ROT  >R 1 - RECURSE R> THEN ;

( =========================================================== )

: NOT ( n -- n ) INVERT ;

: CONVERT ( ud a -- ud a ) CHAR+ -1 >NUMBER DROP ;

H# 80 CONSTANT =IMMEDIATE

: FIND ( a -- a 0 | xt 1 | xt -1 )
  DUP >R  COUNT SFIND ( found ? )
  IF =IMMEDIATE AND ( attribute ? )
    IF 1 ( immediate )
    ELSE -1 ( non-immediate )
    THEN R> DROP EXIT
  THEN 2DROP  R> 0 ; ( not found )

: SEARCH-WORDLIST ( a u wid -- 0 | xt 1 | xt -1 )
  WID? ( found ? )
  IF =IMMEDIATE AND ( attribute ? )
    IF 1 EXIT ( immediate )
    THEN -1 EXIT ( non-immediate )
  THEN 2DROP  0 ; ( not found )

( =========================================================== )

\ The words EXPECT and SPAN are obsolescent.
\ The following definition may be used provided a program does not
\ depend on input being terminated when the final count is
\ reached.

VARIABLE SPAN
: EXPECT ( a u -- ) ACCEPT SPAN ! ;

( =========================================================== )

\ The word WORD is not used in eForth because it requires a
\ character string to be moved from the input buffer, converted
\ to a counted string, and placed in some other buffer. This is
\ unnecessary for both interpreting and compiling.

\ The ANS Standard has change all references to strings to an
\ address and count, except for WORD and FIND. Both words have
\ been in use for a long time, and should be considered
\ 'standard'. But I do not think either should be required in the
\ CORE and I think both should be considered obsolescent. WORD
\ already has obsolescent 'features'.

\ eForth uses only the address and count convention.

\ The following definition is provided as a concession, it has an
\ environmental dependency, it does NOT skip 'non-blank' leading
\ delimiters.

\ If you would like to write a corrected version of WORD, please
\ send it to me. It needs to skip leading delimiters and then
\ parse for that same character as a terminating delimiter.

: WORD ( c -- a )
  DUP BL = ( blank delimited ? )
  IF DROP PARSE-WORD ( skip leading blanks )
  ELSE PARSE ( does NOT skip non-blank leading delimiters )
  THEN HERE PACK ; ( move and convert string )

( =========================================================== )

\ [?]DO pushes the address of a1 to the
\       Return Stack for [?]LEAVE and [+]LOOP
\
\          v-------------------<<
\ [?]DO a1 ... [?]LEAVE ... [+]LOOP ...
\       >>--------+>----------------^
\
\          v-------------------------------------<<
\ [?]DO a1 ... IF a2 ... UNLOOP EXIT THEN ... [+]LOOP ...
\                 >>----------------------^
\       >>--------------------------------------------^
\
\          v-------------------<<
\ [?]DO a1 ... WHILE a2 ... [+]LOOP ... ELSE a4 ... UNLOOP THEN ...
\       >>--------------------------^        >>-----------------^
\                    >>-------------------------^

: _DO ( l i -- ) ( R: a -- a l i )
  BEGIN  SWAP  R> CELL+  DUP >R  SWAP >R  SWAP >R  >R ; \ ???
: _?DO ( l i -- ) ( R: a -- a l i )
  2DUP = UNTIL  2DROP  R> @ >R ; \ ???

: _LOOP ( -- ) ( R: a l i  a -- a l i | )
  R>  R> 1 + R>  2DUP XOR
  IF R@  SWAP >R  SWAP >R  >R  DROP  EXIT
  THEN 2DROP  R> DROP  >R ;

: _+LOOP ( n -- ) ( R: a l i  a -- a l i | )
  R> SWAP  DUP R@ +  SWAP
  DUP  R> NEGATE R@ +  NEGATE UM+ >R DROP ( l i -  n -  save carry )
  INVERT 0< R> + ( overflow ? sign of n and carry )
  IF R> R@  SWAP >R  SWAP >R  >R  DROP  EXIT
  THEN R> 2DROP  R> DROP  >R ;

: DO ( -- a ) ['] _DO COMPILE,  MARK ; IMMEDIATE
: ?DO ( -- a ) ['] _?DO COMPILE,  MARK ; IMMEDIATE

: LOOP ( a -- ) ['] _LOOP COMPILE,  [COMPILE] THEN ; IMMEDIATE
: +LOOP ( a -- ) ['] _+LOOP COMPILE,  [COMPILE] THEN ; IMMEDIATE

: UNLOOP ( -- ) ( R: a l i  a -- ) R>  R> R> 2DROP  R> DROP  >R ;

: LEAVE ( -- ) ( R: a l i  a -- )
  R> DROP  R> R> 2DROP  R> CELL- @ >R ; \ ???

: ?LEAVE ( f -- ) IF R> DROP LEAVE THEN ;

: I ( -- n ) ( R: a l i  a -- a l i ) R> R@ SWAP >R ;

: J ( -- n ) ( R: a l i  a l i  a -- a l i  a l i )
  R>  R> R> R>  R@  SWAP >R  SWAP >R  SWAP >R  SWAP >R ;

( test DO-LOOP ============================================== )

: L1 ( -- ) 9 0 DO I . LOOP ;
: L2 ( -- ) 9 0 ?DO I . LOOP ;
: L3 ( -- ) 9 9 ?DO I . LOOP ;

: L4 ( -- ) 9 0 ?DO I 3 = IF UNLOOP ." UNLOOP " EXIT THEN I . LOOP 99 . ;
: L5 ( -- ) 9 0 ?DO I 3 = IF LEAVE ." LEAVE " THEN I . LOOP 99 . ;
: L6 ( -- ) 9 0 ?DO I 3 = ?LEAVE I . LOOP 99 . ;

: L7 ( -- ) 9 0 ?DO I . 2 +LOOP ;
: L8 ( -- ) 0 9 ?DO I . -2 +LOOP ;

: L9 ( -- ) 9 0 ?DO 4 0 ?DO J . LOOP LOOP ;

( =========================================================== )

\     v--------<<
\ FOR ... NEXT a1 ...
\
\     v---------------------<<          >>----------v
\ FOR ... WHILE a1 ... NEXT a2 ... ELSE a3 ... THEN ...
\               >>-------------------------^
\
\                v-----------------<<
\ FOR ... AFT a1 ... THEN ... NEXT a2 ...
\             >>----------^

: _NEXT ( -- ) ( R: u -- u )
  R>  R> DUP
  IF 1 - >R  @ >R EXIT \ ???
  THEN DROP CELL+ >R ; \ ???

: FOR ( -- a ) ['] >R COMPILE,  [COMPILE] BEGIN ; IMMEDIATE
: NEXT ( a -- ) ['] _NEXT COMPILE,  RESOLVE ; IMMEDIATE

: AFT ( a -- a a )
  DROP  [COMPILE] AHEAD  [COMPILE] BEGIN  SWAP ; IMMEDIATE

( test FOR-NEXT ============================================= )

: N1 ( -- ) 9 FOR R@ . NEXT ;
: N2 ( -- )
  9 FOR 5 R@ < WHILE R@ . NEXT ." X" ELSE R> DROP ." Y" THEN ;
: N3 ( -- ) 9 FOR ." X" AFT ." Y" THEN R@ . NEXT ;

( =========================================================== )

( CASE structure )

0 CONSTANT CASE ( -- 0 ) IMMEDIATE

: OF ( -- sys )
  ['] OVER COMPILE,  ['] = COMPILE,
  [COMPILE] IF  ['] DROP COMPILE, ; IMMEDIATE

: ENDOF ( sys -- sys ) [COMPILE] ELSE ; IMMEDIATE

: ESAC ( 0 i*sys -- ) ( a useful factor )
  BEGIN ?DUP WHILE  [COMPILE] THEN  REPEAT ; IMMEDIATE

: ENDCASE ( 0 i*sys -- ) ['] DROP COMPILE,  [COMPILE] ESAC ; IMMEDIATE

( test CASE )

: TT ( n -- )
  CR ." TEST BEGIN "
  CASE
    1 OF ." HI BEE" ENDOF
    2 OF ." OH BEZEL" ENDOF
    ." NO WAY " DUP 0 .R
  ENDCASE ."  TEST END" ;

( ============================================================ )
( multitask information exchange and synchronization extension )
( modified polled version from Michael B. Montvelishsky )
( ============================================================ )

: CHAN ( 'name' -- ) ( -- a )
  CREATE
    0 , ( flag )
    0 , ( data )
;

: C> ( a -- n ) ( get data from a channel )
  BEGIN PAUSE DUP @ ( data ready ? )
  UNTIL 0 OVER !  CELL+ @ ( get data, flag free )
;

: >C ( n a -- ) ( put data to a channel )
  BEGIN PAUSE DUP @ 0= ( channel free ? )
  UNTIL DUP 2! ( flag inuse, put data )
;

( =========================================================== )
( ??? simplify )
( =========================================================== )

: BUFF ( n 'name' -- ) ( -- a ) ( ONLY powers of 2 )
  CREATE 0 , ( in and out index )
  DUP 1 - , ALLOT ( mask and circular buffer )
;

: B> ( a -- n ) ( get data from the buffer )
  >R ( save buffer )
  R@ CHAR+ C@ ( out index )
  BEGIN DUP R@ C@ = ( buffer empty ? )
  WHILE PAUSE ( yes, wait )
  REPEAT DUP R@ CELL+ CELL+ + @ ( get data )
  SWAP CELL+ R@ CELL+ C@ AND
  R> CHAR+ C! ( update out index )
;

: >B ( n a -- ) ( put data to the buffer )
  >R ( save buffer )
  R@ C@ ( in index )
  DUP CELL+ R@ CELL+ C@ AND ( next in index )
  BEGIN DUP R@ CHAR+ C@ = ( buffer full ? )
  WHILE PAUSE ( yes, wait )
  REPEAT R@ C! ( update in index )
  R> CELL+ CELL+ + ! ( put data )
;

( =========================================================== )

: []CHAN ( 'name' n -- ) ( n a -- a )
  CREATE CELLS 2 * HERE OVER ERASE ALLOT ?STACK
  DOES> SWAP CELLS 2 * + ;

: []CELL ( 'name' n -- ) ( n a -- a )
  CREATE CELLS HERE OVER ERASE ALLOT ?STACK
  DOES> SWAP CELLS + ;

( =========================================================== )

?CSP BASE !

FROM CON