home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PROGRAMS / UTILS / LASER / FPC35_5.ZIP / FPCSRC.ZIP / KERNEL2.SEQ < prev    next >
Encoding:
Text File  |  1989-07-06  |  41.5 KB  |  1,124 lines

  1. \ KERNEL2.SEQ   More kernel stuff
  2.  
  3. FILES DEFINITIONS
  4.  
  5. VARIABLE KERNEL2.SEQ
  6.  
  7. FORTH DEFINITIONS
  8.  
  9. USER DEFINITIONS
  10. VARIABLE  TOS         ( top of stack )
  11. VARIABLE  ENTRY       ( entry point, contains machine code )
  12. VARIABLE  LINK        ( link to next task )
  13. VARIABLE  ES0         ( initial ES: segment )
  14. VARIABLE  SP0         ( initial parameter stack )
  15. VARIABLE  RP0         ( initial return stack )
  16. VARIABLE  DP          ( dictionary pointer )
  17. VARIABLE  OFFSET      ( relative to absolute disk block 0 )
  18. VARIABLE  BASE        ( for numeric input and output )
  19. VARIABLE  HLD         ( points to last character held in pad )
  20. VARIABLE  PRINTING    ( indicates if printing is enabled )
  21.  
  22.    DEFER  EMIT        ( send a character to ouput device )
  23.    DEFER  KEY?        ( test if a character is ready to be received )
  24.    DEFER  KEY         ( get the next character from the keyboard )
  25.    DEFER  TYPE        ( send a string of characters to the console )
  26.    DEFER  TYPEL       ( send a string from extended memory to console )
  27.  
  28. META DEFINITIONS
  29. VARIABLE  PRIOR       ( used for dictionary searches )
  30. VARIABLE  STATE       ( compilation or interpretation )
  31. VARIABLE  WARNING     ( give user duplicate warnings if on )
  32. VARIABLE  DPL         ( numeric input punctuation )
  33. VARIABLE  R#          ( editing cursor position )
  34. VARIABLE  LAST        ( points to nfa of latest definition )
  35. VARIABLE  CSP         ( holds stack pointer for error checking )
  36. VARIABLE  CURRENT     ( vocabulary which gets definitions )
  37. 12 CONSTANT #VOCS     ( the number of vocabularies to search )
  38. VARIABLE  CONTEXT     ( vocabulary searched first )
  39. HERE THERE #VOCS 2* DUP ALLOT CS:ERASE
  40.  
  41. VARIABLE  'TIB        ( address of terminal input buffer )
  42. VARIABLE  WIDTH       ( width of name field )
  43. VARIABLE  VOC-LINK    ( points to newest vocabulary )
  44. VARIABLE  >IN         ( offset into input stream )
  45. VARIABLE  SPAN        ( number of characters expected )
  46. VARIABLE  #TIB        ( number of characters to interpret )
  47. VARIABLE  END?        ( true if input stream exhausted )
  48. VARIABLE  #OUT        ( number of characters emitted )
  49. VARIABLE  #LINE       ( the number of lines sent so far )
  50.  
  51. VARIABLE XDP          ( offset to next available location in list space )
  52. VARIABLE XDPSEG       ( segment to next available location in list space )
  53. VARIABLE YDP          ( offset to next available location in head space )
  54. VARIABLE YSTART       ( offset to beginning of head space in .COM file )
  55. VARIABLE DPSTART      ( beginning of list space in .COM or .EXE file )
  56. VARIABLE XSEGLEN      ( length of list space in segments )
  57. VARIABLE XMOVED       ( flag to tell if list has been moved )
  58. VARIABLE SSEG         ( search & scan segment )
  59.  
  60. 0  VALUE SEQHANDLE    ( the sequential handle pointer )
  61. VARIABLE LOADLINE     ( line # last read by LINEREAD )
  62.  
  63. 32 CONSTANT BL        \ ASCII space
  64.  8 CONSTANT BS        \ ASCII backspace
  65.  7 CONSTANT BELL      \ ASCII bell
  66.  
  67. VARIABLE CAPS         \ Flag: if true, convert names to upper case.
  68.  
  69. CODE FILL       (  start-addr count char -- )
  70. \ Fill each byte of memory in the specified address range with "char".
  71.                 CLD             MOV BX, DS
  72.                 POP AX          POP CX          POP DI
  73.                 PUSH ES         MOV ES, BX
  74.                 REPNZ           STOSB           POP ES
  75.                 NEXT            END-CODE
  76.  
  77. CODE LFILL      (  seg start-addr count char -- )
  78. \ Fill each byte of memory in the specified address range with "char".
  79.                 CLD             POP AX          POP CX
  80.                 POP DI          POP BX
  81.                 PUSH ES         MOV ES, BX
  82.                 REPNZ           STOSB           POP ES
  83.                 NEXT            END-CODE
  84.  
  85. : ERASE         ( addr len -- )   \ Put zeros in the area at addr.
  86.                 0 FILL   ;
  87. : BLANK         ( addr len -- )   \ Put ASCII spaces in the area at addr.
  88.                 BL FILL   ;
  89.  
  90. CODE COUNT      ( addr -- addr+1 len )
  91. \ Convert from the address of a counted string to an address and count.
  92.                 POP BX          SUB AX, AX      MOV AL, 0 [BX]
  93.                 INC BX          PUSH BX
  94.                 1PUSH           END-CODE
  95.  
  96. CODE LENGTH     ( addr -- addr+2 len )  \ really word count
  97. \ Similiar to COUNT , except that the count is in a word, not a byte.
  98.                 POP BX          MOV AX, 0 [BX]
  99.                 ADD BX, # 2
  100.                 PUSH BX
  101.                 1PUSH           END-CODE
  102.  
  103.                                         \ 07/03/89 RB
  104. CODE COUNTL     ( seg addr -- seg addr+1 len )
  105. \ Like COUNT, but works with a LONG (seg/offset) address.
  106.                 POP BX          POP DS
  107.                 XOR AX, AX      MOV AL, 0 [BX]
  108.                 INC BX
  109.                 PUSH DS         PUSH BX
  110.                 MOV DX, CS      MOV DS, DX
  111.                 1PUSH           END-CODE
  112.  
  113. : MOVE          ( from to len -- )
  114. \ Move "len" bytes from "from" address to "to" address, non-destructively.
  115.                 -ROT   2DUP U< IF   ROT CMOVE>   ELSE   ROT CMOVE   THEN ;
  116.  
  117. DECIMAL
  118.  
  119. CREATE ATBL     \ Uppercase translation table
  120.  0  C,   1  C,   2  C,   3  C,   4  C,   5  C,   6  C,   7  C,
  121.  8  C,  32  C,  10  C,  11  C,  12  C,  13  C,  14  C,  15  C,
  122. 16  C,  17  C,  18  C,  19  C,  20  C,  21  C,  22  C,  23  C,
  123. 24  C,  25  C,  26  C,  27  C,  28  C,  29  C,  30  C,  31  C,
  124. 32  C,  '!' C,  '"' C,  '#' C,  '$' C,  '%' C,  '&' C,  ''' C,
  125. '(' C,  ')' C,  '*' C,  '+' C,  ',' C,  '-' C,  '.' C,  '/' C,
  126. '0' C,  '1' C,  '2' C,  '3' C,  '4' C,  '5' C,  '6' C,  '7' C,
  127. '8' C,  '9' C,  ':' C,  ';' C,  '<' C,  '=' C,  '>' C,  '?' C,
  128. '@' C,  'A' C,  'B' C,  'C' C,  'D' C,  'E' C,  'F' C,  'G' C,
  129. 'H' C,  'I' C,  'J' C,  'K' C,  'L' C,  'M' C,  'N' C,  'O' C,
  130. 'P' C,  'Q' C,  'R' C,  'S' C,  'T' C,  'U' C,  'V' C,  'W' C,
  131. 'X' C,  'Y' C,  'Z' C,  '[' C,  '\' C,  ']' C,  '^' C,  '_' C,
  132. '`' C,  'A' C,  'B' C,  'C' C,  'D' C,  'E' C,  'F' C,  'G' C,
  133. 'H' C,  'I' C,  'J' C,  'K' C,  'L' C,  'M' C,  'N' C,  'O' C,
  134. 'P' C,  'Q' C,  'R' C,  'S' C,  'T' C,  'U' C,  'V' C,  'W' C,
  135. 'X' C,  'Y' C,  'Z' C,  '{' C,  '|' C,  '}' C,  '~' C,  127 C,
  136. \ Characters above 127 are translated to below 127
  137.  0  C,   1  C,   2  C,   3  C,   4  C,   5  C,   6  C,   7  C,
  138.  8  C,   9  C,  10  C,  11  C,  12  C,  13  C,  14  C,  15  C,
  139. 16  C,  17  C,  18  C,  19  C,  20  C,  21  C,  22  C,  23  C,
  140. 24  C,  25  C,  26  C,  27  C,  28  C,  29  C,  30  C,  31  C,
  141. 32  C,  '!' C,  '"' C,  '#' C,  '$' C,  '%' C,  '&' C,  ''' C,
  142. '(' C,  ')' C,  '*' C,  '+' C,  ',' C,  '-' C,  '.' C,  '/' C,
  143. '0' C,  '1' C,  '2' C,  '3' C,  '4' C,  '5' C,  '6' C,  '7' C,
  144. '8' C,  '9' C,  ':' C,  ';' C,  '<' C,  '=' C,  '>' C,  '?' C,
  145. '@' C,  'A' C,  'B' C,  'C' C,  'D' C,  'E' C,  'F' C,  'G' C,
  146. 'H' C,  'I' C,  'J' C,  'K' C,  'L' C,  'M' C,  'N' C,  'O' C,
  147. 'P' C,  'Q' C,  'R' C,  'S' C,  'T' C,  'U' C,  'V' C,  'W' C,
  148. 'X' C,  'Y' C,  'Z' C,  '[' C,  '\' C,  ']' C,  '^' C,  '_' C,
  149. '`' C,  'A' C,  'B' C,  'C' C,  'D' C,  'E' C,  'F' C,  'G' C,
  150. 'H' C,  'I' C,  'J' C,  'K' C,  'L' C,  'M' C,  'N' C,  'O' C,
  151. 'P' C,  'Q' C,  'R' C,  'S' C,  'T' C,  'U' C,  'V' C,  'W' C,
  152. 'X' C,  'Y' C,  'Z' C,  '{' C,  '|' C,  '}' C,  '~' C,  127 C,
  153.  
  154. CODE UPC        ( char -- char' )
  155. \ Convert a character to upper case.
  156.                 POP AX
  157.                 MOV BX, # ATBL
  158.                 XLAT
  159.                 1PUSH
  160.                 END-CODE
  161.  
  162. CODE UPPER      ( addr len -- )         
  163. \ Convert a string to upper case.
  164.                 POP CX                  \ get length
  165.                 POP DI                  \ and starting address
  166.                 PUSH SI                 \ save IP
  167.                 MOV DX, ES              \ and LIST POINTER
  168.                 MOV BX, DS
  169.                 MOV ES, BX              \ set ES to DS
  170.                 MOV SI, DI              \ set SI to DI
  171.                 MOV BX, # ATBL          \ loadup BX with table
  172.                 CLD                     \ clear direction flag
  173.           CX<>0 IF
  174.                         HERE                    \ get a char and traslate it
  175.                                 LODSB   XLAT
  176.                                 STOSB
  177.                         LOOPNZ                  \ until all chars are done
  178.                 THEN
  179.                 MOV ES, DX              \ restore ES=LIST
  180.                 POP SI                  \     and SI=IP
  181.                 NEXT    END-CODE
  182.  
  183. CODE ?UPPERCASE ( a1 -- a1 )           
  184. \ Conditionally convert a counted string to upper case
  185.                 MOV CX, CAPS            \ test CAPS variable
  186.   CX<>0 IF                              \ leave if CAPS is not on
  187.                 POP DI
  188.                 PUSH DI                 \ get a copy of address a1
  189.                 SUB CX, CX
  190.                 MOV CL, 0 [DI]
  191.                 INC DI                  \ Addr and Cnt in DI & CX
  192.                 PUSH SI                 \ save IP
  193.                 MOV DX, ES              \ and LIST POINTER
  194.                 MOV BX, DS
  195.                 MOV ES, BX              \ set ES to DS
  196.                 MOV SI, DI              \ set SI to DI
  197.                 MOV BX, # ATBL          \ loadup BX with table
  198.                 CLD                     \ clear direction flag
  199.           CX<>0 IF
  200.                         HERE                    \ get a char and traslate it
  201.                                 LODSB   XLAT
  202.                                 STOSB
  203.                         LOOPNZ                  \ until all chars are done
  204.                 THEN
  205.                 MOV ES, DX              \ restore ES=LIST
  206.                 POP SI                  \     and SI=IP
  207.                 NEXT
  208.         THEN
  209.                 NEXT
  210.                 END-CODE
  211.  
  212. CODE HERE       ( -- adr )
  213. \ Return the address of the top of the dictionary.
  214.                 MOV BX, UP
  215.                 PUSH DP [BX]
  216.                 NEXT
  217.                 END-CODE
  218.  
  219. CODE PAD        ( -- adr )
  220. \ Return the address of a floating temporary storage area.
  221.                 MOV BX, UP
  222.                 MOV AX, DP [BX]
  223.                 ADD AX, # 80
  224.                 1PUSH           END-CODE
  225.  
  226. CODE -TRAILING  ( addr len -- addr len1 )
  227. \ The length of string is conditionally reduced by the number of trailing
  228. \ blanks.
  229.                 POP CX
  230.                 POP DI          PUSH DI
  231.           CX<>0 IF      MOV AX, DS
  232.                         PUSH ES
  233.                         STD
  234.                         MOV ES, AX
  235.                         ADD DI, CX
  236.                         DEC DI
  237.                         MOV AL, # $20
  238.                         REPE SCASB
  239.                     0<> IF      INC CX
  240.                         THEN
  241.                         CLD
  242.                         POP ES
  243.                 THEN
  244.                 PUSH CX
  245.                 NEXT            END-CODE
  246.  
  247. CODE COMP       ( addr1 addr2 len -- -1 | 0 | 1 )
  248. \ Compare two strings.  If equal, return 0.  If str1 < str2, return -1.
  249. \ If str1 > str2, return 1 .
  250.                 MOV DX, SI      POP CX
  251.                 POP DI          POP SI
  252.           CX<>0 IF      PUSH ES
  253.                         MOV ES, SSEG
  254.                         REPZ CMPSB
  255.                     0<> IF
  256.                              0< IF      MOV CX, # -1
  257.                                 ELSE    MOV CX, # 1
  258.                                 THEN
  259.                         THEN
  260.                         POP ES
  261.                 THEN
  262.                 MOV SI, DX
  263.                 PUSH CX
  264.                 NEXT            END-CODE
  265.  
  266. CODE CAPS-COMP  ( addr1 addr2 len -- -1 | 0 | 1 )
  267. \ Perform a comparison of two strings, but ignore Case differences.
  268.                 MOV DX, SI      POP CX
  269.                 POP DI          POP SI
  270.                 PUSH ES         MOV ES, SSEG
  271.                 BEGIN
  272.                     JCXZ  0 $
  273.                     MOV     AH, 0 [SI]      INC SI
  274.                     MOV ES: AL, 0 [DI]      INC DI
  275.                     OR AX, # $02020         CMP AH, AL
  276.                     JNE 1 $                 DEC CX
  277.                 AGAIN
  278.         1 $: 0< IF
  279.                    MOV CX, # -1
  280.                 ELSE
  281.                    MOV CX, # 1
  282.                 THEN
  283.         0 $:    MOV SI, DX
  284.                 POP ES
  285.                 PUSH CX
  286.                 NEXT            END-CODE
  287.  
  288. : COMPARE       ( addr1 addr2 len -- -1 | 0 | 1 )
  289. \ Compare two strings.  If CAPS is true, ignore case.
  290.                 CAPS @ IF   CAPS-COMP   ELSE   COMP   THEN   ;
  291.  
  292. CODE ?CS:       ( -- cs )
  293. \ Return the code segment CS
  294.                 PUSH CS         NEXT            END-CODE
  295.  
  296. CODE ?ES:       ( -- es )
  297. \ Return the extra segment ES
  298.                 PUSH ES         NEXT            END-CODE
  299.  
  300. CODE @L         ( seg addr -- word )
  301. \ Load a 16 bit word from the specified segment and offset.
  302.                 POP BX          POP DS          MOV AX, 0 [BX]
  303.                 MOV BX, CS      MOV DS, BX
  304.                 1PUSH           END-CODE
  305.  
  306. CODE C@L        ( seg addr -- byte )
  307. \ Load an 8 bit byte from the specified segment and offset.
  308.                 POP BX          POP DS          MOV AL, 0 [BX]
  309.                 XOR AH, AH      MOV BX, CS      MOV DS, BX
  310.                 1PUSH           END-CODE
  311.  
  312. CODE C!L        ( byte seg adr )
  313. \ Store the byte at the specified segment and offset.
  314.                 POP BX          POP DS          POP AX
  315.                 MOV 0 [BX], AL  MOV BX, CS      MOV DS, BX
  316.                 NEXT            END-CODE
  317.  
  318. CODE !L         ( n seg adr -- )
  319. \ Store the 16 bit word n at the specified segment and offset.
  320.                 POP BX          POP DS          POP AX
  321.                 MOV 0 [BX], AX  MOV BX, CS      MOV DS, BX
  322.                 NEXT            END-CODE
  323.  
  324. CODE <BDOS>     ( n fun -- m )
  325. \ Perform a simple DOS call.  fun is the function number, and n
  326. \ is the value of the DX register.  The result code is pushed as m .
  327.                 POP AX          MOV AH, AL      POP DX
  328.                 INT $21         SUB AH, AH
  329.                 1PUSH           END-CODE
  330.  
  331. DEFER BDOS      ' <BDOS> IS BDOS
  332. \ A defered DOS call.
  333.  
  334. CODE BDOS2      ( CX DX AX -- CX DX AX )
  335. \ Similiar to BDOS, except that an additional register, CX , is used.
  336.                 POP AX          POP DX          POP CX
  337.                 MOV AH, AL      INT $21
  338.                 PUSH CX         PUSH DX         PUSH AX
  339.                 NEXT            END-CODE
  340.  
  341. : OS2           BDOS2 255 AND ;
  342.  
  343. VARIABLE BIOSCHAR       \ Holds the char from BIOS on scan by BIOSKEY?
  344. VARIABLE BIOSKEYVAL     \ Holds the key value from BIOSKEY
  345.  
  346. CODE BIOSKEY?   ( -- f1 )
  347. \ Return a true flag if a key, other than control break, has been pressed.
  348.         BEGIN
  349.                 MOV AH, # 1
  350.                 PUSH SI         PUSH BP
  351.                 INT $16
  352.                 POP BP          POP SI
  353.                 MOV BIOSCHAR AX
  354.           0= IF
  355.                 MOV AX, # 0
  356.                 1PUSH
  357.              THEN
  358.                 CMP AX, # 0     \ Ignore Control Break keys
  359.      0= WHILE
  360.                 MOV AH, # 0     \ That is, throw them away
  361.                 PUSH SI         PUSH BP
  362.                 INT $16
  363.                 POP BP          POP SI
  364.         REPEAT
  365.                 MOV AX, # -1
  366.                 1PUSH           END-CODE
  367.  
  368. CODE BIOSKEY    ( -- c1 )
  369. \ Return the value of the next key, other than control break.
  370.         BEGIN
  371.                 MOV AH, # 0
  372.                 PUSH SI         PUSH BP
  373.                 INT $16
  374.                 POP BP          POP SI
  375.                 CMP AX, # 0             \ Ignore Control BREAK, 00 Hex.
  376.     0<> UNTIL
  377.                 MOV BIOSKEYVAL AX
  378.                 1PUSH           END-CODE
  379.  
  380. DEFER KEYFILTER ' NOOP IS KEYFILTER     \ Pre-filter keys before passing on.
  381.  
  382. DEFER BGSTUFF   ' NOOP IS BGSTUFF       \ BACKGROUND STUFF
  383.  
  384. : (KEY?)        ( -- f )
  385. \ Returns TRUE if user depressed a key.  Otherwise, FALSE.
  386.                 BGSTUFF BIOSKEY? ;
  387.  
  388. : (KEY)         ( -- char )
  389. \ Wait until the user presses a key, then return its value.
  390.                 BEGIN   PAUSE KEY? UNTIL
  391.                 BIOSKEY DUP 127 AND 0=
  392.                 IF      FLIP DUP 3 =
  393.                         IF      DROP 0          \ allow a NULL
  394.                         ELSE    127 AND 128 OR
  395.                         THEN
  396.                 ELSE    255 AND
  397.                 THEN    KEYFILTER ;
  398.  
  399. DEFER OUTPAUSE  ( ' PAUSE ) ' NOOP IS OUTPAUSE
  400. \ A defered word for background tasks while sending characters to screen.
  401.  
  402. DEFER CONSOLE
  403. \ A defered word for sending characters to the screen.
  404.  
  405. CODE CMOVEL     ( sseg sptr dseg dptr cnt )
  406. \ Move "cnt" characters from source segment and offset to destination
  407. \ segment and offset.
  408.                 CLD             MOV BX, SI
  409.                 POP CX          POP DI
  410.                 POP AX          POP SI
  411.                 POP DS          PUSH ES         MOV ES, AX
  412.                 OR CX, CX
  413.             0<> IF
  414.                 REPNZ           MOVSB
  415.             THEN
  416.                 POP ES
  417.                 MOV AX, CS      MOV DS, AX
  418.                 MOV SI, BX
  419.                 NEXT            END-CODE
  420.  
  421. CODE CMOVEL>    ( sseg sptr dseg dptr cnt )
  422. \ Similiar to CMOVEL , except move is in the "reverse" direction,
  423. \ i.e., from high memory to low memory.
  424.                 STD             MOV BX, SI
  425.                 POP CX          POP DI
  426.                 POP AX          POP SI
  427.                 POP DS          PUSH ES         MOV ES, AX
  428.                 OR CX, CX
  429.             0<> IF
  430.                 DEC CX          ADD DI, CX
  431.                 ADD SI, CX      INC CX
  432.                 REPNZ           MOVSB
  433.             THEN
  434.                 POP ES
  435.                 MOV AX, CS      MOV DS, AX
  436.                 MOV SI, BX
  437.                 CLD
  438.                 NEXT            END-CODE
  439.  
  440. $01000 VALUE #CODESEGS \ Number of segments needed for CODE.  64k
  441. $01800 VALUE #LISTSEGS \ Number of segments needed for : definitions. 64k
  442. $01000 VALUE #HEADSEGS \ Number of segments needed for HEADS. 64K
  443.  
  444. : MEMCHK        ( f1 -- )
  445. \ If flag is true, Terminate execution and return to DOS with error message.
  446.                 IF      ." Insufficient Memory"
  447.                         0 0 BDOS
  448.                 THEN ;
  449.  
  450. CODE DEALLOC    ( n1 -- f1 ) 
  451. \ n1 = block to de-allocate, f1 = 0 is ok.
  452. \ f1 = 9 means invalid block address.
  453.                 MOV AH, # $49 
  454.                 POP DX
  455.                 PUSH ES         MOV ES, DX      INT $21
  456.              U< IF
  457.                 SUB AH, AH
  458.              ELSE
  459.                 MOV AX, # 0
  460.              THEN
  461.                 POP ES          1PUSH           END-CODE
  462.  
  463. CODE ALLOC      ( n1 -- n2 n3 f1 )      
  464. \ n1 = size needed, n3 = segment
  465. \ n2 = largest segment available
  466. \ f1 =  8 not enough memory.
  467.                 MOV AH, # $48            
  468.                 POP BX
  469.                 INT $21
  470.                 PUSH BX         PUSH AX
  471.              U< IF
  472.                 SUB AH, AH
  473.              ELSE
  474.                 MOV AX, # 0
  475.              THEN
  476.                 1PUSH           END-CODE
  477.  
  478. CODE SETBLOCK   ( seg siz -- f1 )
  479. \ Re-adjust the memory block specified by "seg" to the new size "siz"
  480. \ in segments.
  481.                 POP BX                  \ get new size
  482.                 MOV AH, # $4A           \ setblock call
  483.                 POP DX
  484.                 PUSH ES
  485.                 MOV ES, DX
  486.                 INT $21
  487.              U< IF      SUB AH, AH
  488.                 ELSE    MOV AX, # 0
  489.                 THEN
  490.                 POP ES
  491.                 1PUSH           END-CODE
  492.  
  493. : DOSVER        ( -- n1 )
  494. \ Get the DOS version number.
  495.                 0 $030 BDOS $0FF AND ;
  496.  
  497. DEFER CURSORSET ' NOOP IS CURSORSET
  498.  
  499.                                         \ 07/03/89 RB
  500. CODE +XSEG      ( n1 -- n2 )            \ Add XSEG to n1, returning n2.
  501.                 POP AX
  502.                 ADD AX, XSEG
  503.                 1PUSH           END-CODE
  504.  
  505. : SETYSEG       ( -- )
  506. \ Sets head segment + more space
  507.                 [ LABEL 'SETYSEG ]
  508.                 ?CS: SSEG !
  509.                 XSEGLEN @ +XSEG XDPSEG !
  510.                 XDP OFF
  511.                 DPSTART @ DP !
  512.                 DOSVER 2 <
  513.                 IF      ." Must have DOS 2.x or higher."
  514.                         0 0 BDOS
  515.                 THEN
  516.                 ?CS: #CODESEGS #LISTSEGS + #HEADSEGS + SETBLOCK MEMCHK
  517.                 #OUT 0! $018 ( 24 DECIMAL ) #LINE !
  518.                 CURSORSET ;
  519.  
  520. CODE YHERE      ( -- adr )
  521. \ The next available location in "Head" space.
  522.                 PUSH YDP        NEXT
  523.                 END-CODE
  524.  
  525. CODE YS:        ( w -- yseg w )
  526. \ Insert the base of the head segment under the offset at the top.
  527.                 POP AX          PUSH YSEG
  528.                 1PUSH           END-CODE
  529.  
  530. CODE Y@         ( addr -- n )
  531. \ Fetch the word at the specified offset in the head segment.
  532.                 POP BX
  533.                 MOV DS, YSEG
  534.                 PUSH 0 [BX]
  535.                 MOV BX, CS      MOV DS, BX
  536.                 NEXT            END-CODE
  537.  
  538. CODE Y!         ( n addr -- )
  539. \ Store word n at the offset in the head segment.
  540.                 POP BX
  541.                 MOV DS, YSEG
  542.                 POP 0 [BX]
  543.                 MOV BX, CS      MOV DS, BX
  544.                 NEXT            END-CODE
  545.  
  546. CODE YC@        ( addr -- char )
  547. \ Fetch the byte at the offset in the head segment.
  548.                 POP BX          SUB AX, AX
  549.                 MOV DS, YSEG
  550.                 MOV AL, 0 [BX]
  551.                 MOV BX, CS      MOV DS, BX
  552.                 1PUSH           END-CODE
  553.  
  554. CODE YC!        ( char addr -- )
  555. \ Store the byte at the specified offset in the head segment.
  556.                 POP BX          POP AX
  557.                 MOV DS, YSEG
  558.                 MOV 0 [BX], AL
  559.                 MOV BX, CS      MOV DS, BX
  560.                 NEXT            END-CODE
  561.  
  562. CODE Y,         ( n -- )
  563. \ Add the 16 bit value  n  to the end of the working head space.
  564.                 MOV BX, YDP
  565.                 ADD YDP # 2 WORD
  566.                 POP CX
  567.                 MOV DS, YSEG
  568.                 MOV 0 [BX], CX
  569.                 MOV BX, CS      MOV DS, BX
  570.                 NEXT
  571.                 END-CODE
  572.  
  573. CODE YCSET      ( byte addr -- )
  574. \ Set the bits at offset in the head segment according to "b".
  575.                 POP BX          POP AX
  576.                 MOV DS, YSEG
  577.                 OR 0 [BX], AL
  578.                 MOV BX, CS      MOV DS, BX
  579.                 NEXT            END-CODE
  580.  
  581. CODE YHASH      ( ystr vocaddr -- thread )
  582. \ Find the vocabulary thread corresponding to a counted string in head 
  583. \ space.
  584.                 POP DX          POP BX
  585.                 MOV DS, YSEG
  586.                 MOV AX, 1 [BX]          \ Get first and second chars
  587.                 SHL AL, # 1             \ Shift first char left one
  588.                 MOV CL, 0 [BX]          \ Get count
  589.                 AND CX, # 31            \ mask out all but actual word length
  590.                 DEC CX                  \ dec, and if zero then use a blank.
  591.     CX<>0  IF   ADD AL, AH
  592.            ELSE MOV AH, # 32
  593.                 ADD AL, AH              \ Plus second char
  594.            THEN SHL AX, # 1             \ The sum shifted left one again
  595.                 ADD AL, 0 [BX]          \ Plus count byte
  596.                 AND AX, # #THREADS 1-
  597.                 SHL AX, # 1     ADD AX, DX
  598.                 MOV CX, CS      MOV DS, CX
  599.                 1PUSH           END-CODE
  600.  
  601. CODE XHERE      ( -- seg adr )
  602. \ Returns segment an offset of next available byte in list space.
  603.                 PUSH XDPSEG     PUSH XDP
  604.                 NEXT            END-CODE
  605.  
  606. CODE X,         ( n -- )        \ XHERE !L  2 XDP +!
  607. \ Adds a 16 bit value to the end of list space.
  608.                 POP AX
  609.                 MOV BX, XDP
  610.                 MOV DS, XDPSEG
  611.                 MOV 0 [BX], AX
  612.                 MOV BX, CS
  613.                 MOV DS, BX
  614.                 ADD XDP # 2 WORD
  615.                 NEXT            END-CODE
  616.  
  617. CODE XC,        ( n -- )        \ XHERE C!L 1 XDP +!
  618. \ Adds an 8 bit value to the end of list space.
  619.                 POP AX
  620.                 MOV BX, XDP
  621.                 MOV DS, XDPSEG
  622.                 MOV 0 [BX], AL
  623.                 MOV BX, CS
  624.                 MOV DS, BX
  625.                 INC XDP WORD
  626.                 NEXT            END-CODE
  627.  
  628. CODE PR-STATUS  ( n1 -- b1 )
  629. \ n1 is the printer number.  Return the printer status byte.
  630.                 POP DX          \ PRINTER NUMBER
  631.                 MOV AH, # 2
  632.                 PUSH SI         PUSH BP
  633.                 INT $17
  634.                 POP BP          POP SI
  635.                 MOV AL, AH
  636.                 MOV AH, # 0
  637.                 1PUSH           END-CODE
  638.  
  639. : <?PTR.READY> ( -- f1 )
  640. \ $090 is printer not busy & printer selected.
  641.                 0 PR-STATUS ( $090 AND ) $090 = ;
  642.  
  643. DEFER ?PRINTER.READY    ' <?PTR.READY> IS ?PRINTER.READY
  644. \ A defered word.  Returns  TRUE  if printer is ready.
  645.  
  646. DEFER CR
  647. \ Send a carraige-return and line-feed to the console.
  648.  
  649. DEFER PEMIT     \ ' (PRINT) IS PEMIT
  650. \ A version of  EMIT  that sends a character to the printer.
  651.  
  652. : (EMIT)        ( char -- )
  653. \ Send a character to the console, and optionally to the printer.
  654.                 PRINTING @
  655.                 IF      PEMIT
  656.                 ELSE    CONSOLE
  657.                 THEN    ;
  658.  
  659. : CRLF          ( -- )
  660. \ Sends a carriage return line feed sequence.
  661.                 13 EMIT 10 EMIT #OUT OFF
  662.                 #LINE DUP @ 1+
  663.                 PRINTING @ 0=
  664.                 IF      ROWS 1- MIN  THEN SWAP ! ;
  665.  
  666. : FEMIT         ( c1 -- )
  667. \ A fast version of EMIT.  Control characters show graphic equivalence.
  668.                 SP@ 1 TYPE DROP ;
  669.  
  670. CREATE SPCS     ( -- a1 )      \ An array of 80 spaces for use by SPACES
  671.                 $02020
  672.                 DUP , DUP , DUP , DUP , DUP , DUP , DUP , DUP ,
  673.                 DUP , DUP , DUP , DUP , DUP , DUP , DUP , DUP ,
  674.                 DUP , DUP , DUP , DUP , DUP , DUP , DUP , DUP ,
  675.                 DUP , DUP , DUP , DUP , DUP , DUP , DUP , DUP ,
  676.                 DUP , DUP , DUP , DUP , DUP , DUP , DUP ,     ,
  677.  
  678. : SPACE         ( -- )    \ Display a space on the terminal.
  679.                 SPCS 1 TYPE ;
  680.  
  681. : SPACES        ( n -- )
  682. \ Send a sequence of  n  spaces to the console.
  683.                 0MAX    DUP 80 <
  684.                 IF      SPCS SWAP TYPE
  685.                 ELSE    80 /MOD 0
  686.                         ?DO     SPCS   80 TYPE
  687.                         LOOP    SPCS SWAP TYPE
  688.                 THEN    ;
  689.  
  690. : BACKSPACES    ( n -- )
  691. \ Send a sequence of  n  backspaces to the console.
  692.                 0 ?DO   BS EMIT -2 #OUT +! LOOP  ;
  693.  
  694. : %BEEP         ( -- )
  695.                 BELL (EMIT) #OUT DECR ;
  696.  
  697. DEFER BEEP      ( -- )          ' %BEEP IS BEEP
  698. \ Ring the bell on the terminal
  699.  
  700.  
  701. : BS-IN         ( n c -- 0 | n-1 )
  702. \ If at beginning of line, beep, otherwise back up 1.
  703.                 >R DUP
  704.                 IF      1-   BS EMIT
  705.                         #OUT @ 2- 0MAX #OUT !
  706.                 ELSE    BEEP
  707.                 THEN    R> ;
  708.  
  709. : (DEL-IN)      ( n c -- 0 | n-1 )
  710. \ If at beginning of line, beep, otherwise back up and erase 1.
  711.                 >R DUP
  712.                 IF      1- BS EMIT SPACE BS EMIT
  713.                         #OUT @ 4 - 0MAX #OUT !
  714.                 ELSE    BEEP
  715.                 THEN    R> ;
  716.  
  717. DEFER DEL-IN    ' (DEL-IN) IS DEL-IN
  718. \ If at beginning of line, beep, otherwise back up and erase 1.
  719.  
  720. : BACK-UP       ( n c -- 0 c )
  721. \ Wipe out the current line by overwriting it with spaces.
  722.                 >R DUP BACKSPACES   DUP SPACES   BACKSPACES   0  R> ;
  723.  
  724. : RESET-IN      ( -- )
  725. \ Reset the system to a relatively clean state.
  726.                 FORTH   TRUE ABORT" Reset"  ;
  727.  
  728. DEFER RES-IN    ' RESET-IN IS RES-IN
  729. \ Reset the system to a relatively clean state.
  730.  
  731. : P-IN          ( -- )
  732. \ Toggle the printer on or off
  733.                 PRINTING @ 0= PRINTING !  ;
  734.  
  735. : (ESC-IN)      ( a n char -- a n+1 char )
  736. \ Default handler of ESC character
  737.                 >R 2DUP + @ EMIT 1+ R> ;
  738.  
  739. DEFER ESC-IN    ' (ESC-IN) IS ESC-IN
  740. \ A defered word to handle ESC character
  741.  
  742. : CR-IN         ( m a n c -- m a m c )
  743. \ Finish input and remember the number of chars in SPAN
  744.                 >R SPAN !   OVER   BL EMIT R>  ;
  745.  
  746. : (CHAR)        ( a n char -- a n+1 char )
  747. \ Process an ordinary character by appending it to the buffer.
  748.                 DUP>R 3DUP EMIT + C!   1+  R> ;
  749.  
  750. DEFER CHAR      ' (CHAR) IS CHAR
  751. \ is usually (CHAR). Executed for most characters.
  752.  
  753. DEFER ^CHAR     ' CHAR   IS ^CHAR
  754. \ Similiar to  CHAR  for control characters.
  755.  
  756. : NORM-KEYTABLE    ( a n1 char n2 -- a n1+1 char )
  757. \ Execute the control character corresponding to n2
  758.                EXEC:
  759.    ^CHAR   ^CHAR  ^CHAR  RES-IN ^CHAR  ^CHAR   ^CHAR  ^CHAR
  760.    DEL-IN  ^CHAR  ^CHAR  ^CHAR  ^CHAR  CR-IN   ^CHAR  ^CHAR
  761.    P-IN    ^CHAR  ^CHAR  ^CHAR  ^CHAR  BACK-UP ^CHAR  ^CHAR
  762.    BACK-UP ^CHAR  ^CHAR  ESC-IN ^CHAR  ^CHAR   ^CHAR  ^CHAR ;
  763.  
  764. DEFER KEYTABLE  ( a n1 char n2 -- a n1+1 char )
  765. \ A defered word to execute the control character corresponding to n2 .
  766. ' NORM-KEYTABLE IS KEYTABLE
  767.  
  768.  
  769. : NEXPECT       ( adr len start -- )
  770. \ expect to a buffer that may already contain some data.
  771.                 DUP>R IF OVER R@ TYPE THEN
  772.                 DUP SPAN !   SWAP R> ( LEN ADR 0_SOFAR )
  773.                 BEGIN   2 PICK OVER - ( len adr #so-far #left )
  774.                 WHILE   2>R >R KEY R> SWAP 2R> ROT
  775.                                 \ The above looks silly no doubt, it is done
  776.                                 \ to assure the stack is empty of the
  777.                                 \ parameters used by NEXPECT, so a background
  778.                                 \ task can display the stack when both shift
  779.                                 \ keys are pressed together.
  780.                         DUP BL <
  781.                         IF      DUP KEYTABLE DROP
  782.                         ELSE    DUP 127 =
  783.                                 IF   DEL-IN   ELSE   CHAR   THEN  DROP
  784.                         THEN
  785.                 REPEAT  3DROP ;
  786.  
  787. : (EXPECT)      ( adr len --- )
  788. \ Accept text into the buffer at "adr" for "len" bytes.
  789.                 0   NEXPECT  ;          ( len adr 0 )
  790.  
  791. DEFER EXPECT    ' (EXPECT) IS EXPECT
  792. \ Get a string from the terminal and place it in the buffer provided.
  793.  
  794. CODE TIB        ( -- addr )
  795. \ Leaves address of text input buffer.
  796.                 PUSH 'TIB       NEXT    END-CODE
  797.  
  798.                                         \ 07/03/89 RB
  799. CODE MORE?      ( -- Flag )             \ Is words left in input stream?
  800.                 MOV AX, >IN
  801.                 SUB AX, #TIB
  802.                 SBB AX, AX
  803.                 1PUSH   END-CODE
  804.  
  805. : QUERY         ( -- )
  806. \  Get more input from the user and place it at TIB.
  807.                 TIB COLS EXPECT  SPAN @ #TIB ! >IN OFF  ;
  808.  
  809.       VARIABLE DISK-ERROR
  810. \ Returns the address of a variable which contains error information on the
  811. \ most recent attempt to access the disk.
  812.  
  813.    -2 CONSTANT LIMIT
  814. \ The highest address in the Code Segment used by Forth.
  815.  
  816. LIMIT 10 - CONSTANT FIRST
  817. \ This is a simple constant having the value 10 less than  LIMIT .
  818.  
  819. FIRST 10 - CONSTANT INIT-R0
  820. \ Address of the base of the Return Stack.
  821.  
  822. DECIMAL
  823.  
  824. FORTH DEFINITIONS
  825.  
  826. : HEX           ( -- )   
  827. \ Set the contents of BASE to 16 (i.e., Hexadecimal).
  828.                 16 BASE !  ;
  829.  
  830. : DECIMAL       ( -- )
  831. \ Restore the contents of base to 10 (i.e., Decimal)
  832.                 10 BASE !  ;
  833.  
  834. : OCTAL         ( -- )
  835. \ Set the contents of BASE to 8 (i.e., Octal)
  836.                 8 BASE !  ;
  837.  
  838. DEFER DEFAULT
  839. \ Opens the default file per the execute line.  
  840. \ Does nothing if no file was given.
  841.  
  842. CODE DIGIT      ( char base -- n f )
  843. \ If the character is equivalent to a digit in the specified base,
  844. \ convert the character and return a  TRUE  flag, else leave char and  FALSE.
  845.                 POP DX          POP AX          PUSH AX
  846.                 SUB AL, # ASCII 0
  847.                 JB 0 $
  848.                         CMP AL, # 9
  849.               > IF
  850.                         CMP AL, # 17
  851.                         JB 0 $
  852.                         SUB AL, # 7
  853.                 THEN
  854.                 CMP AL, DL
  855.                 JAE 0 $
  856.                         MOV DL, AL
  857.                         POP AX
  858.                         MOV AX, # TRUE
  859.                 2PUSH
  860.         0 $:    SUB AX, AX      1PUSH           END-CODE
  861.  
  862. : DOUBLE?       ( -- f )
  863. \ Returns non-zero if a period was encountered during last numeric scan. 
  864.                 DPL @ 1+   0<> ;
  865.  
  866. : CONVERT       ( +d1 adr1 -- +d2 adr2 )
  867. \ Convert the string at adr1 to a double number until an unconvertable
  868. \ character is encountered (pointed to by adr2).  Accumulate in +d1.
  869.                 BEGIN   1+  DUP>R  C@  BASE @  DIGIT
  870.                 WHILE   SWAP  BASE @ UM*  DROP  ROT  BASE @ UM*  D+
  871.                         DOUBLE?  IF  DPL INCR THEN  R>
  872.                 REPEAT  DROP  R>  ;
  873.  
  874. : (NUMBER?)     ( adr -- d flag )
  875. \ Convert string at  adr  to a number.  If successful, leave  TRUE  flag.  
  876. \ The string should terminate with an ASCII space.
  877.                 0 0  ROT  DUP 1+  C@  ASCII -  =  DUP  >R  -  DPL -1!
  878.                 BEGIN   CONVERT  DUP C@  ASCII , ASCII / BETWEEN
  879.                 WHILE   DPL 0!
  880.                 REPEAT  -ROT  R> IF  DNEGATE  THEN   ROT C@ BL =  ;
  881.  
  882. : NUMBER?       ( adr -- d flag )
  883. \ Convert a counted string to a number.  The string should terminate
  884. \ with an ASCII space and contain a valid, possibly signed, number.
  885.                 FALSE  OVER COUNT BOUNDS
  886.                 ?DO     I C@ BASE @ DIGIT NIP
  887.                         IF      DROP TRUE LEAVE THEN
  888.                 LOOP
  889.                 IF  (NUMBER?)  ELSE  DROP  0 0 FALSE  THEN  ;
  890.  
  891. : %$NUM         ( a1 -- d1 f1 )         \ process as a hex number $A123
  892.                 dup>r DUP COUNT 1- 0MAX >R
  893.                 DUP 1+ SWAP R> CMOVE    \ Extract the $.
  894.                 DUP C@ 1- OVER C!       \ Shorten count by 1.
  895.                 BL OVER COUNT + C!      \ Append a blank to string.
  896.                 BASE @ >R               \ Save the base for later restoral.
  897.                 HEX NUMBER?             \ Try to convert the number in HEX
  898.                 R> BASE !               \ Restore the BASE.
  899.                 DUP 0=                  \ If its not a number, restore the $.
  900.                 IF      R@ COUNT >R DUP 1+ R> CMOVE>
  901.                         R@ C@ 1+ R@ C!
  902.                         ASCII $ R@ 1+ C!
  903.                 THEN    r>drop ;
  904.  
  905. : %'NUM         ( a1 -- d1 f1 )         \ process as an ascii char 'A'
  906.                 STATE @
  907.                 IF      DROP
  908.                         TIB >IN @ 3 - + C@ 0
  909.                 ELSE    2+ C@ 0
  910.                 THEN    TRUE DPL ON ;
  911.  
  912. : %^NUM         ( a1 -- d1 f1 )         \ process as a control char ^A
  913.                 2+ C@ $1F AND 0 TRUE DPL ON ;
  914.  
  915. DEFER $NUM      ' %$NUM   IS $NUM
  916. DEFER 'NUM      ' %'NUM   IS 'NUM
  917. DEFER ^NUM      ' %^NUM   IS ^NUM
  918. DEFER #NUM      ' NUMBER? IS #NUM
  919.  
  920. CODE %NUMBER    ( a1 -- d1 f1 )
  921. \ Convert count delimited string at a1 into double number.  Special
  922. \ prefixes allowed.
  923.                 MOV DI, SP
  924.                 MOV BX, 0 [DI]
  925.                 MOV AL, 1 [BX]
  926.                 CMP AL, # ASCII $               \ test for leading $
  927.              0= IF      JMP ' $NUM              \ process as HEX
  928.                 THEN
  929.                 MOV AL, 1 [BX]
  930.                 MOV AH, 3 [BX]
  931.                 CMP AX, # ASCII '  dup flip +   \ test for lead & trail '
  932.              0= IF      JMP ' 'NUM              \ process as ascii char
  933.                 THEN
  934.                 MOV AX, 0 [BX]
  935.                 CMP AX, # ASCII ^ flip $02 +    \ test for lead ^ & cnt = 2
  936.              0= IF      JMP ' ^NUM              \ process as control char
  937.                 THEN
  938.                 JMP ' #NUM                      \ else process as a number
  939.                 END-CODE
  940.  
  941. : (NUMBER)      ( a1 -- d1 )
  942. \ Convert count delimited string at a1 into a double number.
  943.                 %NUMBER NOT ?MISSING ;
  944.  
  945. DEFER NUMBER    ' (NUMBER) IS NUMBER
  946. \ Convert count delimited string at a1 into a double number.
  947.  
  948. : HOLD          ( char -- )
  949. \ Save the character for later output.  Characters are entered in a
  950. \ right to left sequence!
  951.                 HLD DECR HLD @ C!   ;
  952.  
  953. : <#            ( -- )  
  954. \ Start numeric conversion.
  955.                 PAD  HLD  !  ;
  956.  
  957. : #>            ( d# -- addr len )
  958. \ Terminate numeric conversion.
  959.                 2DROP  HLD  @  PAD  OVER  -  ;
  960.  
  961. : SIGN          ( n1 -- )
  962. \ If n1 is negative insert a minus sign into the string.
  963.                 0< IF  ASCII -  HOLD  THEN  ;
  964.  
  965. : #             ( d1 -- d2 )
  966. \ Convert a single digit in the current base.
  967.                 BASE @ MU/MOD ROT 9 OVER <
  968.                 IF  7 + THEN ASCII 0  +  HOLD  ;
  969.  
  970. : #S            ( d -- 0 0 )
  971. \ Convert a number until it is finished.
  972.                 BEGIN  #  2DUP  OR  0=  UNTIL  ;
  973.  
  974. : (U.)          ( u -- a l )
  975. \ Convert an unsigned 16 bit number to a string.
  976.                 0    <# #S #>   ;
  977.  
  978. : U.            ( u -- )
  979. \ Convert an unsigned 16 bit number to a string.
  980.                 (U.)   TYPE SPACE   ;
  981.  
  982. : U.R           ( u l -- )
  983. \ Output as an unsigned single number right justified.
  984.                 >R   (U.)   R> OVER - SPACES   TYPE   ;
  985.  
  986. : (.)           ( n -- a l )
  987. \ Convert a signed 16 bit number to a string.
  988.                 DUP ABS 0   <# #S   ROT SIGN   #>   ;
  989.  
  990. : .             ( n -- )
  991. \ Output as a signed single number with a trailing space.
  992.                 (.)   TYPE SPACE   ;
  993.  
  994. : .R            ( n l -- )
  995. \ Output as a signed single number right justified.
  996.                 >R   (.)   R> OVER - SPACES   TYPE   ;
  997.  
  998. : (UD.)         ( ud -- a l )
  999. \ Convert an unsigned double number to a string.
  1000.                 <# #S #>   ;
  1001.  
  1002. : UD.           ( ud -- )
  1003. \ Output as an unsigned double number with a trailing space
  1004.                 (UD.)   TYPE SPACE   ;
  1005.  
  1006. : UD.R          ( ud l -- )
  1007. \ Output as an unsigned double number right justified.
  1008.                 >R   (UD.)   R> OVER - SPACES   TYPE  ;
  1009.  
  1010. : (D.)          ( d -- a l )
  1011. \ Convert a signed double number to a string.
  1012.                 TUCK DABS   <# #S   ROT SIGN  #>   ;
  1013.  
  1014. : D.            ( d -- )
  1015. \ Output as a signed double number with a trailing space.
  1016.                 (D.)   TYPE SPACE   ;
  1017.  
  1018. : D.R           ( d l -- )
  1019. \ Output as a signed double number right justified.
  1020.                 >R   (D.)   R> OVER - SPACES   TYPE   ;
  1021.  
  1022. CODE  SKIP      ( addr len char -- addr' len' )
  1023. \ Skip char through addr for len, returning addr' and len' of char+1.
  1024.                 POP AX          POP CX
  1025.                 JCXZ 0 $
  1026.                 POP DI
  1027.                 MOV DX, ES      MOV ES, SSEG
  1028.                 REPZ            SCASB
  1029.                 MOV ES, DX
  1030.             0<> IF
  1031.                 INC CX          DEC DI
  1032.             THEN
  1033.                 PUSH DI         PUSH CX
  1034.                 NEXT
  1035.         0 $:    PUSH CX         NEXT            END-CODE
  1036.  
  1037. CODE  SCAN      ( addr len char -- addr' len' )
  1038. \ Scan for char through addr for len, returning addr' and len' of char.
  1039.                 POP AX          POP CX
  1040.                 JCXZ 0 $
  1041.                 POP DI
  1042.                 MOV DX, ES      MOV ES, SSEG
  1043.                 REPNZ           SCASB
  1044.                 MOV ES, DX
  1045.              0= IF
  1046.                 INC CX          DEC DI
  1047.              THEN
  1048.                 PUSH DI         PUSH CX
  1049.                 NEXT
  1050.         0 $:    PUSH CX         NEXT            END-CODE
  1051.  
  1052. CODE /STRING    ( addr len n -- addr' len' )
  1053. \ Index into the string by n.  Returns addr+n and len-n.
  1054.                 POP AX          POP BX
  1055.                 PUSH BX         CMP BX, AX
  1056.             U<= IF
  1057.                 XCHG BX, AX     \ AX = SMALLER OF AX BX
  1058.              THEN
  1059.                 POP BX          POP DX
  1060.                 ADD DX, AX      PUSH DX
  1061.                 SUB BX, AX      PUSH BX
  1062.                 NEXT            END-CODE
  1063.  
  1064. CODE SOURCE     ( -- addr len )         \ TIB #TIB @
  1065. \ Return address and count of the input string in the Text input buffer.
  1066.                 MOV DX, 'TIB
  1067.                 MOV AX, #TIB
  1068.                 2PUSH
  1069.                 END-CODE
  1070.  
  1071. : PARSE         ( char -- addr len )
  1072. \ Scan the input stream until char is encountered.
  1073.                 >R   SOURCE >IN @ /STRING   OVER SWAP R> SCAN
  1074.                 >R OVER -  DUP R>  0<> -  >IN +!  ;
  1075.  
  1076. CODE WORD       ( c1 --- addr )
  1077. \  Parse the input stream for char and return a count delimited
  1078. \  string at here.  Note there is always a blank following it.
  1079.                 MOV DI, 'TIB
  1080.                 MOV CX, #TIB
  1081.                 POP BX
  1082.                 PUSH ES                         \ Save ES for later restoral
  1083.                 MOV DX, DS      MOV ES, DX      \ ES = DS from now to END
  1084.                 MOV AX, >IN
  1085.                 CMP CX, AX
  1086.             U<= IF              MOV AX, CX      \ AX = SMALLER OF AX CX
  1087.                 THEN
  1088.                 ADD DI, AX
  1089.                 SUB CX, AX
  1090.                 MOV AX, BX
  1091.           CX<>0 IF              REPZ            SCASB
  1092.                             0<> IF              INC CX
  1093.                                                 DEC DI
  1094.                                 THEN
  1095.                 THEN
  1096.                 MOV DX, DI
  1097.                 MOV AX, BX
  1098.           CX<>0 IF              REPNZ           SCASB
  1099.                              0= IF              INC CX
  1100.                                                 DEC DI
  1101.                                 THEN
  1102.                 THEN
  1103.                 SUB DI, DX
  1104.                 MOV BX, #TIB
  1105.                 MOV AX, DX
  1106.           CX<>0 IF      DEC CX
  1107.                 THEN
  1108.                 SUB BX, CX      MOV >IN BX
  1109.                 MOV BX, UP
  1110.                 MOV DX, DP [BX]
  1111.                 MOV CX, DI
  1112.                 MOV DI, DX
  1113.                 MOV 0 [DI], CL
  1114.                 INC DI          \ CLD
  1115.                 MOV BX, IP
  1116.                 MOV IP, AX
  1117.                 REPNZ           MOVSB
  1118.                 MOV AL, # 32    STOSB
  1119.                 MOV IP, BX
  1120.                 POP ES                          \ Restore ES
  1121.                 PUSH DX
  1122.                 NEXT            END-CODE
  1123.  
  1124.