PageRenderTime 56ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/samo-lib/forth/EForthOriginals/linux-eforth-1.0e/eforth.4th

https://github.com/sunnysujan/wikireader
Forth | 864 lines | 641 code | 223 blank | 0 comment | 3 complexity | 42311031f4703fd0010697e89c7dccd6 MD5 | raw file
  1. \ eForth Initial Model (8086)
  2. \ Based on bFORTH 1990 by Bill Muench, 1990
  3. \ Donated to eForth Working Group, Silicon Valley FIG Chapter
  4. \ to serve as a model of portable Forth for experimentation.
  5. \ Conventions
  6. \
  7. \ <string> characters in the input stream
  8. \
  9. \ a aligned address
  10. \ b byte address
  11. \ c character
  12. \ ca code address
  13. \ cy carry
  14. \ d signed double integer
  15. \ F logical false
  16. \ f flag 0 or non-zero
  17. \ la link address
  18. \ n signed integer
  19. \ na name address
  20. \ T logical true
  21. \ t flag T or F
  22. \ u unsigned integer
  23. \ ud unsigned double integer
  24. \ va vocabulary address
  25. \ w unspecified weighted value
  26. \ Header: token(ptr) link(la) name(na)
  27. \
  28. \ Count-byte and Lexicon bits ioxn nnnn
  29. \ i - immediate
  30. \ o - compile-only
  31. \ x - tag
  32. \ n - string length (31 characters MAX)
  33. \ Compiler does not set bits in the NAME string
  34. \ 0 < la na < .. < la na < va < CONTEXT @
  35. \ 0 < FORTH < .. < vl va < vl va < CURRENT CELL+ @
  36. .( Equates )
  37. $xxxx EQU =RP \ return stack base
  38. $xxxx EQU =SP \ data stack base
  39. $xxxx EQU =UP \ user base
  40. $xxxx EQU =TIB \ default Terminal Input Buffer
  41. $0080 EQU =IMED \ lexicom immediate bit
  42. $0040 EQU =COMP \ lexicom compile-only bit
  43. $7F1F EQU =MASK \ lexicon bit mask
  44. $0001 EQU =BYTE \ size of a byte
  45. $0002 EQU =CELL \ size of a cell
  46. $000A EQU =BASE \ default radix
  47. $0008 EQU =VOCS \ vocabulary stack depth
  48. $E890 EQU =CALL \ 8086 CALL opcode (NOP CALL)
  49. \ 8086 register useage
  50. \
  51. \ AX BX CX DX DI ES free
  52. \ SP data stack pointer
  53. \ BP return stack pointer
  54. \ SI interpreter pointer
  55. \ CS=DS=SS segment pointers
  56. \ IP instruction pointer
  57. \ The Forth inner interpreter
  58. \
  59. \ On the 8086 it is more efficient to compile
  60. \ the inner interpreter as inline code.
  61. \ On other processors it may be better
  62. \ to jump to the routine.
  63. MACRO NEXT ( -- )
  64. LODS WORD \ 1 byte
  65. JMP AX \ 2 bytes
  66. END-MACRO
  67. .( Special interpreters )
  68. CODE doLIT ( -- w ) COMPILE-ONLY
  69. LODS WORD \ r> dup 2+ >r @
  70. PUSH AX
  71. NEXT
  72. END-CODE
  73. CODE doLIST ( a -- ) \ call dolist list..
  74. XCHG BP, SP
  75. PUSH SI \ push on return stack
  76. XCHG BP, SP
  77. POP SI \ new list address
  78. NEXT
  79. END-CODE
  80. CODE COLD ( -- )
  81. JMP ORIG
  82. CODE BYE
  83. INT $20
  84. CODE EXECUTE ( a -- )
  85. POP BX
  86. JMP BX
  87. CODE EXIT ( -- )
  88. XCHG BP, SP
  89. POP SI \ pop from return stack
  90. XCHG BP, SP
  91. NEXT
  92. END-CODE
  93. .( Loop & Branch 16bit absolute address )
  94. \ : next ( -- ) \ hiLevel model 16bit absolute branch
  95. \ r> r> dup if 1 - >r @ >r exit then drop cell+ >r ;
  96. CODE next ( -- ) COMPILE-ONLY \ single index loop
  97. SUB 0 [BP], # 1 WORD \ decrement index
  98. U>= IF \ test index
  99. MOV SI, 0 [SI] \ continue looping, r> @ >r
  100. NEXT
  101. THEN
  102. INC BP INC BP \ drop index (pop return stack)
  103. LABEL noBRAN
  104. INC SI INC SI \ exit loop
  105. NEXT
  106. END-CODE
  107. CODE ?branch ( f -- ) COMPILE-ONLY
  108. POP BX
  109. OR BX, BX \ test flag
  110. JNZ noBRAN
  111. MOV SI, 0 [SI] \ branch, r> @ >r
  112. NEXT
  113. END-CODE
  114. CODE branch ( -- ) COMPILE-ONLY
  115. MOV SI, 0 [SI] \ r> @ >r
  116. NEXT
  117. END-CODE
  118. .( Memory fetch & store )
  119. CODE ! ( w a -- )
  120. POP BX
  121. POP 0 [BX]
  122. NEXT
  123. END-CODE
  124. CODE @ ( a -- w )
  125. POP BX
  126. PUSH 0 [BX]
  127. NEXT
  128. END-CODE
  129. CODE C! ( w b -- )
  130. POP BX
  131. POP AX
  132. MOV 0 [BX], AL
  133. NEXT
  134. END-CODE
  135. CODE C@ ( b -- c )
  136. POP BX
  137. XOR AX, AX
  138. MOV AL, 0 [BX]
  139. PUSH AX
  140. NEXT
  141. END-CODE
  142. .( Return Stack )
  143. CODE RP@ ( -- a )
  144. PUSH BP
  145. NEXT
  146. END-CODE
  147. CODE RP! ( a -- ) COMPILE-ONLY
  148. POP BP
  149. NEXT
  150. END-CODE
  151. CODE R> ( -- w ) COMPILE-ONLY
  152. PUSH 0 [BP]
  153. INC BP INC BP
  154. NEXT
  155. END-CODE
  156. CODE R@ ( -- w )
  157. PUSH 0 [BP]
  158. NEXT
  159. END-CODE
  160. CODE >R ( w -- ) COMPILE-ONLY
  161. DEC BP DEC BP
  162. POP 0 [BP]
  163. NEXT
  164. END-CODE
  165. .( Data Stack )
  166. CODE SP@ ( -- a )
  167. MOV BX, SP
  168. PUSH BX
  169. NEXT
  170. END-CODE
  171. CODE SP! ( a -- )
  172. POP SP
  173. NEXT
  174. END-CODE
  175. CODE DROP ( w -- )
  176. INC SP INC SP
  177. NEXT
  178. END-CODE
  179. CODE DUP ( w -- w w )
  180. MOV BX, SP
  181. PUSH 0 [BX]
  182. NEXT
  183. END-CODE
  184. CODE SWAP ( w1 w2 -- w2 w1 )
  185. POP BX
  186. POP AX
  187. PUSH BX
  188. PUSH AX
  189. NEXT
  190. END-CODE
  191. CODE OVER ( w1 w2 -- w1 w2 w1 )
  192. MOV BX, SP
  193. PUSH 2 [BX]
  194. NEXT
  195. END-CODE
  196. : ?DUP ( w -- w w, 0 ) DUP IF DUP THEN ;
  197. : NIP ( w w -- w ) SWAP DROP ;
  198. : ROT ( w1 w2 w3 -- w2 w3 w1 ) >R SWAP R> SWAP ;
  199. : 2DROP ( w w -- ) DROP DROP ;
  200. : 2DUP ( w1 w2 -- w1 w2 w1 w2 ) OVER OVER ;
  201. .( Logic )
  202. CODE 0< ( n -- t )
  203. POP AX
  204. CWD
  205. PUSH DX
  206. NEXT
  207. END-CODE
  208. CODE AND ( w w -- w )
  209. POP BX
  210. POP AX
  211. AND BX, AX
  212. PUSH BX
  213. NEXT
  214. END-CODE
  215. CODE OR ( w w -- w )
  216. POP BX
  217. POP AX
  218. OR BX, AX
  219. PUSH BX
  220. NEXT
  221. END-CODE
  222. CODE XOR ( w w -- w )
  223. POP BX
  224. POP AX
  225. XOR BX, AX
  226. PUSH BX
  227. NEXT
  228. END-CODE
  229. : INVERT ( w -- w ) -1 XOR ;
  230. .( Arithmetic )
  231. CODE UM+ ( u u -- u cy ) \ or ( u u -- ud )
  232. XOR CX, CX
  233. POP BX
  234. POP AX
  235. ADD AX, BX
  236. RCL CX, # 1 \ pick up carry
  237. PUSH AX
  238. PUSH CX
  239. NEXT
  240. END-CODE
  241. : + ( u u -- u ) UM+ DROP ;
  242. : NEGATE ( n -- -n ) INVERT 1 + ;
  243. : DNEGATE ( d -- -d ) INVERT >R INVERT 1 UM+ R> + ;
  244. : - ( w w -- w ) NEGATE + ;
  245. : ABS ( n -- +n ) DUP 0< IF NEGATE THEN ;
  246. .( User variables )
  247. : doUSER ( -- a ) R> @ UP @ + ; COMPILE-ONLY
  248. : doVAR ( -- a ) R> ; COMPILE-ONLY
  249. 8 \ start offset
  250. DUP USER SP0 1 CELL+ \ initial data stack pointer
  251. DUP USER RP0 1 CELL+ \ initial return stack pointer
  252. DUP USER '?KEY 1 CELL+ \ character input ready vector
  253. DUP USER 'EMIT 1 CELL+ \ character output vector
  254. DUP USER 'EXPECT 1 CELL+ \ line input vector
  255. DUP USER 'TAP 1 CELL+ \ input case vector
  256. DUP USER 'ECHO 1 CELL+ \ input echo vector
  257. DUP USER 'PROMPT 1 CELL+ \ operator prompt vector
  258. DUP USER BASE 1 CELL+ \ number base
  259. DUP USER temp 1 CELL+ \ scratch
  260. DUP USER SPAN 1 CELL+ \ #chars input by EXPECT
  261. DUP USER >IN 1 CELL+ \ input buffer offset
  262. DUP USER #TIB 1 CELL+ \ #chars in the input buffer
  263. 1 CELLS ALLOT \ address of input buffer
  264. DUP USER UP 1 CELL+ \ user base pointer
  265. DUP USER CSP 1 CELL+ \ save stack pointers
  266. DUP USER 'EVAL 1 CELL+ \ interpret/compile vector
  267. DUP USER 'NUMBER 1 CELL+ \ numeric input vector
  268. DUP USER HLD 1 CELL+ \ formated numeric string
  269. DUP USER HANDLER 1 CELL+ \ error frame pointer
  270. DUP USER CONTEXT 1 CELL+ \ first search vocabulary
  271. =VOCS CELL+ \ vocabulary stack
  272. DUP USER CURRENT 1 CELL+ \ definitions vocabulary
  273. 1 CELL+ \ newest vocabulary
  274. DUP USER CP 1 CELL+ \ dictionary code pointer
  275. 1 CELL+ \ dictionary name pointer
  276. 1 CELL+ \ last name compiled
  277. ?USER
  278. .( Comparison )
  279. : 0= ( w -- t ) IF 0 EXIT THEN -1 ;
  280. : = ( w w -- t ) XOR 0= ;
  281. : U< ( u u -- t ) 2DUP XOR 0< IF NIP 0< EXIT THEN - 0< ;
  282. : < ( n n -- t ) 2DUP XOR 0< IF DROP 0< EXIT THEN - 0< ;
  283. : MAX ( n n -- n ) 2DUP < IF SWAP THEN DROP ;
  284. : MIN ( n n -- n ) 2DUP SWAP < IF SWAP THEN DROP ;
  285. : WITHIN ( u ul uh -- t ) OVER - >R - R> U< ;
  286. .( Divide )
  287. : UM/MOD ( udl udh un -- ur uq )
  288. 2DUP U<
  289. IF NEGATE 15
  290. FOR >R DUP UM+ >R >R DUP UM+ R> + DUP
  291. R> R@ SWAP >R UM+ R> OR
  292. IF >R DROP 1 + R> ELSE DROP THEN R>
  293. NEXT DROP SWAP EXIT
  294. THEN DROP 2DROP -1 DUP ;
  295. : M/MOD ( d n -- r q ) \ floored
  296. DUP 0< DUP >R
  297. IF NEGATE >R DNEGATE R>
  298. THEN >R DUP 0< IF R@ + THEN R> UM/MOD R>
  299. IF SWAP NEGATE SWAP THEN ;
  300. : /MOD ( n n -- r q ) OVER 0< SWAP M/MOD ;
  301. : MOD ( n n -- r ) /MOD DROP ;
  302. : / ( n n -- q ) /MOD NIP ;
  303. .( Multiply )
  304. : UM* ( u1 u2 -- ud )
  305. 0 SWAP ( u1 0 u2 ) 15
  306. FOR DUP UM+ >R >R DUP UM+ R> + R>
  307. IF >R OVER UM+ R> + THEN
  308. NEXT ROT DROP ;
  309. : * ( n n -- n ) UM* DROP ;
  310. : M* ( n n -- d )
  311. 2DUP XOR 0< >R ABS SWAP ABS UM* R> IF DNEGATE THEN ;
  312. : */MOD ( n n n -- r q ) >R M* R> M/MOD ;
  313. : */ ( n n n -- q ) */MOD NIP ;
  314. .( Bits & Bytes )
  315. : BYTE+ ( b -- b ) [ =BYTE ] LITERAL + ;
  316. : CELL+ ( a -- a ) [ =CELL ] LITERAL + ;
  317. : CELLS ( n -- n ) [ =CELL ] LITERAL * ;
  318. : BL ( -- 32 ) 32 ;
  319. : >CHAR ( c -- c )
  320. 127 AND DUP 127 BL WITHIN IF [ CHAR _ ] LITERAL NIP THEN ;
  321. : DEPTH ( -- n ) SP@ SP0 @ SWAP - 2 / ;
  322. : PICK ( +n -- w ) 1 + CELLS SP@ + @ ;
  323. : ALIGNED ( b -- a ) ; IMMEDIATE
  324. .( Memory access )
  325. : +! ( n a -- ) SWAP OVER @ + SWAP ! ;
  326. : 2! ( d a -- ) SWAP OVER ! CELL+ ! ;
  327. : 2@ ( a -- d ) DUP CELL+ @ SWAP @ ;
  328. : COUNT ( b -- b +n ) DUP 1 + SWAP C@ ;
  329. : HERE ( -- a ) CP @ ;
  330. : PAD ( -- a ) HERE 80 + ;
  331. : TIB ( -- a ) #TIB CELL+ @ ;
  332. : NP ( -- a ) CP CELL+ ;
  333. : LAST ( -- a ) NP CELL+ ;
  334. : @EXECUTE ( a -- ) @ ?DUP IF EXECUTE THEN ;
  335. : CMOVE ( b b u -- )
  336. FOR AFT >R COUNT R@ C! R> 1 + THEN NEXT 2DROP ;
  337. : -TRAILING ( b u -- b u )
  338. FOR AFT DUP R@ + C@ BL XOR
  339. IF R> 1 + EXIT THEN THEN
  340. NEXT 0 ;
  341. : FILL ( b u c -- )
  342. SWAP FOR SWAP AFT 2DUP C! 1 + THEN NEXT 2DROP ;
  343. : ERASE ( b u -- ) 0 FILL ;
  344. : PACK$ ( b u a -- a ) \ null terminated
  345. DUP >R 2DUP C! 1 + 2DUP + 0 SWAP ! SWAP CMOVE R> ;
  346. .( Numeric Output ) \ single precision
  347. : DIGIT ( u -- c ) 9 OVER < 7 AND + [ CHAR 0 ] LITERAL + ;
  348. : EXTRACT ( n base -- n c ) 0 SWAP UM/MOD SWAP DIGIT ;
  349. : <# ( -- ) PAD HLD ! ;
  350. : HOLD ( c -- ) HLD @ 1 - DUP HLD ! C! ;
  351. : # ( u -- u ) BASE @ EXTRACT HOLD ;
  352. : #S ( u -- 0 ) BEGIN # DUP WHILE REPEAT ;
  353. : SIGN ( n -- ) 0< IF [ CHAR - ] LITERAL HOLD THEN ;
  354. : #> ( w -- b u ) DROP HLD @ PAD OVER - ;
  355. : str ( w -- b u ) DUP >R ABS <# #S R> SIGN #> ;
  356. : HEX ( -- ) 16 BASE ! ;
  357. : DECIMAL ( -- ) 10 BASE ! ;
  358. .( Numeric Input ) \ single precision
  359. : DIGIT? ( c base -- u t )
  360. >R [ CHAR 0 ] LITERAL - 9 OVER <
  361. IF 7 - DUP 10 < OR THEN DUP R> U< ;
  362. : NUMBER? ( a -- n T, a F )
  363. BASE @ >R 0 OVER COUNT ( a 0 b n)
  364. OVER C@ [ CHAR $ ] LITERAL =
  365. IF HEX SWAP BYTE+ SWAP 1 - THEN ( a 0 b' n')
  366. OVER C@ [ CHAR - ] LITERAL = >R ( a 0 b n)
  367. SWAP R@ - SWAP R@ + ( a 0 b" n") ?DUP
  368. IF 1 - ( a 0 b n)
  369. FOR DUP >R C@ BASE @ DIGIT?
  370. WHILE SWAP BASE @ * + R> BYTE+
  371. NEXT R@ ( ?sign) NIP ( b) IF NEGATE THEN SWAP
  372. ELSE R> R> ( b index) 2DROP ( digit number) 2DROP 0
  373. THEN DUP
  374. THEN R> ( n ?sign) 2DROP R> BASE ! ;
  375. .( Basic I/O )
  376. : KEY? ( -- f ) '?KEY @EXECUTE ;
  377. : KEY ( -- c ) BEGIN '?KEY UNTIL ;
  378. : EMIT ( c -- ) 'EMIT @EXECUTE ;
  379. : NUF? ( -- f ) KEY? DUP IF KEY 2DROP KEY 13 = THEN ;
  380. : PACE ( -- ) 11 EMIT ;
  381. : SPACE ( -- ) BL EMIT ;
  382. : CHARS ( +n c -- ) SWAP 0 MAX FOR AFT DUP EMIT THEN NEXT DROP ;
  383. : SPACES ( +n -- ) BL CHARS ;
  384. : do$ ( -- a )
  385. R> R@ R> COUNT + ALIGNED >R SWAP >R ; COMPILE-ONLY
  386. : $"| ( -- a ) do$ ; COMPILE-ONLY
  387. : TYPE ( b u -- ) FOR AFT COUNT EMIT THEN NEXT DROP ;
  388. : .$ ( a -- ) COUNT TYPE ;
  389. : ."| ( -- ) do$ .$ ; COMPILE-ONLY
  390. : CR ( -- ) 13 EMIT 10 EMIT ;
  391. : .R ( n +n -- ) >R str R> OVER - SPACES TYPE ;
  392. : U.R ( u +n -- ) >R <# #S #> R> OVER - SPACES TYPE ;
  393. : U. ( u -- ) <# #S #> SPACE TYPE ;
  394. : . ( w -- ) BASE @ 10 XOR IF U. EXIT THEN str SPACE TYPE ;
  395. : ? ( a -- ) @ . ;
  396. .( Parsing )
  397. : parse ( b u c -- b u delta \ <string> )
  398. temp ! OVER >R DUP \ b u u
  399. IF 1 - temp @ BL =
  400. IF \ b u' \ 'skip'
  401. FOR COUNT temp @ SWAP - 0< INVERT WHILE
  402. NEXT ( b) R> DROP 0 DUP EXIT \ all delim
  403. THEN 1 - R>
  404. THEN OVER SWAP \ b' b' u' \ 'scan'
  405. FOR COUNT temp @ SWAP - temp @ BL =
  406. IF 0< THEN WHILE
  407. NEXT DUP >R ELSE R> DROP DUP >R 1 -
  408. THEN OVER - R> R> - EXIT
  409. THEN ( b u) OVER R> - ;
  410. : PARSE ( c -- b u \ <string> )
  411. >R TIB >IN @ + #TIB @ >IN @ - R> parse >IN +! ;
  412. : .( ( -- ) [ CHAR ) ] LITERAL PARSE TYPE ; IMMEDIATE
  413. : ( ( -- ) [ CHAR ) ] LITERAL PARSE 2DROP ; IMMEDIATE
  414. : \ ( -- ) #TIB @ >IN ! ; IMMEDIATE
  415. : CHAR ( -- c ) BL PARSE DROP C@ ;
  416. : CTRL ( -- c ) CHAR $001F AND ;
  417. : TOKEN ( -- a \ <string> )
  418. BL PARSE 31 MIN NP @ OVER - 2 - PACK$ ;
  419. : WORD ( c -- a \ <string> ) PARSE HERE PACK$ ;
  420. .( Dictionary Search )
  421. : NAME> ( na -- ca ) 2 CELLS - @ ;
  422. : SAME? ( a a u -- a a f \ -0+ )
  423. FOR AFT OVER R@ CELLS + @
  424. OVER R@ CELLS + @ - ?DUP
  425. IF R> DROP EXIT THEN THEN
  426. NEXT 0 ;
  427. : find ( a va -- ca na, a F )
  428. SWAP \ va a
  429. DUP C@ 2 / temp ! \ va a \ get cell count
  430. DUP @ >R \ va a \ count byte & 1st char
  431. CELL+ SWAP \ a' va
  432. BEGIN @ DUP \ a' na na
  433. IF DUP @ [ =MASK ] LITERAL AND R@ XOR \ ignore lexicon bits
  434. IF CELL+ -1 ELSE CELL+ temp @ SAME? THEN
  435. ELSE R> DROP EXIT
  436. THEN
  437. WHILE 2 CELLS - \ a' la
  438. REPEAT R> DROP NIP 1 CELLS - DUP NAME> SWAP ;
  439. : NAME? ( a -- ca na, a F )
  440. CONTEXT DUP 2@ XOR IF 1 CELLS - THEN >R \ context<>also
  441. BEGIN R> CELL+ DUP >R @ ?DUP
  442. WHILE find ?DUP
  443. UNTIL R> DROP EXIT THEN R> DROP 0 ;
  444. .( Terminal )
  445. : ^H ( b b b -- b b b ) \ backspace
  446. >R OVER R@ < DUP
  447. IF [ CTRL H ] LITERAL 'ECHO @EXECUTE THEN R> + ;
  448. : TAP ( bot eot cur key -- bot eot cur )
  449. DUP 'ECHO @EXECUTE OVER C! 1 + ;
  450. : kTAP ( bot eot cur key -- bot eot cur )
  451. DUP 13 XOR
  452. IF [ CTRL H ] LITERAL XOR IF BL TAP ELSE ^H THEN EXIT
  453. THEN DROP NIP DUP ;
  454. : accept ( b u -- b u )
  455. OVER + OVER
  456. BEGIN 2DUP XOR
  457. WHILE KEY DUP BL - 95 U<
  458. IF TAP ELSE 'TAP @EXECUTE THEN
  459. REPEAT DROP OVER - ;
  460. : EXPECT ( b u -- ) 'EXPECT @EXECUTE SPAN ! DROP ;
  461. : QUERY ( -- )
  462. TIB 80 'EXPECT @EXECUTE #TIB ! 0 NIP >IN ! ;
  463. .( Error handling )
  464. : CATCH ( ca -- err#/0 )
  465. SP@ >R HANDLER @ >R RP@ HANDLER !
  466. EXECUTE
  467. R> HANDLER ! R> DROP 0 ;
  468. : THROW ( err# -- err# )
  469. HANDLER @ RP! R> HANDLER ! R> SWAP >R SP! DROP R> ;
  470. CREATE NULL$ 0 ,
  471. : ABORT ( -- ) NULL$ THROW ;
  472. : abort" ( f -- ) IF do$ THROW THEN do$ DROP ; COMPILE-ONLY
  473. .( Interpret )
  474. : $INTERPRET ( a -- )
  475. NAME? ?DUP
  476. IF @ [ =COMP ] LITERAL AND
  477. ABORT" compile ONLY" EXECUTE EXIT
  478. THEN
  479. 'NUMBER @EXECUTE
  480. IF EXIT THEN THROW ;
  481. : [ ( -- ) [ ' $INTERPRET ] LITERAL 'EVAL ! ; IMMEDIATE
  482. : .OK ( -- ) [ ' $INTERPRET ] LITERAL 'EVAL @ = IF ." ok" THEN CR ;
  483. : ?STACK ( -- ) DEPTH 0< IF $" underflow" THROW THEN ;
  484. : EVAL ( -- )
  485. BEGIN TOKEN DUP C@
  486. WHILE 'EVAL @EXECUTE ?STACK
  487. REPEAT DROP 'PROMPT @EXECUTE ;
  488. .( Device I/O )
  489. CODE IO? ( -- f ) \ FFFF is an impossible character
  490. XOR BX, BX
  491. MOV DL, # $0FF \ input
  492. MOV AH, # 6 \ MS-DOS Direct Console I/O
  493. INT $021
  494. 0<> IF \ ?key ready
  495. OR AL, AL
  496. 0= IF \ ?extended ascii code
  497. INT $021
  498. MOV BH, AL \ extended code in msb
  499. ELSE MOV BL, AL
  500. THEN
  501. PUSH BX
  502. MOVE BX, # -1
  503. THEN
  504. PUSH BX
  505. NEXT
  506. END-CODE
  507. CODE TX! ( c -- )
  508. POP DX
  509. CMP DL, # $0FF
  510. 0= IF \ do NOT allow input
  511. MOV DL, # 32 \ change to blank
  512. THEN
  513. MOV AH, # 6 \ MS-DOS Direct Console I/O
  514. INT $021
  515. NEXT
  516. END-CODE
  517. : !IO ( -- ) ; IMMEDIATE \ initialize I/O device
  518. .( Shell )
  519. : PRESET ( -- ) SP0 @ SP! [ =TIB ] LITERAL #TIB CELL+ ! ;
  520. : XIO ( a a a -- ) \ reset 'EXPECT 'TAP 'ECHO 'PROMPT
  521. [ ' accept ] LITERAL 'EXPECT !
  522. 'TAP ! 'ECHO ! 'PROMPT ! ;
  523. : FILE ( -- )
  524. [ ' PACE ] LITERAL [ ' DROP ] LITERAL [ ' kTAP ] LITERAL XIO ;
  525. : HAND ( -- )
  526. [ ' .OK ] LITERAL 'EMIT @ [ ' kTAP ] LITERAL XIO ;
  527. CREATE I/O ' RX? , ' TX! , \ defaults
  528. : CONSOLE ( -- ) I/O 2@ 'KEY? 2! HAND ;
  529. : que ( -- ) QUERY EVAL ;
  530. : QUIT ( -- ) \ clear return stack ONLY
  531. RP0 @ RP!
  532. BEGIN [COMPILE] [
  533. BEGIN [ ' que ] LITERAL CATCH ?DUP
  534. UNTIL ( a)
  535. CONSOLE NULL$ OVER XOR
  536. IF CR TIB #TIB @ TYPE
  537. CR >IN @ [ CHAR ^ ] LITERAL CHARS
  538. CR .$ ." ? "
  539. THEN PRESET
  540. AGAIN ;
  541. .( Compiler Primitives )
  542. : ' ( -- ca ) TOKEN NAME? IF EXIT THEN THROW ;
  543. : ALLOT ( n -- ) CP +! ;
  544. : , ( w -- ) HERE ALIGNED DUP CELL+ CP ! ! ;
  545. : [COMPILE] ( -- \ <string> ) ' , ; IMMEDIATE
  546. : COMPILE ( -- ) R> DUP @ , CELL+ >R ; COMPILE-ONLY
  547. : LITERAL ( w -- ) COMPILE doLIT , ; IMMEDIATE
  548. : $," ( -- ) [ CHAR " ] LITERAL PARSE HERE PACK$ C@ 1 + ALLOT ;
  549. : RECURSE ( -- ) LAST @ CURRENT @ ! ; IMMEDIATE
  550. .( Structures )
  551. : FOR ( -- a ) COMPILE >R HERE ; IMMEDIATE
  552. : BEGIN ( -- a ) HERE ; IMMEDIATE
  553. : NEXT ( a -- ) COMPILE next , ; IMMEDIATE
  554. : UNTIL ( a -- ) COMPILE ?branch , ; IMMEDIATE
  555. : AGAIN ( a -- ) COMPILE branch , ; IMMEDIATE
  556. : IF ( -- A ) COMPILE ?branch HERE 0 , ; IMMEDIATE
  557. : AHEAD ( -- A ) COMPILE branch HERE 0 , ; IMMEDIATE
  558. : REPEAT ( A a -- ) [COMPILE] AGAIN HERE SWAP ! ; IMMEDIATE
  559. : THEN ( A -- ) HERE SWAP ! ; IMMEDIATE
  560. : AFT ( a -- a A ) DROP [COMPILE] AHEAD [COMPILE] BEGIN SWAP ; IMMEDIATE
  561. : ELSE ( A -- A ) [COMPILE] AHEAD SWAP [COMPILE] THEN ; IMMEDIATE
  562. : WHILE ( a -- A a ) [COMPILE] IF SWAP ; IMMEDIATE
  563. : ABORT" ( -- \ <string> ) COMPILE abort" $," ; IMMEDIATE
  564. : $" ( -- \ <string> ) COMPILE $"| $," ; IMMEDIATE
  565. : ." ( -- \ <string> ) COMPILE ."| $," ; IMMEDIATE
  566. .( Name Compiler )
  567. : ?UNIQUE ( a -- a )
  568. DUP NAME? IF ." reDef " OVER .$ THEN DROP ;
  569. : $,n ( na -- )
  570. DUP C@
  571. IF ?UNIQUE
  572. ( na) DUP LAST ! \ for OVERT
  573. ( na) HERE ALIGNED SWAP
  574. ( cp na) 1 CELLS -
  575. ( cp la) CURRENT @ @
  576. ( cp la na') OVER !
  577. ( cp la) 1 CELLS - DUP NP ! ( ptr) ! EXIT
  578. THEN $" name" THROW ;
  579. .( FORTH Compiler )
  580. : $COMPILE ( a -- )
  581. NAME? ?DUP
  582. IF C@ [ =IMED ] LITERAL AND
  583. IF EXECUTE ELSE , THEN EXIT
  584. THEN
  585. 'NUMBER @EXECUTE
  586. IF [COMPILE] LITERAL EXIT
  587. THEN THROW ;
  588. : OVERT ( -- ) LAST @ CURRENT @ ! ;
  589. : ; ( -- )
  590. COMPILE EXIT [COMPILE] [ OVERT ; COMPILE-ONLY IMMEDIATE
  591. : ] ( -- ) [ ' $COMPILE ] LITERAL 'EVAL ! ;
  592. : CALL, ( ca -- ) \ DTC 8086 relative call
  593. [ =CALL ] LITERAL , HERE CELL+ - , ;
  594. : : ( -- \ <string> ) TOKEN $,n [ ' doLIST ] LITERAL CALL, ] ;
  595. : IMMEDIATE ( -- ) [ =IMED ] LITERAL LAST @ C@ OR LAST @ C! ;
  596. .( Defining Words )
  597. : USER ( u -- \ <string> ) TOKEN $,n OVERT COMPILE doUSER , ;
  598. : CREATE ( -- \ <string> ) TOKEN $,n OVERT COMPILE doVAR ;
  599. : VARIABLE ( -- \ <string> ) CREATE 0 , ;
  600. .( Tools )
  601. : _TYPE ( b u -- ) FOR AFT COUNT >CHAR EMIT THEN NEXT DROP ;
  602. : dm+ ( b u -- b )
  603. OVER 4 U.R SPACE FOR AFT COUNT 3 U.R THEN NEXT ;
  604. : DUMP ( b u -- )
  605. BASE @ >R HEX 16 /
  606. FOR CR 16 2DUP dm+ -ROT 2 SPACES _TYPE NUF? 0= WHILE
  607. NEXT ELSE R> DROP THEN DROP R> BASE ! ;
  608. : .S ( -- ) CR DEPTH FOR AFT R@ PICK . THEN NEXT ." <tos" ;
  609. : !CSP ( -- ) SP@ CSP ! ;
  610. : ?CSP ( -- ) SP@ CSP @ XOR ABORT" stack depth" ;
  611. : >NAME ( ca -- na, F )
  612. CURRENT
  613. BEGIN CELL+ @ ?DUP WHILE 2DUP
  614. BEGIN @ DUP WHILE 2DUP NAME> XOR
  615. WHILE 1 CELLS -
  616. REPEAT THEN NIP ?DUP
  617. UNTIL NIP NIP EXIT THEN 0 NIP ;
  618. : .ID ( na -- )
  619. ?DUP IF COUNT $001F AND TYPE EXIT THEN ." {noName}" ;
  620. : WORDS ( -- )
  621. CR CONTEXT @
  622. BEGIN @ ?DUP
  623. WHILE DUP SPACE .ID 1 CELLS - NUF?
  624. UNTIL DROP THEN ;
  625. .( Hardware reset )
  626. \ version
  627. $100 CONSTANT VER ( -- u )
  628. \ hi byte = major revision in decimal
  629. \ lo byte = minor revision in decimal
  630. : hi ( -- )
  631. !IO \ initialize IO device & sign on
  632. CR ." eForth v1.0"
  633. ; COMPILE-ONLY
  634. CREATE 'BOOT ' hi , \ application vector
  635. : COLD ( -- )
  636. \ init CPU
  637. \ init stacks
  638. \ init user area
  639. \ init IP
  640. PRESET 'BOOT @EXECUTE
  641. QUIT ;