commit 6f4ac1c44ad58dd50245d302858b4e805c0e028d Author: Brad Nelson Date: Sat Dec 26 16:47:54 2020 -0800 Adding EForth high level words cut and paste. diff --git a/eforth.fs b/eforth.fs new file mode 100644 index 0000000..6d5e715 --- /dev/null +++ b/eforth.fs @@ -0,0 +1,517 @@ +( Variables and User Variables ) + +: doVAR ( -- a ) R> ; + +VARIABLE UP ( -- a, Pointer to the user area.) + +: doUSER ( -- a, Run time routine for user variables.) + R> @ \ retrieve user area offset + UP @ + ; \ add to user area base addr +: doVOC ( -- ) R> CONTEXT ! ; +: FORTH ( -- ) doVOC [ 0 , 0 , +: doUSER ( -- a ) R> @ UP @ + ; + +( User Variables ) + +SP0 ( -- a, pointer to bottom of the data stack.) +RP0 ( -- a, pointer to bottom of the return stack.) +'?KEY ( -- a, execution vector of ?KEY. Default to ?rx.) +'EMIT ( -- a, execution vector of EMIT. Default to tx!) +'EXPECT ( -- a, execution vector of EXPECT. Default to 'accept'.) +'TAP ( -- a, execution vector of TAP. Defulat the kTAP.) +'ECHO ( -- a, execution vector of ECHO. Default to tx!.) +'PROMPT ( -- a, execution vector of PROMPT. Default to '.ok'.) +BASE ( -- a,.radix base for numeric I/O. Default to 10.) +tmp ( -- a, a temporary storage location used in parse and find.) +SPAN ( -- a, hold character count received by EXPECT.) +>IN ( -- a, hold the character pointer while parsing input stream.) +#TIB ( -- a, hold the current count and address of the terminal input buffer. + Terminal Input Buffer used one cell after #TIB.) +CSP ( -- a, hold the stack pointer for error checking.) +'EVAL ( -- a, execution vector of EVAL. Default to EVAL.) +'NUMBER ( -- a, address of number conversion. Default to NUMBER?.) +HLD ( -- a, hold a pointer in building a numeric output string.) +HANDLER ( -- a, hold the return stack pointer for error handling.) +CONTEXT ( -- a, a area to specify vocabulary search order. Default to FORTH. + Vocabulary stack, 8 cells follwing CONTEXT.) +CURRENT ( -- a, point to the vocabulary to be extended. Default to FORTH. + Vocabulary link uses one cell after CURRENT.) +CP ( -- a, point to the top of the code dictionary.) +NP ( -- a, point to the bottom of the name dictionary.) +LAST ( -- a, point to the last name in the name dictionary.) + +( Common Functions ) + +: ?DUP ( w -- w w | 0 ) DUP IF DUP THEN ; +: ROT ( w1 w2 w3 -- w2 w3 w1 ) >R SWAP R> SWAP ; +: 2DROP ( w w -- ) DROP DROP ; +: 2DUP ( w1 w2 -- w1 w2 w1 w2 ) OVER OVER ; +: + ( w w -- w ) UM+ DROP ; +: NOT ( w -- w ) -1 XOR ; +: NEGATE ( n -- -n ) NOT 1 + ; +: DNEGATE ( d -- -d ) NOT >R NOT 1 UM+ R> + ; +: D+ ( d d -- d ) >R SWAP >R UM+ R> R> + + ; +: - ( w w -- w ) NEGATE + ; +: ABS ( n -- +n ) DUP 0< IF NEGATE THEN ; + +( Comparison ) + +: = ( w w -- t ) XOR IF 0 EXIT THEN -1 ; +: U< ( u u -- t ) 2DUP XOR 0< IF SWAP DROP 0< EXIT THEN - 0< ; +: < ( n n -- t ) 2DUP XOR 0< IF DROP 0< EXIT THEN - 0< ; +: MAX ( n n -- n ) 2DUP < IF SWAP THEN DROP ; +: MIN ( n n -- n ) 2DUP SWAP < IF SWAP THEN DROP ; +: WITHIN ( u ul uh -- t ) \ ul <= u < uh + OVER - >R - R> U< ; + +( Divide ) + +: UM/MOD ( ud u -- ur uq ) + 2DUP U< + IF NEGATE 15 + FOR >R DUP UM+ >R >R DUP UM+ R> + DUP + R> R@ SWAP >R UM+ R> OR + IF >R DROP 1 + R> ELSE DROP THEN R> + NEXT DROP SWAP EXIT + THEN DROP 2DROP -1 DUP ; +: M/MOD ( d n -- r q ) \ floored division + DUP 0< DUP >R + IF NEGATE >R DNEGATE R> + THEN >R DUP 0< IF R@ + THEN R> UM/MOD R> + IF SWAP NEGATE SWAP THEN ; +: /MOD ( n n -- r q ) OVER 0< SWAP M/MOD ; +: MOD ( n n -- r ) /MOD DROP ; +: / ( n n -- q ) /MOD SWAP DROP ; + +( Multiply ) + +: UM* ( u u -- ud ) + 0 SWAP ( u1 0 u2 ) 15 + FOR DUP UM+ >R >R DUP UM+ R> + R> + IF >R OVER UM+ R> + THEN + NEXT ROT DROP ; +: * ( n n -- n ) UM* DROP ; +: M* ( n n -- d ) + 2DUP XOR 0< >R ABS SWAP ABS UM* R> IF DNEGATE THEN ; +: */MOD ( n n n -- r q ) >R M* R> M/MOD ; +: */ ( n n n -- q ) */MOD SWAP DROP ; + +( Memory Alignment ) + +: CELL- ( a -- a ) -2 + ; +: CELL+ ( a -- a ) 2 + ; +: CELLS ( n -- n ) 2 * ; +: ALIGNED ( b -- a ) + DUP 0 2 UM/MOD DROP DUP + IF 2 SWAP - THEN + ; +: BL ( -- 32 ) 32 ; +: >CHAR ( c -- c ) + $7F AND DUP 127 BL WITHIN IF DROP 95 THEN ; +: DEPTH ( -- n ) SP@ SP0 @ SWAP - 2 / ; +: PICK ( +n -- w ) 1 + CELLS SP@ + @ ; + +( Memory Access ) + +: +! ( n a -- ) SWAP OVER @ + SWAP ! ; +: 2! ( d a -- ) SWAP OVER ! CELL+ ! ; +: 2@ ( a -- d ) DUP CELL+ @ SWAP @ ; +: COUNT ( b -- b +n ) DUP 1 + SWAP C@ ; +: HERE ( -- a ) CP @ ; +: PAD ( -- a ) HERE 80 + ; +: TIB ( -- a ) #TIB CELL+ @ ; +: @EXECUTE ( a -- ) @ ?DUP IF EXECUTE THEN ; +: CMOVE ( b b u -- ) + FOR AFT >R DUP C@ R@ C! 1 + R> 1 + THEN NEXT 2DROP ; +: FILL ( b u c -- ) + SWAP FOR SWAP AFT 2DUP C! 1 + THEN NEXT 2DROP ; +: -TRAILING ( b u -- b u ) + FOR AFT BL OVER R@ + C@ < + IF R> 1 + EXIT THEN THEN + NEXT 0 ; +: PACK$ ( b u a -- a ) \ null fill + ALIGNED DUP >R OVER + DUP 0 2 UM/MOD DROP + - OVER + 0 SWAP ! 2DUP C! 1 + SWAP CMOVE R> ; + +( Numeric Output ) + +: DIGIT ( u -- c ) 9 OVER < 7 AND + 48 + ; +: EXTRACT ( n base -- n c ) 0 SWAP UM/MOD SWAP DIGIT ; +: <# ( -- ) PAD HLD ! ; +: HOLD ( c -- ) HLD @ 1 - DUP HLD ! C! ; +: # ( u -- u ) BASE @ EXTRACT HOLD ; +: #S ( u -- 0 ) BEGIN # DUP WHILE REPEAT ; +: SIGN ( n -- ) 0< IF 45 HOLD THEN ; +: #> ( w -- b u ) DROP HLD @ PAD OVER - ; +: str ( n -- b u ) DUP >R ABS <# #S R> SIGN #> ; +: HEX ( -- ) 16 BASE ! ; +: DECIMAL ( -- ) 10 BASE ! ; + +( Number Output ) + +: str ( n -- b u ) + ( Convert a signed integer to a numeric string.) + DUP >R ( save a copy for sign) + ABS ( use absolute of n) + <# #S ( convert all digits) + R> SIGN ( add sign from n) + #> ; ( return number string addr and length) +: HEX ( -- ) + ( Use radix 16 as base for numeric conversions.) + 16 BASE ! ; +: DECIMAL ( -- ) + ( Use radix 10 as base for numeric conversions.) + 10 BASE ! ; +: .R ( n +n -- ) + ( Display an integer in a field of n columns, right justified.) + >R str ( convert n to a number string) + R> OVER - SPACES ( print leading spaces) + TYPE ; ( print number in +n column format) +: U.R ( u +n -- ) + ( Display an unsigned integer in n column, right justified.) + >R ( save column number) + <# #S #> R> ( convert unsigned number) + OVER - SPACES ( print leading spaces) + TYPE ; ( print number in +n columns) +: U. ( u -- ) + ( Display an unsigned integer in free format.) + <# #S #> ( convert unsigned number) + SPACE ( print one leading space) + TYPE ; ( print number) +: . ( w -- ) + ( Display an integer in free format, preceeded by a space.) + BASE @ 10 XOR ( if not in decimal mode) + IF U. EXIT THEN ( print unsigned number) + str SPACE TYPE ; ( print signed number if decimal) +: ? ( a -- ) + ( Display the contents in a memory cell.) + @ . ; ( very simple but useful command) + +( Number Input ) + +: DIGIT? ( c base -- u t ) + >R 48 - 9 OVER < + IF 7 - DUP 10 < OR THEN DUP R> U< ; +: NUMBER? ( a -- n T | a F ) + BASE @ >R 0 OVER COUNT ( a 0 b n) + OVER C@ 36 = + IF HEX SWAP 1 + SWAP 1 - THEN ( a 0 b' n') + OVER C@ 45 = >R ( a 0 b n) + SWAP R@ - SWAP R@ + ( a 0 b" n") ?DUP + IF 1 - ( a 0 b n) + FOR DUP >R C@ BASE @ DIGIT? + WHILE SWAP BASE @ * + R> 1 + + NEXT DROP R@ ( b ?sign) IF NEGATE THEN SWAP + ELSE R> R> ( b index) 2DROP ( digit number) 2DROP 0 + THEN DUP + THEN R> ( n ?sign) 2DROP R> BASE ! ; + +( Basic I/O ) + +: ?KEY ( -- c T | F ) '?KEY @EXECUTE ; +: KEY ( -- c ) BEGIN ?KEY UNTIL ; +: EMIT ( c -- ) 'EMIT @EXECUTE ; +: NUF? ( -- f ) ?KEY DUP IF 2DROP KEY 13 = THEN ; +: PACE ( -- ) 11 EMIT ; +: SPACE ( -- ) BL EMIT ; +: CHARS ( +n c -- ) \ ???ANS conflict + SWAP 0 MAX FOR AFT DUP EMIT THEN NEXT DROP ; +: SPACES ( +n -- ) BL CHARS ; +: TYPE ( b u -- ) FOR AFT DUP C@ EMIT 1 + THEN NEXT DROP ; +: CR ( -- ) 13 EMIT 10 EMIT ; +: do$ ( -- a ) + R> R@ R> COUNT + ALIGNED >R SWAP >R ; +: $"| ( -- a ) do$ ; +: ."| ( -- ) do$ COUNT TYPE ; COMPILE-ONLY +: .R ( n +n -- ) >R str R> OVER - SPACES TYPE ; +: U.R ( u +n -- ) >R <# #S #> R> OVER - SPACES TYPE ; +: U. ( u -- ) <# #S #> SPACE TYPE ; +: . ( n -- ) BASE @ 10 XOR IF U. EXIT THEN str SPACE TYPE ; +: ? ( a -- ) @ . ; + +( Parsing ) + +: parse ( b u c -- b u delta ; ) + tmp ! OVER >R DUP \ b u u + IF 1 - tmp @ BL = + IF \ b u' \ 'skip' + FOR BL OVER C@ - 0< NOT WHILE 1 + + NEXT ( b) R> DROP 0 DUP EXIT \ all delim + THEN R> + THEN OVER SWAP \ b' b' u' \ 'scan' + FOR tmp @ OVER C@ - tmp @ BL = + IF 0< THEN WHILE 1 + + NEXT DUP >R ELSE R> DROP DUP 1 + >R + THEN OVER - R> R> - EXIT + THEN ( b u) OVER R> - ; +: PARSE ( c -- b u ; ) + >R TIB >IN @ + #TIB @ >IN @ - R> parse >IN +! ; +: .( ( -- ) 41 PARSE TYPE ; IMMEDIATE +: ( ( -- ) 41 PARSE 2DROP ; IMMEDIATE +: \ ( -- ) #TIB @ >IN ! ; IMMEDIATE +: CHAR ( -- c ) BL PARSE DROP C@ ; +: TOKEN ( -- a ; ) + BL PARSE 31 MIN NP @ OVER - CELL- PACK$ ; +: WORD ( c -- a ; ) PARSE HERE PACK$ ; + +( Dictionary Search ) + +: NAME> ( a -- xt ) CELL- CELL- @ ; +: SAME? ( a a u -- a a f \ -0+ ) + FOR AFT OVER R@ CELLS + @ + OVER R@ CELLS + @ - ?DUP + IF R> DROP EXIT THEN THEN + NEXT 0 ; +: find ( a va -- xt na | a F ) + SWAP \ va a + DUP C@ 2 / tmp ! \ va a \ get cell count + DUP @ >R \ va a \ count byte & 1st char + CELL+ SWAP \ a' va + BEGIN @ DUP \ a' na na + IF DUP @ [ =MASK ] LITERAL AND R@ XOR \ ignore lexicon bits + IF CELL+ -1 ELSE CELL+ tmp @ SAME? THEN + ELSE R> DROP EXIT + THEN + WHILE CELL- CELL- \ a' la + REPEAT R> DROP SWAP DROP CELL- DUP NAME> SWAP ; +: NAME? ( a -- xt na | a F ) + CONTEXT DUP 2@ XOR IF CELL- THEN >R \ context<>also + BEGIN R> CELL+ DUP >R @ ?DUP + WHILE find ?DUP + UNTIL R> DROP EXIT THEN R> DROP 0 ; + +( Terminal ) + +: ^H ( b b b -- b b b ) \ backspace + >R OVER R> SWAP OVER XOR + IF 8 'ECHO @EXECUTE + 32 'ECHO @EXECUTE \ distructive + 8 'ECHO @EXECUTE \ backspace + THEN ; +: TAP ( bot eot cur c -- bot eot cur ) + DUP 'ECHO @EXECUTE OVER C! 1 + ; +: kTAP ( bot eot cur c -- bot eot cur ) + DUP 13 XOR + IF 8 XOR IF BL TAP ELSE ^H THEN EXIT + THEN DROP SWAP DROP DUP ; +: accept ( b u -- b u ) + OVER + OVER + BEGIN 2DUP XOR + WHILE KEY DUP BL - 95 U< + IF TAP ELSE 'TAP @EXECUTE THEN + REPEAT DROP OVER - ; +: EXPECT ( b u -- ) 'EXPECT @EXECUTE SPAN ! DROP ; +: QUERY ( -- ) + TIB 80 'EXPECT @EXECUTE #TIB ! DROP 0 >IN ! ; + +( Error Handling ) + +: CATCH ( ca -- err#/0 ) + ( Execute word at ca and set up an error frame for it.) + SP@ >R ( save current stack pointer on return stack ) + HANDLER @ >R ( save the handler pointer on return stack ) + RP@ HANDLER ! ( save the handler frame pointer in HANDLER ) + ( ca ) EXECUTE ( execute the assigned word over this safety net ) + R> HANDLER ! ( normal return from the executed word ) + ( restore HANDLER from the return stack ) + R> DROP ( discard the saved data stack pointer ) + 0 ; ( push a no-error flag on data stack ) +: THROW ( err# -- err# ) + ( Reset system to current local error frame an update error flag.) + HANDLER @ RP! ( expose latest error handler frame on return stack) + R> HANDLER ! ( restore previously saved error handler frame ) + R> SWAP >R ( retrieve the data stack pointer saved ) + SP! ( restore the data stack ) + DROP + R> ; ( retrived err# ) + +CREATE NULL$ 0 , $," coyote" +: ABORT ( -- ) NULL$ THROW ; +: abort" ( f -- ) IF do$ THROW THEN do$ DROP ; + +( Text Interpreter ) + +: $INTERPRET ( a -- ) + NAME? ?DUP + IF @ $40 AND + ABORT" compile ONLY" EXECUTE EXIT + THEN 'NUMBER @EXECUTE IF EXIT THEN THROW ; +: [ ( -- ) doLIT $INTERPRET 'EVAL ! ; IMMEDIATE +: .OK ( -- ) doLIT $INTERPRET 'EVAL @ = IF ." ok" THEN CR ; +: ?STACK ( -- ) DEPTH 0< ABORT" underflow" ; +: EVAL ( -- ) + BEGIN TOKEN DUP C@ + WHILE 'EVAL @EXECUTE ?STACK + REPEAT DROP 'PROMPT @EXECUTE ; + +( Shell ) + +: PRESET ( -- ) SP0 @ SP! TIB #TIB CELL+ ! ; +: xio ( a a a -- ) \ reset 'EXPECT 'TAP 'ECHO 'PROMPT + doLIT accept 'EXPECT 2! 'ECHO 2! ; COMPILE-ONLY +: FILE ( -- ) + doLIT PACE doLIT DROP doLIT kTAP xio ; +: HAND ( -- ) + doLIT .OK doLIT EMIT [ kTAP xio ; + CREATE I/O ' ?RX , ' TX! , \ defaults +: CONSOLE ( -- ) I/O 2@ '?KEY 2! HAND ; + +: QUIT ( -- ) + RP0 @ RP! + BEGIN [COMPILE] [ + BEGIN QUERY doLIT EVAL CATCH ?DUP + UNTIL 'PROMPT @ SWAP CONSOLE NULL$ OVER XOR + IF CR #TIB 2@ TYPE + CR >IN @ 94 CHARS + CR COUNT TYPE ." ? " + THEN doLIT .OK XOR + IF $1B EMIT THEN + PRESET + AGAIN ; + +( Interpreter and Compiler ) + +: [ ( -- ) + [ ' $INTERPRET ] LITERAL + 'EVAL ! ( vector EVAL to $INTERPRET ) +; IMMEDIATE ( enter into text interpreter mode ) + +: ] ( -- ) + [ ' $COMPILE ] LITERAL + 'EVAL ! ( vector EVAL to $COMPILE ) +; + +( Primitive Compiler Words ) + +: ' ( -- xt ) TOKEN NAME? IF EXIT THEN THROW ; +: ALLOT ( n -- ) CP +! ; +: , ( w -- ) HERE DUP CELL+ CP ! ! ; \ ???ALIGNED +: [COMPILE] ( -- ; ) ' , ; IMMEDIATE +: COMPILE ( -- ) R> DUP @ , CELL+ >R ; +: LITERAL ( w -- ) COMPILE doLIT , ; IMMEDIATE +: $," ( -- ) 34 WORD COUNT ALIGNED CP ! ; +: RECURSE ( -- ) LAST @ NAME> , ; IMMEDIATE + +( Structures ) + +: MARK ( -- A ) HERE 0 , ; +: >RESOLVE ( A -- ) R MARK ; IMMEDIATE +: AHEAD ( -- A ) COMPILE branch >MARK ; IMMEDIATE +: REPEAT ( A a -- ) [COMPILE] AGAIN >RESOLVE ; IMMEDIATE +: THEN ( A -- ) >RESOLVE ; IMMEDIATE +: AFT ( a -- a A ) DROP [COMPILE] AHEAD [COMPILE] BEGIN SWAP ; IMMEDIATE +: ELSE ( A -- A ) [COMPILE] AHEAD SWAP [COMPILE] THEN ; IMMEDIATE +: WHEN ( a A -- a A a ) [COMPILE] IF OVER ; IMMEDIATE +: WHILE ( a -- A a ) [COMPILE] IF SWAP ; IMMEDIATE +: ABORT" ( -- ; ) COMPILE abort" $," ; IMMEDIATE +: $" ( -- ; ) COMPILE $"| $," ; IMMEDIATE +: ." ( -- ; ) COMPILE ."| $," ; IMMEDIATE + +( Compiler ) + +: ?UNIQUE ( a -- a ) DUP NAME? IF ." reDef " OVER COUNT TYPE THEN DROP ; +: $,n ( a -- ) + DUP C@ + IF ?UNIQUE + ( na) DUP LAST ! \ for OVERT + ( na) HERE ALIGNED SWAP + ( cp na) CELL- + ( cp la) CURRENT @ @ + ( cp la na') OVER ! + ( cp la) CELL- DUP NP ! ( ptr) ! EXIT + THEN $" name" THROW ; +.( FORTH Compiler ) +: $COMPILE ( a -- ) + NAME? ?DUP + IF @ $80 AND + IF EXECUTE ELSE , THEN EXIT + THEN 'NUMBER @EXECUTE + IF [COMPILE] LITERAL EXIT + THEN THROW ; +: OVERT ( -- ) LAST @ CURRENT @ ! ; +: ; ( -- ) + COMPILE EXIT [COMPILE] [ OVERT ; IMMEDIATE +: ] ( -- ) doLIT $COMPILE 'EVAL ! ; +: call, ( xt -- ) \ DTC 8086 relative call + $E890 , HERE CELL+ - , ; +: : ( -- ; ) TOKEN $,n doLIT doLIST call, ] ; +: IMMEDIATE ( -- ) $80 LAST @ @ OR LAST @ ! ; + +( Defining Words ) + +: USER ( n -- ; ) + TOKEN $,n OVERT + doLIT doLIST COMPILE doUSER , ; +: CREATE ( -- ; ) + TOKEN $,n OVERT + doLIT doLIST COMPILE doVAR ; +: VARIABLE ( -- ; ) CREATE 0 , ; + +( Memory Dump ) + +: _TYPE ( b u -- ) + FOR AFT DUP C@ >CHAR EMIT 1 + THEN NEXT DROP ; +: dm+ ( b u -- b ) + OVER 4 U.R SPACE FOR AFT DUP C@ 3 U.R 1 + THEN NEXT ; +: DUMP ( b u -- ) + BASE @ >R HEX 16 / + FOR CR 16 2DUP dm+ ROT ROT 2 SPACES _TYPE NUF? NOT WHILE + NEXT ELSE R> DROP THEN DROP R> BASE ! ; + +( Stack Tools ) + +: .S ( -- ) CR DEPTH FOR AFT R@ PICK . THEN NEXT ." NAME ( xt -- na | F ) + CURRENT + BEGIN CELL+ @ ?DUP WHILE 2DUP + BEGIN @ DUP WHILE 2DUP NAME> XOR + WHILE CELL- + REPEAT THEN SWAP DROP ?DUP + UNTIL SWAP DROP SWAP DROP EXIT THEN DROP 0 ; +: .ID ( a -- ) + ?DUP IF COUNT $01F AND _TYPE EXIT THEN ." {noName}" ; +: SEE ( -- ; ) + ' CR CELL+ + BEGIN CELL+ DUP @ DUP IF >NAME THEN ?DUP + IF SPACE .ID ELSE DUP @ U. THEN NUF? + UNTIL DROP ; +: WORDS ( -- ) + CR CONTEXT @ + BEGIN @ ?DUP + WHILE DUP SPACE .ID CELL- NUF? + UNTIL DROP THEN ; + +( Startup ) + +: VER ( -- u ) $101 ; +: hi ( -- ) + !IO BASE @ HEX \ initialize IO device & sign on + CR ." eFORTH V" VER <# # # 46 HOLD # #> TYPE + CR ; +: EMPTY ( -- ) + FORTH CONTEXT @ DUP CURRENT 2! 6 CP 3 MOVE OVERT ; + CREATE 'BOOT ' hi , \ application vector +: COLD ( -- ) + BEGIN + U0 UP 74 CMOVE + PRESET 'BOOT @EXECUTE + FORTH CONTEXT @ DUP CURRENT 2! OVERT + QUIT + AGAIN ; +