home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / portfoli / tbasic / tbasic.asm < prev    next >
Encoding:
Assembly Source File  |  1991-08-21  |  45.7 KB  |  1,887 lines

  1. ;***************************************************************
  2. ;*
  3. ;*
  4. ;*          TINY BASIC FOR INTEL 8086
  5. ;*
  6. ;*
  7. ;*              VERSION: 1.1
  8. ;*
  9. ;*                  BY
  10. ;*
  11. ;*              MICHAEL SULLIVAN
  12. ;*                              BASED
  13. ;*                               ON
  14. ;*                       LI-CHEN WANG'S
  15. ;*
  16. ;*                    8080 TINY BASIC
  17. ;*
  18. ;*
  19. ;*                    27 JUNE 1982
  20. ;*
  21. ;*        @COPYLEFT
  22. ;*        ALL WRONGS RESERVED
  23. ;*
  24. ;*    NOTE:
  25. ;*        8080 REGISTERS HAVE BEEN MAPPED AS FOLLOWS:
  26. ;*
  27. ;*        8080        8086
  28. ;*    -------------------------------------
  29. ;*
  30. ;*        BC    <->    CX
  31. ;*        DE    <->    DX
  32. ;*        HL    <->    BX
  33. ;*
  34. ;*
  35. ;*    VERS 1.1 - SUPPORT MS-DOS INTERUPT I/O
  36. ;*           IMPROVE RND ACTION
  37. ;*           SUPPORT TIME AND DATE FROM MS-DOS
  38. ;*
  39. ;**************************************************************
  40.     ;
  41.     ;
  42.     ORG    100H    ;STANDARD MS-DOS START ADDR.
  43. START:
  44.     MOV    SP,STACK    ;SET UP STACK
  45.     MOV    DX,MSG1    ;GET SIGN-ON MSG
  46.     CALL    PRTSTG    ;SEND IT
  47.     MOV    B,[BUFFER-2],80H ;INIT CMD LINE BUFFER
  48. ;
  49. ;    MAIN
  50. ;
  51. ; THIS IS THE MAIN LOOP THAT COLLECTS THE TINY BASIC PROGRAM
  52. ; AND STORES IT IN MEMORY.
  53. ;
  54. ; AT START, IT PRINTS OUT "(CR)OK(LF)", AND INITIALIZES THE
  55. ; STACK AND SOME OTHER INTERNAL VARIABLES. THEN IT PROMPTS
  56. ; ">" AND READS A LINE. IF THE LINE STARTS WITH A NONZERO
  57. ; NUMBER, THIS NUMBER IS THE LINE NUMBER. THE LINE NUMBER
  58. ; (IN 16 BIT BINARY) AND THE REST OF THE LINE (INCLUDING
  59. ; ITS (CR))IS STORED IN MEMORY. IF A LINE WITH THE SAME
  60. ; LINE NUMBER IS ALREADY THERE, IT IS REPLACED BY THE NEW
  61. ; ONE. IF THE REST OF THE LINE CONSISTS OF A (CR) ONLY, IT
  62. ; IS STORED AND ANY EXISTING LINE WITH THE SAME LINE
  63. ; NUMBER IS DELETED.
  64. ;
  65. ; AFTER A LINE IS INSERTED, REPLACED, OR DELETED, THE
  66. ; PROGRAM LOOPS BACK AND ASKS FOR ANOTHER LINE. THIS LOOP
  67. ; WILL BE TERMINATED WHEN IT READS A LINE WITH ZERO OR NO
  68. ; LINE NUMBER: CONTROL IS THEN TRANSFERED TO "DIRECT".
  69. ;
  70. ; THE TINY BASIC PROGRAM SAVE AREA STARTS AT THE MEMORY
  71. ; LOCATION LABELED "TXTBGN" AND ENDS AT "TXTEND". WE ALWAYS
  72. ; FILL THIS AREA STARTING AT "TXTBGN", THE UNFILLED PORTION
  73. ; POINTED TO BY THE CONTENTS OF THE MEMORY LOCATION LABELED
  74. ; "TXTUNF".
  75. ;
  76. ; THE MEMORY LOCATION "CURRNT" POINTS TO THE LINE NUMBER
  77. ; THAT IS CURRENTLY BEING INTERPRETED. WHILE WE AR IN THIS
  78. ; LOOP OR WHILE WE ARE INTERPRETING A DIRECT COMMAND
  79. ; (SEE NEXT SECTION), "CURRNT" SHOULD POINT TO A 0.
  80. ;
  81. RSTART:
  82.     MOV    SP,STACK    ;SET STACK POINTER
  83. ST1:
  84.     CALL    CRLF
  85.     MOV    DX,OK    ;DE->STRING
  86.     SUB    AL,AL
  87.     CALL    PRTSTG    ;PRINT PROMPT
  88.     MOV    W,[CURRNT],0 ;CURRENT LINE # = 0
  89. ST2:
  90.     MOV    W,[LOPVAR],0
  91.     MOV    W,[STKGOS],0
  92. ST3:
  93.     MOV    AL,'>'    ;PROMPT ">" NOW
  94.     CALL    GETLN    ;READ A LINE
  95.     PUSH    DI    ;DI -> END OF LINE
  96. ST3A:
  97.     MOV    DX,BUFFER ;DX -> BEGINNING OF LINE
  98.     CALL    TSTNUM    ;TEST IF IT'S A NUMBER
  99.     MOV    AH,0
  100.     CALL    IGNBLNK
  101.     OR    BX,BX    ;BX:= VALUE OF # OR 0 IF NO # FOUND
  102.     POP    CX    ;CX -> END OF LINE
  103.     JNZ    ST3B
  104.     JMP    DIRECT
  105. ST3B:
  106.     DEC    DX
  107.     DEC    DX
  108.     MOV    AX,BX    ;GET LINE #
  109.     MOV    DI,DX
  110.     STOW        ;VALUE OF LINE # THERE
  111.     PUSH    CX
  112.     PUSH    DX    ;BX,DX -> BEGIN,END
  113.     MOV    AX,CX
  114.     SUB    AX,DX
  115.     PUSH    AX    ;AX:= # BYTES IN LINE
  116.     CALL    FNDLN    ;FIND THIS LINE IN SAVE
  117.     PUSH    DX    ;AREA, DX -> SAVE AREA
  118.     JNZ    ST4    ;NZ:NOT FOUND, INSERT
  119.     PUSH    DX    ;Z:FOUND, DELERE IT
  120.     CALL    FNDNXT    ;FIND NEXT LINE
  121.             ;DE -> NEXT LIE
  122.     POP    CX    ;CX -> LINE TO BE DELETED
  123.     MOV    BX,[TXTUNF] ;BX -> UNFILLED SAVE AREA
  124.     CALL    MVUP    ;MOVE UP TO DELETE
  125.     MOV    BX,CX    ;TXTUNF -> UNFILLED AREA
  126.     MOV    [TXTUNF],BX ;UPDATE
  127. ST4:
  128.     POP    CX    ;GET READY TO INSERT
  129.     MOV    BX,[TXTUNF] ;BUT FIRST CHECK IF
  130.     POP    AX    ;AX = # CHARS IN LINE
  131.     PUSH    BX    ;IS 3 (LINE # AND CR)
  132.     CMP    AL,3    ;THEN DO NOT INSERT
  133.     JZ    RSTART    ;MUST CLEAR THE STACK
  134.     ADD    AX,BX    ;COMPUTE NEW TSTUNF
  135.     MOV    BX,AX    ;BX -> NEW UNFILLED AREA
  136. ST4A:
  137.     MOV    DX,TXTEND ;CHECK TO SEE IF THERE
  138.     CMP    BX,DX    ;IS ENOUGH SPACE
  139.     JC    ST4B    ;SORRY, NO ROOM FOR IT
  140.     JMP    QSORRY
  141. ST4B:
  142.     MOV    [TXTUNF],BX ;OK, UPDATE TXTUNF
  143.     POP    DX    ;DX -> OLD UNFILLED AREA
  144.     CALL    MVDOWN
  145.     POP    DX    ;DX -> BEGIN, BX -> END
  146.     POP    BX
  147.     CALL    MVUP    ;MOVE NEW LINE TO SAVE AREA
  148.     JP    ST3
  149.     
  150. TSTV:    MOV    AH,64    ;TEST VARIABLES
  151.     CALL    IGNBLNK
  152.     JC    RET
  153. TSTV1:
  154.     JNZ    TV1    ;NOT @ ARRAY
  155.     CALL    PARN    ;@ SHOULD BE FOLLOWED
  156.     ADD    BX,BX
  157.     JNC    SS1B    ;IS INDEX TOO BIG?
  158.         JMP     QHOW
  159. SS1B:    PUSH    DX    ;WILL IT OVERWRITE
  160.     XCHG    DX,BX    ;TEXT?
  161.     CALL    SIZE    ;FIND SIZE OF FREE
  162.     CMP    BX,DX    ;AND CHECK THAT
  163.     JNC    SS1A    ;IFF SO, SAY "SORRY"
  164.         JMP     ASORRY
  165. SS1A:
  166.     MOV    BX,VARBGN    ;IFF NOT, GET ADDRESS
  167.     SUB    BX,DX    ;OF @(EXPR) AND PUT IT
  168.     POP    DX    ;IN HL
  169.     RET    ;C FLAG IS CLEARED
  170. TV1:
  171.     CMP    AL,27    ;NOT @, IS IT A TO Z?
  172. CMC:
  173.     ;IFF NOT, RETURN C FLAG
  174.     JC    RET    ;IFF NOT, RETURN C FLAG
  175.     INC    DX
  176. TV1A:
  177.     MOV    BX,VARBGN    ;COMPUTE ADDRESS OF
  178.     MOV    AH,0    ;CLEAR UPPER BYTE
  179.     ADD    AX,AX    ;AX:=AX*2 (WORD STORAGE)
  180.     ADD    BX,AX    ;BX:=VARBGN+2*AL
  181.     RET        ;USE CARRY AS ERROR INDICATOR
  182. ;
  183. ; TSTNUM - AT ENTRY DX -> BUFFER OF ASCII CHARACTERS
  184. ;
  185. TSTNUM:
  186.     MOV    BX,0    ;****TSTNUM****
  187.     MOV    CH,BH    ;TEST IFF THE TEXT IS
  188.     MOV    AH,0    ;FOR CMP IN IGNBLNK
  189.     CALL    IGNBLNK    ;A NUMBER.
  190. TN1:
  191.     CMP    AL,'0'    ;IFF NOT, RETURN 0 IN
  192.     JC    RET    ;B AND HL
  193.     CMP    AL,':'    ;IFF NUMBERS, CONVERT
  194.     JNC    RET    ;TO BINARY IN BX AND
  195.     MOV    AL,0F0H        ;SET AL TO # OF DIGITS
  196.     AND    AL,BH    ;IFF BH>255, THERE IS NO
  197.     JNZ    QHOW    ;ROOM FOR NEXT DIGIT
  198.     INC    CH    ;CH COUNTS NUMBER OF DIGITS
  199.     PUSH    CX
  200.     MOV    AX,BX    ;BX:=10*BX+(NEW DIGIT)
  201.         MOV     CX,10
  202.     PUSH    DX    ;SAVE DX
  203.         MUL     AX,CX
  204.         MOV     BX,AX   ;PARTIAL RESULT NOW IN BX
  205.     POP    DX    ;RESTORE
  206.     MOV    SI,DX
  207.     LODB            ;ASCII DIGIT IN AL NOW
  208.         SUB     AL,48   ;CONVERT TO BINARY
  209.         MOV     AH,0
  210.         ADD     BX,AX   ;FULL RESULT NOW IN BX
  211.     POP    CX
  212.     LODB            ;REPEAT FOR MORE DIGITS
  213.     LAHF        ;SAVE FLAGS
  214.     INC    DX
  215.     SAHF        ;RESTORE FLAGS
  216.     JNS    TN1    ;QUIT IF NO NUM OR OVERFLOW
  217. QHOW:
  218.     PUSH    DX    ;****ERROR: "HOW?"****
  219. AHOW:
  220.     MOV    DX,HOW
  221.     JMP    ERROR
  222. HOW:
  223.     DB    'HOW?',0DH
  224. OK:
  225.     DB    'OK',0DH
  226. WHAT:
  227.     DB    'WHAT?',0DH
  228. SORRY:
  229.     DB    'SORRY',0DH
  230. ;
  231. ;*
  232. ;**********************************************************
  233. ;*
  234. ;* *** TABLES *** DIRECT *** & EXEC ***
  235. ;*
  236. ;* THIS SECTION OF THE CODE TESTS A STRING AGAINST A TABLE.
  237. ;* WHEN A MATCH IS FOUND, CONTROL IS TRANSFERRED TO THE SECTION
  238. ;* OF CODE ACCORDING TO THE TABLE.
  239. ;*
  240. ;* AT 'EXEC' DX SHOULD POINT TO THE STRING AND BX SHOULD POINT
  241. ;* TO THE TABLE-1. AT 'DIRECT', DX SHOULD POINT TO THE STRING,
  242. ;* BX WILL BE SET UP TO POINT TO TAB1-1, WHICH IS THE TABLE OF
  243. ;* ALL DIRECT AND STATEMENT COMMANDS.
  244. ;*
  245. ;* A '.' IN THE STRING WILL TERMINATE THE TEST AND THE PARTIAL
  246. ;* MATCH WILL BE CONSIDERED AS A MATCH. E.G., 'PR.',
  247. ;* 'PRI.', 'PRIN.', OR 'PRINT' WILL ALL MATCH 'PRINT'.
  248. ;*
  249. ;* THE TABLE CONSISTS OF ANY NUMBER OF ITEMS. EACH ITEM
  250. ;* IS A STRING OF CHARACTERS WITH BIT 7 SET TO 1 IN LAST CHAR
  251. ;* A JUMP ADDRESS IS STORED FOLLOWING EACH CHARACTER ENTRY.
  252. ;*
  253. ;* END OF TABLE IS AN ITEM WITH A JUMP ADDRESS ONLY. IF THE 
  254. ;* STRING DOES NOT MATCH ANY OF THE OTHER ITEMS, IT WILL
  255. ;* MATCH THIS NULL ITEM AS DEFAULT. THE DEFAULT IS INDICATED
  256. ;* BY FOLLOWING THE 80H DEFAULT INDICATOR.
  257. ;*
  258.  
  259. TAB1:   EQU    $    ;DIRECT COMMANDS
  260.     DM    'LIST'
  261.     DW    LIST    ;EXECUTION ADDRESSES
  262.     DM    'EDIT'
  263.     DW    EDIT
  264.     DM    'E'
  265.     DW    EDIT    ;HAVE SHORT FORM DEFINED ALSO
  266.     DM    'RUN'
  267.     DW    RUN
  268.     DM    'NEW'
  269.     DW    NEW
  270.     DM    'LOAD'
  271.     DW    DLOAD
  272.     DM    'SAVE'
  273.     DW    DSAVE
  274.     DM    'BYE'    ;GO BACK TO DOS (EXIT TBASIC)
  275.     DW    BYE
  276. TAB2:    EQU    $    ;DIRECT/STATEMENT
  277.     DM    'NEXT'
  278.     DW    NEXT    ;EXECUTION ADDRESSES
  279.     DM    'LET'
  280.     DW    LET
  281.     DM    'OUT'
  282.     DW    OUTCMD
  283.     DM    'POKE'
  284.     DW    POKE
  285.     DM    'WAIT'
  286.     DW    WAITCM
  287.     DM    'IF'
  288.     DW    IFF
  289.     DM    'GOTO'
  290.     DW    GOTO
  291.     DM    'GOSUB'
  292.     DW    GOSUB
  293.     DM    'RETURN'
  294.     DW    RETURN
  295.     DM    'REM'
  296.     DW    REM
  297.     DM    'FOR'
  298.     DW    FOR
  299.     DM    'INPUT'
  300.     DW    INPUT
  301.     DM    'PRINT'
  302.     DW    PRINT
  303.     DM    'STOP'
  304.     DW    STOP
  305.     DB    128    ;SIGNALS END
  306.             ;REMEMBER TO MOVE DEFAULT DOWN.
  307.     DW    DEFLT    ;LAST POSIBILITY
  308. TAB4:    EQU    $    ;FUNCTIONS
  309.     DM    'RND'
  310.     DW    RND
  311.     DM    'INP'
  312.     DW    INP
  313.     DM    'PEEK'
  314.     DW    PEEK
  315.     DM    'USR'
  316.     DW    USR
  317.     DM    'ABS'
  318.     DW    ABS
  319.     DM    'SIZE'
  320.     DW    SIZE
  321.     DB    128    ;SIGNALS END
  322.             ;YOU CAN ADD MORE FUNCTIONS BUT REMEMBER
  323.             ;TO MOVE XP40 DOWN
  324.     DW    XP40
  325. TAB5:    EQU    $    ;"TO" IN "FOR"
  326.     DM    'TO'
  327. TAB5A:    DW    FR1
  328.     DB    128
  329.     DW    QWHAT
  330. TAB6:    EQU    $    ;"STEP" IN "FOR"
  331.     DM    'STEP'
  332. TAB6A:    DW    FR2
  333.     DB    128
  334.     DW    FR3
  335. TAB8:    EQU    $    ;RELATION OPERATORS
  336.     DM    '>='
  337.     DW    XP11    ;EXECUTION ADDRESS
  338.     DM    '#'
  339.     DW    XP12
  340.     DM    '>'
  341.     DW    XP13
  342.     DM    '='
  343.     DW    XP15
  344.     DM    '<='
  345.     DW    XP14
  346.     DM    '<'
  347.     DW    XP16
  348.     DB    128
  349.     DW    XP17
  350. ;
  351. ; END OF PARSER ACTION TABLE
  352. ;
  353. ;
  354. ; AT ENTRY BX -> COMMAND TABLE (ABOVE)
  355. ;       DX -> COMMAND LINE (I.E. "BUFFER")
  356. ;
  357. DIRECT:
  358.     MOV    BX,TAB1-1    ;***DIRECT***
  359.     ;*
  360. EXEC:    EQU    $    ;***EXEC***
  361. EX0:
  362.     MOV    AH,0
  363.     CALL    IGNBLNK    ;IGNORE LEADING BLANKS
  364.     PUSH    DX    ;SAVE POINTER
  365.     MOV    SI,DX
  366. EX1:    LODB        ;GET CHAR WHERE DX ->
  367.     INC    DX    ;PRESERVE POINTER
  368.     CMP    AL,'.'    ;WE DECLARE A MATCH
  369.     JZ    EX4
  370.     INC    BX
  371.     MOV    AH,[BX]
  372.     AND    AH,127    ;STRIP BIT 7
  373.     CMP    AL,AH    ;COMPARISON NOW EASY
  374.     JZ    EX2
  375.     ; NO MATCH - CHECK NEXT ENTRY
  376. EX0A:    CMP    B,[BX],128    ;BYTE COMPARE
  377.     JNC    EX0B
  378.     INC    BX
  379.     JP    EX0A
  380.     ; AT THIS POINT HAVE LAST LETTER
  381. EX0B:    ADD    BX,3    ;GET PAST EXECUTION ADDRESS
  382.     CMP    B,[BX],128    ;FOUND DEFAULT?
  383.     JZ    EX3A    ;IF SO, EXECUTE DEFAULT
  384.     DEC    BX    ;CORRECT FOR PRE-INCREMENT
  385.     POP    DX    ;RESTORE POINTER
  386.     JP    EX0    ;LOOK SOME MORE FOR A MATCH
  387. EX4:    INC    BX
  388.     CMP    B,[BX],128
  389.     JC    EX4
  390.     JP    EX3
  391. ;
  392. EX3A:    DEC    SI
  393.     JP    EX3    ;CORRECT SI FOR DEFAULT EXECUTION
  394. EX2:    CMP    B,[BX],128    ;END OF RESERVED WORD?
  395.     JC    EX1    ;NO - CHECK SOME MORE
  396.     ; AT THIS POINT NEED TO GET EXECUTION ADDRESS
  397.  
  398. EX3:    INC    BX    ;BX -> EXECUTION ADDRESS
  399.     POP    AX    ;CLEAR STACK
  400.     MOV    DX,SI    ;RESET POINTER
  401.     JMP    [BX]    ;DO IT
  402. ;*
  403. ;
  404. ;
  405. ; WHAT FOLLOWS IS THE CODE TO ECECUTE DIRECT AND STATEMENT COM-
  406. ; MANDS. CONTROL IS TRANSFERED TO THESE POINTS VIA THE  COMMAND
  407. ; TABLE LOOKUP CODE OF 'DIRECT' AND 'EXEC' IN THE LAST SECTION.
  408. ; AFTER THE COMMAND IS EXECUTED,  CONTROL  IS  TRANSFERRED   TO
  409. ; OTHER SECTIONS AS FOLLOWS:
  410. ;
  411. ; FOR 'LIST','NEW', ANS 'STOP': GO BACK TO 'RSTART'
  412. ;
  413. ; FOR 'RUN',: GO EXECUTE THE FIRST STORED LINE IFF ANY; ELSE
  414. ;            GO BACK TO RSTART.
  415. ;
  416. ; FOR 'GOTO' AND 'GOSUB': GO EXECUTE THE TARGET LINE.
  417. ;
  418. ; FOR 'RETURN' AND 'NEXT': GO BACK TO SAVED RETURN LINE.
  419. ;
  420. ; FOR ALL OTHERS: IFF 'CURRNT' -> 0, GO TO 'RSTART', ELSE
  421. ;            GO EXECUTE NEXT COMMAND. (THIS IS DONE
  422. ;            IN 'FINISH'.)
  423. ;
  424. ;
  425. ; ****NEW****STOP****RUN (& FRIENDS)****GOTO****
  426. ;
  427. ; 'NEW(CR)' SETS 'TXTUNF' TO POINT TO 'TXTBGN'
  428. ;
  429. ; 'STOP(CR)' GOES BACK TO 'RSTART'
  430. ;
  431. ; 'RUN(CR)' FINDS THE FIRST STROED LINE, STORES ITS ADDRESS
  432. ;    (IN 'CURRNT'), AND START TO EXECUTE IT. NOTE THAT ONLY
  433. ;    THOSE COMMANDS IN TAB2 ARE LEGAL FOR STORED PROGRAMS.
  434. ;
  435. ; THERE ARE THREE MORE ENTRIES IN 'RUN':
  436. ;
  437. ;    'RUNNXL' FINDS NEXT LINE, STORES ITS ADDR AND EXEC IT.
  438. ;    'RUNTSL' STORES THE ADDRESS OF THIS LINE AND EXECUTES IT
  439. ;    'RUNSML' CONTINUES THE EXECUTION ON SAME LINE.
  440. ;
  441. ; 'GOTO(EXPR)' EVALUATES THE EXPRESSION, FINDS THE TARGET LINE,
  442. ;    AND JUMPS TO 'RUNTSL' TO DO IT.
  443. ;
  444. ; 'DLOAD' LOADS A NAMES PROGRAM FROM DISK (ANYNAME.TBI)
  445. ;
  446. ; 'DSAVE' SAVES A NAMES PROGRAM ON DISK
  447. ;
  448. ; 'FCBSET' SETS UP THE MSDOS FILE CONTROL BLOCK FOR SUBSEQUENT
  449. ;    DISK I/O.
  450. ;
  451. ;
  452. NEW:
  453.     MOV    W,[TXTUNF],TXTBGN
  454.     ;
  455. STOP:
  456.     CALL    ENDCHK    ;****STOP(CR)****
  457.     JMP    RSTART
  458.     ;
  459. RUN:
  460.     CALL    ENDCHK    ;****RUN(CR)****
  461.     MOV    DX,TXTBGN    ;FIRST SAVED LINE
  462.     ;
  463. RUNNXL:
  464.     MOV    BX,0    ;****RUNNXL****
  465.     CALL    FNDLNP    ;FIND WHATEVER LINE
  466.     JNC    RUNTSL    ;C: PASSED TXTUNF, QUIT
  467.         JMP     RSTART
  468.     ;
  469. RUNTSL:
  470.     XCHG    DX,BX    ;****RUNTSL****
  471.     MOV    [CURRNT],BX    ;SET 'CURRNT"->LINE #
  472.     XCHG    DX,BX
  473.     INC    DX
  474.     INC    DX
  475.     ;
  476. RUNSML:
  477.     CALL    CHKIO    ;****RUNSML****
  478.     MOV    BX,TAB2-1    ;FIND COMMAND IN TABLE 2
  479.     JMP    EXEC    ;AND EXECUTE IT
  480.     ;
  481. GOTO:
  482.     CALL    EXP    ;****GOTO(EXPR)****
  483.     PUSH    DX    ;SAVE FOR ERROR ROUTINE
  484.     CALL    ENDCHK    ;MUST FIND A 0DH (CR)
  485.     CALL    FNDLN    ;FIND THE TARGET LINE
  486.     JZ    GT1    ;NO SUCH LINE #
  487.         JMP     AHOW
  488. GT1:    POP    AX
  489.     JP    RUNTSL    ;GO DO IT
  490.     ;
  491.     ; BDOS EQUATES (FOR MS-DOS)
  492.     ;
  493. BYE:    EQU    0    ;BDOS EXIT ADDRESS
  494. FCB:    EQU    5CH
  495. SETDMA:    EQU    26
  496. OPEN:    EQU    15
  497. READD:    EQU    20
  498. WRITED:    EQU    21
  499. CLOSE:    EQU    16
  500. MAKE:    EQU    22
  501. BCONIN:    EQU    10    ;BUFFERED CONSOLE INPUT
  502. DELETE:    EQU    19
  503. CONOUT:    EQU    2    ;CONSOLE OUTPUT
  504. CONST:    EQU    11    ;CONSOLE STATUS
  505.     ;
  506.     ;
  507. DLOAD:
  508.     MOV    AH,0
  509.     CALL    IGNBLNK    ;IGNORE BLANKS
  510.     PUSH    BX    ;SAVE H
  511.     CALL    FCBSET    ;SET UP FILE CONTROL BLOCK
  512.     PUSH    DX    ;SAVE THE REST
  513.     PUSH    CX    ;SAVE THE REST
  514.     MOV    DX,FCB    ;GET FCB ADDR
  515.     MOV    AH,OPEN    ;PREPARE TO OPEN FILE
  516.     INT    33    ;CALL MS-DOS TO OPEN FILE
  517.     CMP    AL,0FFH    ;IS IT THERE?
  518.     JNZ    DL1    ;NO, SEND ERROR
  519.         JMP     QHOW
  520. DL1:    XOR    AL,AL    ;CLEAR A
  521.     MOV    [FCB+32],AL    ;START AT RECORD 0
  522.     MOV    DX,TXTBGN    ;GET BEGINNING
  523. LOAD:
  524.     PUSH    DX    ;SAVE DMA ADDRESS
  525.     MOV    AH,SETDMA
  526.     INT    33    ;CALL MS-DOS TO SET DAM ADDR
  527.     MOV    AH,READD
  528.     MOV    DX,FCB
  529.     INT    33    ;CALL MS-DOS TO READ SECTOR
  530.     CMP    AL,1    ;DONE?
  531.     JC    RDMORE    ;NO, READ MORE
  532.     JZ    LL1
  533. LOAD1:    JMP    QHOW    ;BAD READ OR NO DELIMITER
  534. LL1:    MOV    AH,CLOSE
  535.     MOV    DX,FCB
  536.     INT    33    ;CALL MS-DOS TO CLOSE FILE
  537.     POP    BP    ;DMA ADDR IN BP
  538.     SUB    BP,100H ;BACKUP
  539.     MOV    CX,100H ;MAX LOOPS
  540. RDM1:    INC    BP    ;PRE INC
  541.     CMP    W,[BP],0 ;FOUND DELIMITER?
  542.     LOOPNZ    RDM1    ;KEEP LOOKING
  543.     CMP    CL,0    ;MAC LOOPS EXECUTED?
  544.     JZ    LOAD1    ;GIVE ERROR IF SO
  545.     MOV    [TXTUNF],BP ;UPDATE POINTER
  546.     POP    CX    ;GET OLD REG BACK
  547.     POP    DX    ;GET OLD REG BACK
  548.     POP    BX    ;GET OLD REG BACK
  549.     CALL    FINISH    ;FINISH
  550. RDMORE:
  551.     POP    DX    ;GET DMA ADDR
  552.     MOV    BX,80H    ;GET 128
  553.     ADD    BX,DX    ;ADD IT TO DMA ADDR
  554.     XCHG    DX,BX    ;BACK IN D
  555.     JMP    LOAD    ;AND READ SOME MORE
  556.     ;
  557. DSAVE:
  558.     CMP    W,[TXTUNF],TXTBGN ;SEE IF ANYTHING TO SAVE
  559.     JNZ    DS1A
  560.     JMP    QWHAT
  561. DS1A:
  562.     MOV    BP,[TXTUNF]
  563.     MOV    W,[BP],0 ;SET DELIMITER
  564.     MOV    AH,0
  565.     CALL    IGNBLNK    ;IGNORE BLANKS
  566.     PUSH    BX    ;SAVE BX
  567.     CALL    FCBSET    ;SETUP FCB
  568.     PUSH    DX
  569.     PUSH    CX    ;SAVE OTHERS
  570.     MOV    DX,FCB
  571.     MOV    AH,DELETE
  572.     INT    33    ;CALL MS-DOS TO ERASE FILE
  573.     MOV    DX,FCB
  574.     MOV    AH,MAKE
  575.     INT    33    ;CALL MS-DOS TO MAKE A NEW ONE
  576.     CMP    AL,0FFH    ;IS THERE SPACE?
  577.     JNZ    DS1
  578.         JMP     QHOW    ;NO, ERROR
  579. DS1:    XOR    AL,AL    ;CLEAR A
  580.     MOV    [FCB+32],AL    ;START AT RECORD 0
  581.     MOV    DX,TXTBGN    ;GET BEGINNING
  582. SAVE:
  583.     PUSH    DX    ;SAVE DMA ADDR
  584.     MOV    AH,SETDMA
  585.     INT    33    ;CALL MS-DOS TO SET DMA ADDR
  586.     MOV    AH,WRITED
  587.     MOV    DX,FCB
  588.     INT    33    ;CALL MS-DOS TO WRITE SECTOR
  589.     OR    AL,AL    ;SET FLAGS
  590.     JZ    SS1    ;IF NOT ZERO, ERROR
  591.         JMP     QHOW
  592. SS1:    POP    DX    ;GET DMA ADDR BACK
  593.     MOV    AX,DX
  594.     CMP    AX,[TXTUNF]    ;SEE IF DONE
  595.     JZ    SAVDON
  596.     JNC    SAVDON    ;JUMP IF DONE
  597. WRITMOR:
  598.     MOV    BX,80H
  599.     ADD    BX,DX
  600.     XCHG    DX,BX    ;GET IT TO D
  601.     JP    SAVE
  602. SAVDON:
  603.     MOV    AH,CLOSE
  604.     MOV    DX,FCB
  605.     INT    33    ;CALL MS-DOS TO CLOSE FILE
  606.     POP    CX    ;GET REGS BACK
  607.     POP    DX    ;GET REGS BACK
  608.     POP    BX    ;GET REGS BACK
  609.     CALL    FINISH
  610.     ;
  611. FCBSET:
  612.     MOV    BX,FCB    ;GET FCB ADDR
  613.     MOV    B,[BX],0    ;CLEAR ENTRY TYPE
  614. FNCLR:
  615.     INC    BX
  616.     MOV    B,[BX],' '    ;CLEAR TO SPACE
  617.     MOV    AX,FCB+8
  618.     CMP    AX,BX    ;DONE?
  619.     JNZ    FNCLR    ;NO, DO IT AGAIN
  620.     INC    BX
  621.     MOV    B,[BX],'T'    ;SET FILE TYPE TO 'TBI'
  622.     INC    BX
  623.     MOV    B,[BX],'B'
  624.     INC    BX
  625.     MOV    B,[BX],'I'
  626. EXRC:
  627.     INC    BX
  628.     MOV    B,[BX],0
  629.     MOV    AX,FCB+15
  630.     CMP    AX,BX
  631.     JNZ    EXRC    ;NO, CONTINUE
  632.     MOV    BX,FCB+1    ;GET FILENAME START
  633. FN:
  634.     MOV    SI,DX
  635.     LODB    ;GET CHAR
  636.     CMP    AL,0DH    ;IS IT A 'CR'
  637.     JZ    RET    ;YES, DONE
  638.     CMP    AL,'!'    ;LEGAL CHAR?
  639.     JNC     FN1    ;NO, SEND ERROR
  640.         JMP     QWHAT
  641. FN1:    CMP    AL,'['    ;AGAIN
  642.     JC    FN2    ;DITTO
  643.         JMP     QWHAT
  644. FN2:    MOV    [BX],AL    ;SAVE IT IN FCB
  645.     INC    BX
  646.     INC    DX
  647.     MOV    AX,FCB+9
  648.     CMP    AX,BX    ;LAST?
  649.     JNZ    FN    ;NO, CONTINUE
  650.     RET    ;TRUNCATE AT EIGHT CHARS
  651. ;
  652. ;
  653. ; ****LIST**** AND ****PRINT**** AND ****EDIT****
  654. ;
  655. ; LIST HAS TWO FORMS:
  656. ;    'LIST(CR)' LISTS ALL SAVED LINES
  657. ;    'LIST #(CR)' START LIST AT THIS LINE #
  658. ; YOU CAN STOP LISTING BY CONTROL C KEY
  659. ;
  660. ; PRINT COMMAND IS 'PRINT ....;' OR 'PRINT ....(CR)'
  661. ; WHERE '....' IS A LIST OF EXPRESIONS, FORMATS, BACKARROWS, AND
  662. ; STRINGS. THESE ITEMS ARE SEPERATED BY COMMAS.
  663. ;
  664. ; A FORMAT IS A POUND SIGN FOLLOWED BY A NUMBER. IT CONTROLS THE
  665. ; NUMBER OF SPACES THE VALUE OF AN EXPRESSION IS TO BE PRINTED.
  666. ; TED. IT STAYS EFFECTIVE FOR THE REST OF THE PRINT, UNLESS
  667. ; CHANGED BY ANOTHER FORMAT. IF NO FORMAT SPEC, 6 POSITIONS
  668. ; WILL BE USED.
  669. ;
  670. ; A STRING IS QUOTED IN A PAIR OF SINGLE QUOTES OR DOUBLE
  671. ; QUOTES.
  672. ;
  673. ; A BACK-ARROW MEANS GENERATE A (CR) WITHOUT (LF).
  674. ;
  675. ; A (CRLF) IS GENERATED AFTER THE ENTIRE LIST HAS BEEN PRINT OR
  676. ; IF THE LIST IS A NULL LIST. HOWEVER IF THE LIST ENDED WITH A 
  677. ; COMMA, NO (CR) IS GENERATED.
  678. ;
  679. ;
  680. LIST:
  681.     CALL    TSTNUM    ;TEST IFF THERE IS A #
  682.     CALL    ENDCHK    ;IFF NO # WE GET A 0
  683.     CALL    FNDLN    ;FIND THIS OR NEXT LINE
  684. LS1:
  685.     JNC    LS2    ;C: PASSED TXTUNF
  686.         JMP     RSTART
  687. LS2:    CALL    PRTLN    ;PRINT THE LINE
  688.     CALL    CHKIO    ;SEE IF ^X OR ^C
  689.     CALL    FNDLNP    ;FIND NEXT LINE
  690.     JP    LS1    ;LOOP BACK
  691.     ;
  692. ;
  693. EDIT:
  694.     CALL    TSTNUM    ;TEST IF THERE IS A #
  695.     CALL    ENDCHK    ;AT END?
  696.     CALL    FNDLN    ;FIND SPEC LINE OR NEXT LINE
  697.     PUSH    DX    ;SAVE LINE #
  698.     JNC    ED2    ;C: PASSED TXTUNF
  699.     POP    DX    ;THROW AWAY LINE #
  700. ED1:    JMP    RSTART
  701. ED2:
  702.     CALL    PRTLN    ;PRINT THE LINE
  703.     POP    DX    ;GET LINE # BACK
  704.     MOV    B,[OCSW],0 ;DIRECT OUTPUT TO BUFFER
  705.     MOV    B,[BUFFER-1],0 ;CLEAR CHAR COUNT
  706.     MOV    B,[PRTLN1+1],4 ;PRINT ONE LESS SPACE
  707.     MOV    DI,BUFFER ;PREPARE TO MOVE
  708.     CALL    PRTLN
  709.     MOV    B,[OCSW],0FFH ;REDIRECT OUTPUT TO CONSOLE
  710.     DEC    [BUFFER-1] ;AVOID CR?
  711.     MOV    B,[PRTLN1+1],5 ;RESTORE PRTLN
  712.     JMP    ST3    ;PROMPT AND GETLINE ONLY
  713. PRINT:
  714.     MOV    CL,6    ;C:= # OF SPACES
  715.     MOV    AH,';'    ;CHECK FOR ';' IN IGNBLNK
  716.     CALL    IGNBLNK    ;IGNORE BLANKS
  717.     JNZ    PR2    ;JUMP IF ';' NOT FOUND
  718.     CALL    CRLF    ;GIVE CR,LF AND
  719.     JMP    RUNSML    ;CONTINUE SAME LINE
  720. PR2:
  721.     MOV    AH,0DH
  722.     CALL    IGNBLNK
  723.     JNZ    PR0
  724.     CALL    CRLF    ;ALSO GIVE CRLF AND
  725.     JMP    RUNNXL    ;GOTO NEXT LINE
  726. PR0:
  727.     MOV    AH,'#'
  728.     CALL    IGNBLNK
  729.     JNZ    PR1
  730.     CALL    EXP    ;YES, EVALUATE EXPR
  731.     MOV    CL,BL    ;AND SAVE IT IN C
  732.     JP     PR3    ;LOOK FOR MORE TO PRINT
  733. PR1:
  734.     CALL    QTSTG    ;OR IS IT A STRING?
  735.     JP    PR8    ;IFF NOT, MUST BE EXPRESSION
  736. PR3:
  737.     MOV    AH,','
  738.     CALL    IGNBLNK
  739.     JNZ    PR6
  740.     CALL    FIN    ;IN THE LIST
  741.     JP    PR0    ;LIST CONTINUES
  742. PR6:
  743.     CALL    CRLF    ;LIST ENDS
  744.     CALL    FINISH
  745. PR8:
  746.     CALL    EXP    ;EVAL THE EXPR
  747.     PUSH    CX
  748.     CALL    PRTNUM    ;PRINT THE VALUE
  749.     POP    CX
  750.     JP    PR3    ;MORE TO PRINT?
  751. ;
  752. ;
  753. ; ****GOSUB**** AND ****RETURN****
  754. ;
  755. ; 'GOSUB (EXPR);' OR 'GOSUB EXPR(CR)' IS LIKE THE 'GOTO' COMMAND
  756. ; EXCEPT THAT THE CURRENT TEXT POINTER, STACK POINTER ETC.   ARE
  757. ; SAVED SO THAT EXECUTION CAN BE CONTINUED AFTER THE  SUBROUTINE
  758. ; 'RETURN'. IN ORDER THAT 'GOSUB' CAN BE NESTED (AND EVEN RECUR-
  759. ; SIVE), THE SAVE AREA MUST BE  STACKED.  THE  STACK  POINTER IS
  760. ; SAVED IN 'STKGOS'. THE OLD 'STKGOS' IS SAVED IN THE STACK. IF
  761. ; WE ARE IN THE MAIN ROUTINE, 'STKGOS' IS ZERO (THIS WAS DONE BY
  762. ; THE "MAIN" SECTION OF THE CODE),  BUT  WE  STILL  SAVE  IT  AS
  763. ; A FLAG FOR NO FURTHER RETURNS.
  764. ;
  765. ; 'RETURN(CR)' UNDOES EVERYTHING THAT 'GOSUB' DID, AND THUS  RE-
  766. ; TURNS THE EXECUTION TO THE COMMAND AFTER THE MOST RECENT  'GO-
  767. ; SUB'. IFF 'STKGOS' IS ZERO, IT INDICATES THAT WE NEVER  HAD  A
  768. ; 'GOSUB' AND IS THUS AN ERROR.
  769. ;
  770. ;
  771. GOSUB:
  772.     CALL    PUSHA    ;SAVE THE CURRENT 'FOR'
  773.     CALL    EXP    ;PARAMETERS
  774.     PUSH    DX
  775.     CALL    FNDLN    ;FIND THE TARGET LINE
  776.     JZ    GS1    ;NOT THERE, SAY "HOW?"
  777.         JMP     AHOW
  778. GS1:    MOV    BX,[CURRNT]    ;FOUND IT, SAVE OLD
  779.     PUSH    BX    ;'CURRNT' OLD 'STKGOS'
  780.     MOV    BX,[STKGOS]
  781.     PUSH    BX
  782.     MOV    BX,0    ;AND LOAD NEW ONES
  783.     MOV    [LOPVAR],BX
  784.     ADD    BX,SP
  785.     MOV    [STKGOS],BX
  786.     JMP    RUNTSL    ;THEN RUN THAT LINE
  787. RETURN:
  788.     CALL    ENDCHK    ;THERE MUST BE A 0DH
  789.     MOV    BX,[STKGOS]    ;OLD STACK POINTER
  790.     OR    BX,BX
  791.     JNZ    RET1    ;SO, WE SAY: "WHAT?"
  792.         JMP     QWHAT
  793. RET1:    XCHG    BX,SP        ;ELSE RESTORE IT
  794.     POP    BX    ;ELSE RESTORE IT
  795.     MOV    [STKGOS],BX    ;AND THE OLD 'STKGOS'
  796.     POP    BX
  797.     MOV    [CURRNT],BX    ;AND THE OLD 'CURRNT'
  798.     POP    DX    ;OLD TEXT POINTER
  799.     CALL    POPA    ;OLD "FOR" PARAMETERS
  800.     CALL    FINISH    ;AND WE ARE BACK HOME
  801. ;
  802. ;
  803. ; ****FOR**** AND ****NEXT****
  804. ;
  805. ;
  806. ; 'FOR' HAS TWO FORMS:
  807. ;    'FOR VAR=EXP1 TO EXP2 STEP EXP3'
  808. ;    'FOR VAR=EXP1 TO EXP2'
  809. ; THE SECOND FORM MEANS THE SAME AS THE FIRST FORM WITH EXP3=1.
  810. ;
  811. ; TBI WILL FIND THE VARIABLE VAR AND SET ITS VALUE TO THE CUR-
  812. ; RENT VALUE OF EXP1. IT ALSO  EVALUATES  EXP2  AND  EXP3  AND
  813. ; SAVES ALL OF THESE TOGETHER  WITH  THE  TEXT  POINTER ETC IN
  814. ; THE 'FOR' SAVE AREA, WHICH CONSISTS OF 'LOPVAR',   'LOPINC',
  815. ; 'LOPLMT', 'LOPLN', AND 'LOPPT'. IFF THERE IS ALREADY   SOME-
  816. ; THING IN THE SAVE AREA (THIS IS  INDICATED  BY  A   NON-ZERO
  817. ; 'LOPVAR'), THEN THE OLD SAVE AREA IS SAVED IN THE STACK  BE-
  818. ; FORE THE NEW ONE OVERWRITES IT.
  819. ;
  820. ; TBI WILL THEN DIG IN THE  STACK  AND  FIND  OUT IFF     THIS
  821. ; SAME VARIABLE WAS USED IN  ANOTHER  CURRENTLY  ACTIVE    FOR
  822. ; LOOP. IT THAT IS THE CASE THEN THE OLD 'FOR'   LOOP IS   DE-
  823. ; IVATED (PURGED FROM THE STACK).
  824. ;
  825. ; 'NEXT VAR' SERVES AS THE LOGICAL (NOT NECESSARILLY PHYSICAL)
  826. ; END OF THE 'FOR' LOOP. THE CONTROL VARIABLE VAR. IS  CHECKED
  827. ; WITH THE 'LOPVAR'. IFF THEY ARE NOT THE SAME, TBI DIGGS   IN
  828. ; THE STACK TO FIND THE RIGHT ONE  AND  PURGES  ALL THOSE THAT
  829. ; DID NOT MATCH. EITHER WAY, TBI THEN ADDS THE 'STEP' TO  THAT
  830. ; VARIABLE AND CHECKS THE RESULT WITH THE LIMIT.  IFF  IT   IS
  831. ; WITHIN THE LIMIT, CONTROL LOOPS BACK TO THE COMMAND  FOLLOW-
  832. ; ING THE 'FOR'. IFF OUTSIDE THE LIMIT, THE SAVE AREA IS PURG-
  833. ; ED AND EXECUTION CONTINUES.
  834. ;
  835. ;
  836. FOR:
  837.     CALL    PUSHA    ;SAVE THE OLD SAVE AREA
  838.     CALL    SETVAL    ;SET THE CONTROL VAR.
  839.     DEC    BX
  840.     MOV    [LOPVAR],BX    ;SAVE TGAT
  841.     MOV    BX,TAB5-1    ;USE 'EXEC' TO LOOK
  842.     JMP    EXEC    ;FOR THE WORD 'TO'
  843. FR1:
  844.     CALL    EXP    ;EVALUATE THE LIMIT
  845.     MOV    [LOPLMT],BX    ;SAVE THAT
  846.     MOV    BX,TAB6-1    ;USED 'EXEC' TO LOOK
  847.     JMP    EXEC    ;FOR THE WORD 'STEP'
  848. FR2:
  849.     CALL    EXP    ;FOUND IT, GET STEP
  850.     JP    FR4    ;FOUND IT, GET STEP
  851. FR3:
  852.     MOV    BX,1    ;NOT FOUND, SET TO ONE
  853. FR4:
  854.     MOV    [LOPINC],BX    ;SAVE THAT TOO
  855. FR5:
  856.     MOV    BX,[CURRNT]    ;SAVE CURRENT LINE #
  857.     MOV    [LOPLN],BX
  858.     XCHG    DX,BX    ;AND TEXT POINTER
  859.     MOV    [LOPPT],BX
  860.     MOV    CX,10    ;DIG INTO STACK TO
  861.     MOV    BX,[LOPVAR]    ;FIND 'LOPVAR'
  862.     XCHG    DX,BX
  863.     MOV    BX,CX    ;BX:=10 NOW
  864.     ADD    BX,SP
  865.     JP    FR7A
  866. FR7:
  867.     ADD    BX,CX
  868. FR7A:    MOV    AX,[BX]    ;GET THAT OLD 'LOPVAR'
  869.     OR    AX,AX
  870.     JZ    FR8    ;0 SAYS NO MORE IN IT
  871.     CMP    AX,DX    ;SAME AS THIS ONE?
  872.     JNZ    FR7
  873.     XCHG    DX,BX
  874.     MOV    BX,0    ;THE OTHER HALF?
  875.     ADD    BX,SP
  876.     MOV    CX,BX
  877.     MOV    BX,10
  878.     ADD    BX,DX
  879.     CALL    MVDOWN    ;AND PURGE 10 WORDS
  880.     XCHG    BX,SP        ;IN THE STACK
  881. FR8:
  882.     MOV    BX,[LOPPT]    ;JOB DONE, RESTORE DE
  883.     XCHG    DX,BX
  884.     CALL    FINISH    ;AND CONTINUE
  885.     ;
  886. NEXT:
  887.     CALL    TSTV    ;GET ADDR OF VAR
  888.     JNC    NX4    ;NO VARIABLE, "WHAT?"
  889.         JMP     QWHAT
  890. NX4:    MOV    [VARNXT],BX    ;YES, SAVE IT
  891. NX0:
  892.     PUSH    DX    ;SAVE TEXT POINTER
  893.     XCHG    DX,BX
  894.     MOV    BX,[LOPVAR]    ;GET VAR IN 'FOR'
  895.     MOV    AL,BH
  896.     OR    AL,BL    ;0 SAY NEVER HAD ONE
  897.     JNZ    NX5    ;SO WE ASK: "WHAT?"
  898.         JMP     AWHAT
  899. NX5:    CMP    DX,BX    ;ELSE WE CHECK THEM
  900.     JZ    NX3    ;OK, THEY AGREE
  901.     POP    DX    ;NO, LET'S SEE
  902.     CALL    POPA    ;PURGE CURRENT LOOP
  903.     MOV    BX,[VARNXT]    ;AND POP ONE LEVEL
  904.     JMP    NX0    ;GO CHECK AGAIN
  905. NX3:
  906.     MOV    DL,[BX]    ;COME HERE WHEN AGREED
  907.     INC    BX
  908.     MOV    DH,[BX]    ;DE = VAL OF VAR
  909.     MOV    BX,[LOPINC]
  910.     PUSH    BX
  911.     ADD    BX,DX
  912.     XCHG    DX,BX    ;ADD ONE STEP
  913.     MOV    BX,[LOPVAR]    ;PUT IT BACK
  914.     MOV    [BX],DL
  915.     INC    BX
  916.     MOV    [BX],DH
  917.     MOV    BX,[LOPLMT]    ;HL-> LIMIT
  918.     POP    AX
  919.     XCHG    AH,AL
  920.     OR    AX,AX
  921.     JNS    NX1    ;STEP > 0
  922.     XCHG    DX,BX
  923. NX1:
  924.     CALL    CKHLDE    ;COMPARE WITH LIMIT
  925.     POP    DX    ;RESTORE TEXT POINTER
  926.     JC    NX2    ;OUTSIDE LIMIT
  927.     MOV    BX,[LOPLN]    ;WITHIN LIMIT, GO
  928.     MOV    [CURRNT],BX    ;BACK TO THE SAVED
  929.     MOV    BX,[LOPPT]    ;'CURRNT' AND TEXT
  930.     XCHG    DX,BX    ;POINTER
  931.     CALL    FINISH    ;POINTER
  932. NX2:
  933.     CALL    POPA    ;PURGE THIS LOOP
  934.     CALL    FINISH
  935. ;
  936. ;
  937. ; ****REM**** AND ****IF**** AND ****LET*****
  938. ;
  939. ;
  940. ; 'REM' CAN BE FOLLOWED BY ANYTHING AND IS IGNORED BY TBI. TBI
  941. ; TREATS IT LIKE AN 'IF' WITH A FALSE CONDITION.
  942. ;
  943. ; 'IF' IS FOLLOWED BY AN EXPR. AS A CONDITION AND ONE OR  MORE
  944. ; COMMANDS (INCLUDING OTHER 'IF'S) SEPERATED  BY  SEMI-COLONS.
  945. ; NOTE THAT THE WORD 'THEN' IS NOT USED.  TBI  EVALUATES   THE
  946. ; EXPR. IFF IT IS NON-ZERO, EXECUTION CONTINUES. IFF THE EXPR.
  947. ; IS ZERO, THE COMMANDS THAT FOLLOW ARE IGNORED AND  EXECUTION
  948. ; CONTINUES AT THE NEXT LINE.
  949. ;
  950. ; 'IPUT' COMMANS IS LIKE THE 'PRINT' COMMAND, AND IS  FOLLOWED
  951. ; BY A LIST OF ITEMS. IFF THE ITEM IS A  STRING  IN  SINGLE OR
  952. ; DOUBLE QUOTES, OR IS A BACK-ARROW, IT HAS THE SAME EFFEDT AS
  953. ; PRINTED OUT FOLLOWED BY A COLON. THEN TBI WAITS FOR AN EXPR.
  954. ; TO BE TYPEN IN. THE VARIABLE IS THEN  SET  TO  THE  VALUE OF
  955. ; THIS EXPR. IFF THE VARIABLE IS PROCEDED BY A STRING  PRINTED
  956. ; FOLLOWED BY A COLON. TBI THEN WAITS FOR INPUT EXPR. AND SETS
  957. ; THE VARIABLE TO THE VALUE OF THE EXPR.
  958. ;
  959. ; IFF THE INPUT EXPR. IS INVALID,  TBI  WILL  PRINT  "WHAT?" ,
  960. ; "HOW?",OR "SORRY" AND REPRINT THE PROMPT AND REDO THE INPUT.
  961. ; THE EXECUTION WILL NOT TERMINATE UNLESS YOU TYPE CONTROL-C .
  962. ; THIS IS HANDLED IN 'INPERR'.
  963. ;
  964. ; 'LET' IS FOLLOWED BY A LIST OF ITEMS SEPERATED  BY  COMMAS .
  965. ; EACH ITEM CONSISTS OF A VARIABLE,  AN  EQUAL  SIGN,  AND  AN
  966. ; EXPR. TBI EVALUATES THE EXPR. AND SETS THE VARIABLE TO  THAT
  967. ; VALUE. TBI WILL ALSO HANDLE 'LET' COMMAND WITHOUT THE   WORD
  968. ; 'LET'. THIS IS DONE BY 'DEFLT'.
  969. ;
  970. ;
  971. ;
  972. REM:
  973.     MOV    BX,0    ;****REM****
  974.     JP    IFF1A    ;JUMP AROUND EXPR
  975.     ;
  976. IFF:
  977.     CALL    EXP    ;****IF****
  978. IFF1A:    CMP    BX,0    ;IS THE EXPR = 0?
  979.     JZ    IFF1    ;NO, CONTINUE
  980.         JMP     RUNSML
  981. IFF1:    CALL    FNDSKP    ;YES, SIKP REST OF LINE
  982.     JC    IFF2    ;YES, SIKP REST OF LINE
  983.         JMP     RUNTSL
  984. IFF2:    JMP    RSTART    ;YES, SIKP REST OF LINE
  985.     ;
  986. INPERR:
  987.     MOV    BX,[STKINP]    ;****INPERR****
  988.     XCHG    BX,SP        ;RESTORE OLD STACK POINTER
  989.     POP    BX    ;AND OLD 'CURRNT'
  990.     MOV    [CURRNT],BX
  991.     POP    DX
  992.     POP    DX    ;REDO INPUT
  993.     ;
  994. INPUT:    EQU    $    ;****INPUT****
  995. IP1:
  996.     PUSH    DX    ;SAVE IN CASE OF ERROR
  997.     CALL    QTSTG    ;IS NEXT ITEM A STRING?
  998.     JP    IP2    ;NO
  999.     CALL    TSTV    ;YES, BUT FOLLOWED BY A
  1000.     JC    IP4    ;VARIABLE? NO.
  1001.     JP    IP3    ;YES. INPUT VAR.
  1002. IP2:
  1003.     PUSH    DX    ;SAVE FOR 'PRTSTG'
  1004.     CALL    TSTV    ;MUST BE A VAR NOW
  1005.     JNC    IP2A    ;"WHAT" IT IS NOT!
  1006.         JMP     QWHAT
  1007. IP2A:    MOV    SI,DX
  1008.     LODB        ;GET READY FOR 'RTSTG'
  1009.     MOV    CL,AL
  1010.     SUB    AL,AL
  1011.     MOV    DI,DX
  1012.     STOB
  1013.     POP    DX
  1014.     CALL    PRTSTG    ;PRINT STRING AS PROMPT
  1015.     MOV    AL,CL
  1016.     DEC    DX
  1017.     MOV    DI,DX
  1018.     STOB
  1019. IP3:
  1020.     PUSH    DX
  1021.     XCHG    DX,BX
  1022.     MOV    BX,[CURRNT]    ;ALSO SAVE 'CURRNT'
  1023.     PUSH    BX
  1024.     MOV    BX,IP1
  1025.     MOV    [CURRNT],BX    ;NEG NUMBER AS FLAG
  1026.     MOV    [STKINP],SP
  1027.     PUSH    DX    ;OLD HL
  1028.     MOV    AL,':'    ;PRINT THIS TOO
  1029.     CALL    GETLN    ;AND GET A LINE
  1030. ②◆ג@≡p≥⓪'½⇦ó,⑥!*ú#"⌐⇦¥É('ñº*)É*'É!*ú#"⌐╱à⇦íáª&⇦ó¼(⇦¥ó½ ª*á¬"É$º(*¬╱à⇦º'¿⇦É⓪⓪⓪⓪⓪⓪⓪íáº⓪!"É③íáª&⓪"º"!ñ%ôåà⇦º'¿⇦É⇦¥íáº⓪!"É③íáª&⓪"º"!ñ%ôåà⇦º'¿⇦É⇦¥íáº⓪!"É③íáª&⓪"º"!ñ%ôåà⇦¿'¿⇦ó,⇦¥ºÑû#ó¬⓪'ª"⓪$&╱à⇦¼!ñ#äó,⑥!,⇦¥ºÑû#ó¬⓪'ª"⓪$&╱à⇦ªº½⇦¡í,.û",╱à⇦¿'¿⇦í,⇦¥úó¬⓪'ª"⓪③í¬⌐)'*③åà⇦ªº½⇦¡í¬⌐)'*.û!,╱à⇦¿'¿⇦ó,⇦¥áº"⓪#ó¬⓪'ª"⓪*"¼*⓪('ñº*"⌐╱à$¿ə╱à⇦¿'¿⇦á¼╱à⇦ªº½⇦áñ⑥③û③åà⇦íáª&⇦ñúº!&'%åà SO THAT EXECUTION CAN BE CONTINUED AFTER THE  SUBROUTINE
  1031. ; 'RETURN'. IN ORDER THAT 'GOSUB' CAN BE NESTED (AND EVEN RECUR-
  1032. ; SIVE), THE SAVE AREA MUST BE  STACKED.  THE  STACK  POINTER IS
  1033. ; SAVED IN 'STKGOS'. THE OLD 'STKGOS' IS SAVED IN THE STACK. IF
  1034. ; WE ARE IN THE MAIN ROUTINE, 'STKGOS' IS ZERO (THIS WAS DONE BY
  1035. ; THE "MAIN" SECTION OF THE CODE),  BUT  WE  STILL  SAVE  IT  AS
  1036. ; A FLAG FOR NO FURTHER RETURNS.
  1037. ;
  1038. ; 'RETURN(CR)' UNDOES EVERYTHING THAT 'GOSUB' DID, AND THUS  RE-
  1039. ; TURNS THE EXECUTION TO THE COMMAND AFTER THE MOST RECENT  'GO-
  1040. ; SUB'. IFF 'STKGOS' IS ZERO, IT INDICATES THAT WE NEVER  HAD  A
  1041. ; 'GOSUB' AND IS THUS AN ERROR.
  1042. ;
  1043. ;
  1044. GOSUB:
  1045.     CALL    PUSHA    ;SAVE THE CURRENT 'FOR'
  1046.     CALL    EXP    ;PARAMETERS
  1047.     PUSH    DX
  1048.     CALL    FNDLN    ;FIND THE TARGET LINE
  1049.     JZ    GS1    ;NOT THERE, SAY "HOW?"
  1050.         JMP     AHOW
  1051. GS1:    MOV    BX,[CURRNT]    ;FOUND IT, SAVE OLD
  1052.     PUSH    BX    ;'CURRNT' OLD 'STKGOS'
  1053.     MOV    BX,[STKGOS]
  1054.     PUSH    BX
  1055.     MOV    BX,0    ;AND LOAD NEW ONES
  1056.     MOV    [LOPVAR],BX
  1057.     ADD    BX,SP
  1058.     MOV    [STKGOS],BX
  1059.     JMP    RUNTSL    ;THEN RUN THAT LINE
  1060. RETURN:
  1061.     CALL    ENDCHK    ;THERE MUST BE A 0DH
  1062.     MOV    BX,[STKGOS]    ;OLD STACK POINTER
  1063.     OR    BX,BX
  1064.     JNZ    RET1    ;SO, WE SAY: "WHAT?"
  1065.         JMP     QWHAT
  1066. RET1:    XCHG    BX,SP        ;ELSE RESTORE IT
  1067.     POP    BX    ;ELSE RESTORE IT
  1068.     MOV    [STKGOS],BX    ;AND THE OLD 'STKGOS'
  1069.     POP    BX
  1070.     MOV    [CURRNT],BX    ;AND THE OLD 'CURRNT'
  1071.     POP    DX    ;OLD TEXT POINTER
  1072.     CALL    POPA    ;OLD "FOR" PARAMETERS
  1073.     CALL    FINISH    ;AND WE ARE BACK HOME
  1074. ;
  1075. ;
  1076. ; ****FOR**** AND ****NEXT****
  1077. ;
  1078. ;
  1079. ; 'FOR' HAS TWO FORMS:
  1080. ;    'FOR VAR=EXP1 TO EXP2 STEP EXP3'
  1081. ;    'FOR VAR=EXP1 TO EXP2'
  1082. ; THE SECOND FORM MEANS THE SAME AS THE FIRST FORM WITH EXP3=1.
  1083. ;
  1084. ; TBI WILL FIND THE VARIABLE VAR AND SET ITS VALUE TO THE CUR-
  1085. ; RENT VALUE OF EXP1. IT ALSO  EVALUATES  EXP2  AND  EXP3  AND
  1086. ; SAVES ALL OF THESE TOGETHER  WITH  THE  TEXT  POINTER ETC IN
  1087. ; THE 'FOR' SAVE AREA, WHICH CONSISTS OF 'LOPVAR',   'LOPINC',
  1088. ; 'LOPLMT', 'LOPLN', AND 'LOPPT'. IFF THERE IS ALREADY   SOME-
  1089. ; THING IN THE SAVE AREA (THIS IS  INDICATED  BY  A   NON-ZERO
  1090. ; 'LOPVAR'), THEN THE OLD SAVE AREA IS SAVED IN THE STACK  BE-
  1091. ; FORE THE NEW ONE OVERWRITES IT.
  1092. ;
  1093. ; TBI WILL THEN DIG IN THE  STACK  AND  FIND  OUT IFF     THIS
  1094. ; SAME VARIABLE WAS USED IN  ANOTHER  CURRENTLY  ACTIVE    FOR
  1095. ; LOOP. IT THAT IS THE CASE THEN THE OLD 'FOR'   LOOP IS   DE-
  1096. ; IVATED (PURGED FROM THE STACK).
  1097. ;
  1098. ; 'NEXT VAR' SERVES AS THE LOGICAL (NOT NECESSARILLY PHYSICAL)
  1099. ; END OF THE 'FOR' LOOP. THE CONTROL VARIABLE VAR. IS  CHECKED
  1100. ; WITH THE 'LOPVAR'. IFF THEY ARE NOT THE SAME, TBI DIGGS   IN
  1101. ; THE STACK TO FIND THE RIGHT ONE  AND  PURGES  ALL THOSE THAT
  1102. ; DID NOT MATCH. EITHER WAY, TBI THEN ADDS THE 'STEP' TO  THAT
  1103. ; VARIABLE AND CHECKS THE RESULT WITH THE LIMIT.  IFF  IT   IS
  1104. ; WITHIN THE LIMIT, CONTROL LOOPS BACK TO THE COMMAND  FOLLOW-
  1105. ; ING THE 'FOR'. IFF OUTSIDE THE LIMIT, THE SAVE AREA IS PURG-
  1106. ; ED AND EXECUTION CONTINUES.
  1107. ;
  1108. ;
  1109. FOR:
  1110.     CALL    PUSHA    ;SAVE THE OLD SAVE AREA
  1111.     CALL    SETVAL    ;SET THE CONTROL VAR.
  1112.     DEC    BX
  1113.     MOV    [LOPVAR],BX    ;SAVE TGAT
  1114.     MOV    BX,TAB5-1    ;USE 'EXEC' TO LOOK
  1115.     JMP    EXEC    ;FOR THE WORD 'TO'
  1116. FR1:
  1117.     CALL    EXP    ;EVALUATE THE LIMIT
  1118.     MOV    [LOPLMT],BX    ;SAVE THAT
  1119.     MOV    BX,TAB6-1    ;USED 'EXEC' TO LOOK
  1120.     JMP    EXEC    ;FOR THE WORD 'STEP'
  1121. FR2:
  1122.     CALL    EXP    ;FOUND IT, GET STEP
  1123.     JP    FR4    ;FOUND IT, GET STEP
  1124. FR3:
  1125.     MOV    BX,1    ;NOT FOUND, SET TO ONE
  1126. FR4:
  1127.     MOV    [LOPINC],BX    ;SAVE THAT TOO
  1128. FR5:
  1129.     MOV    BX,[CURRNT]    ;SAVE CURRENT LINE #
  1130.     MOV    [LOPLN],BX
  1131.     XCHG    DX,BX    ;AND TEXT POINTER
  1132.     MOV    [LOPPT],BX
  1133.     MOV    CX,10    ;DIG INTO STACK TO
  1134.     MOV    BX,[LOPVAR]    ;FIND 'LOPVAR'
  1135.     XCHG    DX,BX
  1136.     MOV    BX,CX    ;BX:=10 NOW
  1137.     ADD    BX,SP
  1138.     JP    FR7A
  1139. FR7:
  1140.     ADD    BX,CX
  1141. FR7A:    MOV    AX,[BX]    ;GET THAT OLD 'LOPVAR'
  1142.     OR    AX,AX
  1143.     JZ    FR8    ;0 SAYS NO MORE IN IT
  1144.     CMP    AX,DX    ;SAME AS THIS ONE?
  1145.     JNZ    FR7
  1146.     XCHG    DX,BX
  1147.     MOV    BX,0    ;THE OTHER HALF?
  1148.     ADD    BX,SP
  1149.     MOV    CX,BX
  1150.     MOV    BX,10
  1151.     ADD    BX,DX
  1152.     CALL    MVDOWN    ;AND PURGE 10 WORDS
  1153.     XCHG    BX,SP        ;IN THE STACK
  1154. FR8:
  1155.     MOV    BX,[LOPPT]    ;JOB DONE, RESTORE DE
  1156.     XCHG    DX,BX
  1157.     CALL    FINISH    ;AND CONTINUE
  1158.     ;
  1159. NEXT:
  1160.     CALL    TSTV    ;GET ADDR OF VAR
  1161.     JNC    NX4    ;NO VARIABLE, "WHAT?"
  1162.         JMP     QWHAT
  1163. NX4:    MOV    [VARNXT],BX    ;YES, SAVE IT
  1164. NX0:
  1165.     PUSH    DX    ;SAVE TEXT POINTER
  1166.     XCHG    DX,BX
  1167.     MOV    BX,[LOPVAR]    ;GET VAR IN 'FOR'
  1168.     MOV    AL,BH
  1169.     OR    AL,BL    ;0 SAY NEVER HAD ONE
  1170.     JNZ    NX5    ;SO WE ASK: "WHAT?"
  1171.         JMP     AWHAT
  1172. NX5:    CMP    DX,BX    ;ELSE WE CHECK THEM
  1173.     JZ    NX3    ;OK, THEY AGREE
  1174.     POP    DX    ;NO, LET'S SEE
  1175.     CALL    POPA    ;PURGE CURRENT LOOP
  1176.     MOV    BX,[VARNXT]    ;AND POP ONE LEVEL
  1177.     JMP    NX0    ;GO CHECK AGAIN
  1178. NX3:
  1179.     MOV    DL,[BX]    ;COME HERE WHEN AGREED
  1180.     INC    BX
  1181.     MOV    DH,[BX]    ;DE = VAL OF VAR
  1182.     MOV    BX,[LOPINC]
  1183.     PUSH    BX
  1184.     ADD    BX,DX
  1185.     XCHG    DX,BX    ;ADD ONE STEP
  1186.     MOV    BX,[LOPVAR]    ;PUT IT BACK
  1187.     MOV    [BX],DL
  1188.     INC    BX
  1189.     MOV    [BX],DH
  1190.     MOV    BX,[LOPLMT]    ;HL-> LIMIT
  1191.     POP    AX
  1192.     XCHG    AH,AL
  1193.     OR    AX,AX
  1194.     JNS    NX1    ;STEP > 0
  1195.     XCHG    DX,BX
  1196. NX1:
  1197.     CALL    CKHLDE    ;COMPARE WITH LIMIT
  1198.     POP    DX    ;RESTORE TEXT POINTER
  1199.     JC    NX2    ;OUTSIDE LIMIT
  1200.     MOV    BX,[LOPLN]    ;WITHIN LIMIT, GO
  1201.     MOV    [CURRNT],BX    ;BACK TO THE SAVED
  1202.     MOV    BX,[LOPPT]    ;'CURRNT' AND TEXT
  1203.     XCHG    DX,BX    ;POINTER
  1204.     CALL    FINISH    ;POINTER
  1205. NX2:
  1206.     CALL    POPA    ;PURGE THIS LOOP
  1207.     CALL    FINISH
  1208. ;
  1209. ;
  1210. ; ****REM**** AND ****IF**** AND ****LET*****
  1211. ;
  1212. ;
  1213. ; 'REM' CAN BE FOLLOWED BY ANYTHING AND IS IGNORED BY TBI. TBI
  1214. ; TREATS IT LIKE AN 'IF' WITH A FALSE CONDITION.
  1215. ;
  1216. ; 'IF' IS FOLLOWED BY AN EXPR. AS A CONDITION AND ONE OR  MORE
  1217. ; COMMANDS (INCLUDING OTHER 'IF'S) SEPERATED  BY  SEMI-COLONS.
  1218. ; NOTE THAT THE WORD 'THEN' IS NOT USED.  TBI  EVALUATES   THE
  1219. ; EXPR. IFF IT IS NON-ZERO, EXECUTION CONTINUES. IFF THE EXPR.
  1220. ; IS ZERO, THE COMMANDS THAT FOLLOW ARE IGNORED AND  EXECUTION
  1221. ; CONTINUES AT THE NEXT LINE.
  1222. ;
  1223. ; 'IPUT' COMMANS IS LIKE THE 'PRINT' COMMAND, AND IS  FOLLOWED
  1224. ; BY A LIST OF ITEMS. IFF THE ITEM IS A  STRING  IN  SINGLE OR
  1225. ; DOUBLE QUOTES, OR IS A BACK-ARROW, IT HAS THE SAME EFFEDT AS
  1226. ; PRINTED OUT FOLLOWED BY A COLON. THEN TBI WAITS FOR AN EXPR.
  1227. ; TO BE TYPEN IN. THE VARIABLE IS THEN  SET  TO  THE  VALUE OF
  1228. ; THIS EXPR. IFF THE VARIABLE IS PROCEDED BY A STRING  PRINTED
  1229. ; FOLLOWED BY A COLON. TBI THEN WAITS FOR INPUT EXPR. AND SETS
  1230. ; THE VARIABLE TO THE VALUE OF THE EXPR.
  1231. ;
  1232. ; IFF THE INPUT EXPR. IS INVALID,  TBI  WILL  PRINT  "WHAT?" ,
  1233. ; "HOW?",OR "SORRY" AND REPRINT THE PROMPT AND REDO THE INPUT.
  1234. ; THE EXECUTION WILL NOT TERMINATE UNLESS YOU TYPE CONTROL-C .
  1235. ; THIS IS HANDLED IN 'INPERR'.
  1236. ;
  1237. ; 'LET' IS FOLLOWED BY A LIST OF ITEMS SEPERATED  BY  COMMAS .
  1238. ; EACH ITEM CONSISTS OF A VARIABLE,  AN  EQUAL  SIGN,  AND  AN
  1239. ; EXPR. TBI EVALUATES THE EXPR. AND SETS THE VARIABLE TO  THAT
  1240. ; VALUE. TBI WILL ALSO HANDLE 'LET' COMMAND WITHOUT THE   WORD
  1241. ; 'LET'. THIS IS DONE BY 'DEFLT'.
  1242. ;
  1243. ;
  1244. ;
  1245. REM:
  1246.     MOV    BX,0    ;****REM**
  1247. POK2:    CALL    FINISH
  1248. PEEK:
  1249.     CALL    PARN
  1250.     MOV    BL,[BX]
  1251.     MOV    BH,0
  1252.     RET
  1253.     JMP    QWHAT
  1254. USR:
  1255.     PUSH    CX
  1256.     MOV    AH,'('
  1257.     CALL    IGNBLNK
  1258.     JNZ    QWT
  1259.     CALL    EXP    ;EXPR
  1260.     MOV    AH,')'
  1261.     CALL    IGNBLNK    ;EXPR
  1262.     JNZ    PASPRM
  1263.     PUSH    DX
  1264.     MOV    DX,USRET
  1265.     PUSH    DX
  1266.     PUSH    BX
  1267.     RET    ;CALL USR ROUTINE
  1268. PASPRM:
  1269.     MOV    AH,','
  1270.     CALL    IGNBLNK
  1271.     JNZ    USRET1
  1272.     PUSH    BX
  1273.     CALL    EXP
  1274.     MOV    AH,')'
  1275.     CALL    IGNBLNK
  1276.     JNZ    USRET1
  1277.     POP    CX
  1278.     PUSH    DX
  1279.     MOV    DX,USRET
  1280.     PUSH    DX
  1281.     PUSH    CX
  1282.     RET    ;CALL USR ROUTINE
  1283. USRET:
  1284.     POP    DX
  1285. USRET1:    POP    CX
  1286.     RET
  1287. QWT:    JMP    QWHAT
  1288. ;
  1289. ;
  1290. ; ****DIVIDE**** AND ****CHKSGN****
  1291. ; ****CHKSGN**** AND ****CKHLDE****
  1292. ;
  1293. ;
  1294. ; 'DIVIDE DIVIDES BX BY DX, RESULT IN CX, REMAINDER IN BX
  1295. ;
  1296. ; 'CHKSGN' CHECKS SIGN OF BX. IFF +, NO CHANGE. IFF -, CHANGE
  1297. ;    SIGN AND FLIP SIGN OF C
  1298. ;
  1299. ; 'CHGSGN' CHANGES SIGN OF BX AND CL UNCONDITIONALLY.
  1300. ;
  1301. ; 'CKHLDE' CHECK SIGN OF BX AND DX. IFF DIFFERENT, BX AND DX
  1302. ; ARE INTERCHANGED. IFF SAME SIGN, NOT INTERCHANGED.   EITHER
  1303. ; CASE, BX AND DX ARE THEN COMPARED TO SET THE FLAGS.
  1304. ;
  1305. ;
  1306. DIVIDE:
  1307.     PUSH    DX    ;PRESERVE DX ACCROSS CALL
  1308.     PUSH    DX
  1309.     XOR    DX,DX
  1310.     POP    CX
  1311.     MOV    AX,BX
  1312.     IDIV    AX,CX
  1313.     MOV    CX,AX    ;QUOTIENT
  1314.     MOV    BX,DX    ;REMAINDER
  1315.     POP    DX    ;DX RESTORED
  1316.     RET
  1317.     ;
  1318. CHKSGN:
  1319.     OR    BX,BX    ;SET FLAGS TO CHECK SIGN
  1320.     JNS    RET    ;IFF -, CHANGE SIGN
  1321.     ;
  1322. CHGSGN:
  1323.     NOT    BX    ;****CHGSGN****
  1324.     INC    BX
  1325.     XOR    CH,128
  1326.     RET
  1327.     ;
  1328. CKHLDE:
  1329.     MOV    AL,BH
  1330.     XOR    AL,DH    ;SAME SIGN?
  1331.     JNS    CK1    ;YES, COMPARE
  1332.     XCHG    DX,BX
  1333. CK1:
  1334.     CMP    BX,DX
  1335.     RET
  1336. ;
  1337. ;
  1338. ; ****SETVAL**** AND ****FIN**** AND ****ENDCHK****
  1339. ; ****ERROR**** AND FRIENDS
  1340. ;
  1341. ;
  1342. ; 'SETVAL' EXPECTS A VARIABLE, FOLLOWED BY AN EQUAL SIGN AND
  1343. ; THEN AN EXPR. IT EVALUATES THE EXPR AND SETS THE  VARIABLE
  1344. ; TO THAT VALUE.
  1345. ;
  1346. ; 'FIN' CHECKS THE END OF A COMMAND. IFF IT ENDED WITH ";" ,
  1347. ; EXECUTION CONTINUES. IFF IT ENDED WITH A CR, IT FINDS  THE
  1348. ; NEXT LINE AND CONTINUES FROM THERE.
  1349. ;
  1350. ; 'ENDCHK' CHECKS IFF A COMMAND IS ENDED WITH A CR, THIS  IS
  1351. ; REQUIRED IN CERTAIN COMMANDS. (GOTO, RETURN, AND STOP,ETC)
  1352. ;
  1353. ; 'ERROR' PRINTS THE STRING POINTED BY DX (AND ENDS  WITH  A
  1354. ; CR). IT THEN PRINTS THE LINE POINTED BY 'CURRNT' WITH A ?.
  1355. ; INSERTED AT WHERE THE OLD TEXT POINTER (SHOULD  BE  ON TOP
  1356. ; OF THE STACK) POINTS TO. EXECUTION OF TB IS  STOPPED   AND
  1357. ; TBI IS RESTARTED. HOWEVER, IFF 'CURRNT' -> ZERO (INDICAT -
  1358. ; ING A DIRECT COMMAND), THE DIRECT COMMAND IS NOT PRINTED ,
  1359. ; AND IFF 'CURRNT' -> NEGATIVE # (INDICATING 'INPUT' COMMAND
  1360. ; THE INPUT LINE IS NOT PRINTED AND EXECUTION IS NOT TERMIN-
  1361. ; ATED BUR CONTINUED AT 'INPERR').
  1362. ;
  1363. ; RELATED TO 'ERROR' ARE THE FOLLOWING:
  1364. ;
  1365. ;    'QWHAT' SAVES TEXT POINTER IN STACK AND GETS MESSAGE
  1366. ;        "WHAT?"
  1367. ;    'AWHAT'    JUST GETS MESSAGE "WHAT?" AND JUMPS TO ERROR
  1368. ;
  1369. ;    'QSORRY' AND 'ASORRY' DO THE SAME KIND OF THING.
  1370. ;
  1371. ;    'QHOW' AND 'AHOW' IN THE ZERO PAGE SECTION ALSO   DO
  1372. ;        THIS.
  1373. ;
  1374. ;
  1375. SETVAL:
  1376.     CALL    TSTV    ;SEE IT IT'S A VARIABLE
  1377.     JC    QWHAT    ;"WHAT" NO VARIABLE
  1378.     PUSH    BX    ;SAVE ADDR OF VARIABLE
  1379.     MOV    AH,'='
  1380.     CALL    IGNBLNK
  1381.     JNZ    SV1
  1382.     CALL    EXP
  1383.     MOV    CX,BX    ;VALUE IN CX NOW
  1384.     POP    BX    ;GET ADDR
  1385.     MOV    [BX],CL    ;SAVE VALUE
  1386.     INC    BX
  1387.     MOV    [BX],CH    ;SAVE VALUE
  1388.     RET
  1389. SV1:
  1390.     JMP    QWHAT    ;NO '=' SIGN
  1391.     ;
  1392. FIN:
  1393.     MOV    AH,';'
  1394.     CALL    IGNBLNK
  1395.     JNZ    FI1
  1396.     POP    AX
  1397.     JMP    RUNSML
  1398. FI1:
  1399.     MOV    AH,0DH
  1400.     CALL    IGNBLNK
  1401.     JNZ    RET
  1402.     POP    AX
  1403.     JMP    RUNNXL    ;RUN NEXT LINE
  1404. FI2:
  1405.     RET    ;ELSE RETURN TO CALLER
  1406.     ;
  1407. ENDCHK:
  1408.     MOV    AH,0DH    ;END WITH CR?
  1409.     CALL    IGNBLNK
  1410.     JZ    RET    ;OK, ELSE SAY "WHAT?"
  1411.     ;
  1412. QWHAT:
  1413.     PUSH    DX    ;****QWHAT****
  1414. AWHAT:
  1415.     MOV    DX,WHAT    ;****AWHAT****
  1416. ERROR:
  1417.     SUB    AL,AL    ;****ERROR****
  1418.     CALL    PRTSTG    ;PRINT 'WHAT?','HOW?'
  1419.     POP    DX
  1420.     MOV    SI,DX
  1421.     LODB
  1422.     PUSH    AX    ;SAVE THE CHARACTER
  1423.     SUB    AL,AL    ;AND PUT A ZERO THERE
  1424.     MOV    DI,DX
  1425.     STOB
  1426.     MOV    BX,[CURRNT]    ;GET CURRENT LINE #
  1427.     CMP    W,[CURRNT],0    ;DIRECT COMMAND?
  1428.     JNZ    ERR1    ;IFF ZERO, JUST RESTART
  1429.     JP    ERR2    ;SAVE A BYTE
  1430. ERR1:    MOV    AL,[BX]    ;IFF NEGATIVE,
  1431.     OR    AL,AL
  1432.     JNS    ERR1A
  1433.     JMP    INPERR    ;REDO INPUT
  1434. ERR1A:    CALL    PRTLN    ;ELSE PRINT THE LINE
  1435.     DEC    DX
  1436.     POP    AX
  1437.     MOV    DI,DX
  1438.     STOB    ;RESTORE THE CHAR
  1439.     MOV    AL,63    ;PRINT A '?'
  1440.     CALL    CHROUT
  1441.     SUB    AL,AL    ;AND THE REST OF THE
  1442.     CALL    PRTSTG    ;LINE
  1443. ERR2:    JMP    RSTART    
  1444. QSORRY:
  1445.     PUSH    DX    ;****QSORRY****
  1446. ASORRY:
  1447.     MOV    DX,SORRY    ;****ASORRY****
  1448.     JP    ERROR
  1449. ;
  1450. ;
  1451. ; ****GETLN**** AND ****FNDLN****
  1452. ;
  1453. ;
  1454. ; 'GETLN' READS AN INPUT LINE INTO 'BUFFER'. IT FIRST PROMPTS
  1455. ; THE CHARACTER IN A (GIVEN BY THE CALLER), THEN IT FILLS THE
  1456. ; BUFFER AND ECHOS IT. IT USES BDOS PRIMITIVES TO  ACCOMPLISH
  1457. ; THIS. ONCE A FULL LINE IS READ IN, 'GETLN' RETURNS.
  1458. ;
  1459. ; 'FNDLN' FINDS A LINE WITH A GIVEN LINE #(IN BX) IN THE TEXT
  1460. ; SAVE AREA. DX IS USED AS THE TEXT POINTER. IFF THE LINE  IS
  1461. ; FOUND, DX WILL POINT TO THE BEGINNING OF THAT LINE IFF THAT
  1462. ; LINE (I.E. THE LOW BYTE OF THE LINE #), AND FLAGS ARE NC&Z.
  1463. ; IFF THAT LINE IS NOT THERE AND A LINE WITH A HIGHER LINE  #
  1464. ; IS FOUND, DX POINTS TO THERE AND FLAGS ARE NC&NZ.  IFF   WE
  1465. ; REACHED THE END OF TEXT SAVE AREA AND CANNOT FIND THE LINE,
  1466. ; FLAGS ARE C&NZ.
  1467. ; 'FNDLN' WILL INITIALIZE DX TO THE  BEGINNING  OF  THE  TEXT
  1468. ; SAVE AREA TO START THE SEARCH. SOME OTHER ENTRIES  OF  THIS
  1469. ; ROUTINE WILL NOT INITIALIZE DX AND DO THE SEARCH.
  1470. ;
  1471. ; 'FNDLNP' WILL START WITH DX AND SEARCH FOR THE LINE #.
  1472. ;
  1473. ; 'FNDNXT' WILL BUMP DX BY  2, FIND A 0DH AND THEN START  THE
  1474. ;    SEARCH.
  1475. ; 'FNDSKP' USES DX TO FIND A CR, AND THEN STARTS THE SEARCH.
  1476. ;
  1477. ;
  1478. ;
  1479. GETLN:
  1480.     CALL    CHROUT    ;****GETLN****
  1481. GL1:
  1482.     MOV    DX,BUFFER-2
  1483.     PUSH    DX
  1484.     MOV    AH,BCONIN ;BUFFERED CONSOLE INPUT
  1485.     INT    33    ;CALL MS-DOS
  1486.     POP    DX
  1487.     ADD    DL,[BUFFER-1]
  1488.     INC    DX
  1489.     INC    DX
  1490.     INC    DX
  1491.     MOV    DI,DX    ;FOR CONSISTANCY
  1492.     PUSH    DX
  1493.     CALL    CRLF    ;NEED CRLF
  1494.     POP    DX
  1495.     RET    ;WE'VE GOT A LINE
  1496. ;
  1497. ; AT ENTRY BX -> LINE # TO BE FOUND
  1498. ;
  1499. FNDLN:
  1500.     OR    BX,BX    ;CHECK SIGN OF BX
  1501.     JNS    FND1    ;IT CAN'T BE -
  1502.     JMP    QHOW    ;ERROR
  1503. FND1:    MOV    DX,TXTBGN
  1504.     ;
  1505. FNDLNP:
  1506. FL1:
  1507.     PUSH    BX    ;SAVE LINE #
  1508.     MOV    BX,[TXTUNF]    ;CHECK IFF WE PASSED END
  1509.     DEC    BX
  1510.     CMP    BX,DX    ;SUBSTITUTE FOR CALL 4
  1511.     POP    BX    ;GET LINE # BACK
  1512.     JC    RET    ;C, NZ PASSED END
  1513.     MOV    SI,DX
  1514.     LODW
  1515.     CMP    AX,BX
  1516.     JC    FL2
  1517.     RET    ;NC,Z:FOUND;NC,NZ:NOT FOUND
  1518.     ;
  1519. FNDNXT:                 ;****FNDNXT****
  1520.     INC    DX
  1521. FL2:
  1522.     INC    DX
  1523.     ;
  1524. FNDSKP:
  1525.     MOV    SI,DX
  1526.     LODB    ;****FNDSKP****
  1527.     CMP    AL,0DH    ;TRY TO FIND CR
  1528.     JNZ    FL2    ;KEEP LOOKING
  1529.     INC    DX
  1530.     JP    FL1    ;CHECK IFF END OF TEXT
  1531. ;
  1532. ;
  1533. ; **** PRTSTG **** QTSTG **** PRTNUM **** PRTLN ****
  1534. ;
  1535. ;
  1536. ; 'PRTSTG PRINTS A STRING POINTED TO BY DX. IT STOPS PRINTING
  1537. ; AND RETURNS TO CALLER WHEN EITHER A 0DH IS PRINTED OR  WHEN
  1538. ; THE NEXT BYTE IS THE SAMES AS WHAT WAS IN A  ( GIVEN BY THE
  1539. ; CALLER). OLD AL IS STORED IN CH, OLD CH IS LOST.
  1540. ;
  1541. ; 'QTSTG' LOOKS FOR A BACK-SLASH,  SINGLE QUOTE,   OR  DOUBLE
  1542. ; QUOTE. IFF NONE OF THESE, RETURN TO CALLER. IF BACK SLASH \
  1543. ; OUTPUT A ODH WITHOUT A LF. IFF SINGLE OR DOUBLE QUOTE,PRINT
  1544. ; THE STRING IN THE QUOTE AND DEMANDS A MATCHING UNQUOTE. AF-
  1545. ; TER THE PRINTING THE NEXT 3 BYTES OF THE CALLER  IS SKIPPED
  1546. ; OVER (USUALLY A JMP INSTRUCTION).
  1547. ;
  1548. ; 'PRTNUM' PRINTS THE NUMBER IN HL. LEADING BLANKS  ARE ADDED
  1549. ; IFF NEEDED TO PAD THE NUMBER OF SPACES TO THE NUMBER IN  C.
  1550. ; NOWEVER, IFF THE NUMBER OF DIGITS IS LARGER THAN THE NUMBER
  1551. ; IN C, ALL DIGITS ARE PRINTED ANYWAY. NEGATIVE SIGN IS  ALSO
  1552. ; PRINTED AND COUNTED IN, POSITIVE SIGN IS NOT.
  1553. ;
  1554. ; 'PRTLN' PRINTS A SAVED TEXT LINE WITH LINE # AND ALL.
  1555. ;
  1556. ;
  1557. ;
  1558. PRTSTG:
  1559.     MOV    CH,AL    ;****PRTSTG****
  1560. PS1:
  1561.     MOV    SI,DX
  1562.     LODB    ;GET A CHAR
  1563.     LAHF            ;PRESERVE FLAGS
  1564.     INC    DX
  1565.     SAHF            ;RESTORE FLAGS
  1566.     CMP    AL,CH    ;SAME AS OLD A?
  1567.     JNZ    PS2    ;YES, RETURN
  1568.         RET
  1569. PS2:    CALL    CHROUT    ;ELSE, PRINT IT
  1570.     CMP    AL,0DH    ;WAS IT A CR?
  1571.     JNZ    PS1    ;NO, NEXT
  1572.     RET
  1573.     ;
  1574. QTSTG:
  1575.     MOV    AH,'"'
  1576.     CALL    IGNBLNK
  1577.     JNZ    QT3
  1578.     MOV    AL,34    ;IT IS A '"'
  1579. QT1:
  1580.     CALL    PRTSTG    ;PRINT UNTIL ANOTHER
  1581.     CMP    AL,0DH    ;WAS LAST ONE A CR?
  1582.     POP    BX    ;RETURN ADDRESS
  1583.     JNZ    QT2    ;WAS CR, RUN NEXT LINE
  1584.         JMP     RUNNXL
  1585. QT2:
  1586.     INC    BX    ;SKIPS TWO BYTES ON RETURN!!!!
  1587.     INC    BX
  1588.     JMP    BX    ;JUMP TO ADDRESS IN BX
  1589. QT3:
  1590.     MOV    AH,39    ;IS IT A SINGLE QUOTE (')?
  1591.     CALL    IGNBLNK
  1592.     JNZ    QT4
  1593.     MOV    AL,39    ;YES, DO SAME
  1594.     JP    QT1    ;AS IN ' " '
  1595. QT4:
  1596.     MOV    AH,'\'
  1597.     CALL    IGNBLNK    ;IS IT BACK-SLASH?('\')
  1598.     JNZ    QT5
  1599.     MOV    AL,141    ;YES, 0DH WITHOUT LF!
  1600.     CALL    CHROUT    ;DO IT TWICE
  1601.     CALL    CHROUT    ;TO GIVE TTY ENOUGH TIME
  1602.     POP    BX    ;RETURN ADDRESS
  1603.     JP    QT2
  1604. QT5:
  1605.     RET        ;NONE OF THE ABOVE
  1606.     ;
  1607. ; ON ENTRY BX = BINARY #,CL = # SPACES
  1608. ;
  1609. PRTNUM:
  1610.     PUSH    DX    ;****PRTNUM****
  1611.     MOV    DX,10    ;DECIMAL
  1612.     PUSH    DX    ;SAVE AS A FLAG
  1613.     MOV    CH,DH    ;CH=SIGN
  1614.     DEC    CL    ;CL=SPACES
  1615.     CALL    CHKSGN    ;CHECK SIGN
  1616.     JNS    PN1    ;NO SIGN
  1617.     MOV    CH,45    ;CH=SIGN
  1618.     DEC    CL    ;'-' TAKES SPACE
  1619. PN1:
  1620.     PUSH    CX    ;SAVE SIGN % SPACE
  1621. PN2:
  1622.     CALL    DIVIDE    ;DIVIDE BX BY 10 (IN DX)
  1623.     OR    CX,CX    ;CX HAS QUOTIENT
  1624.     JZ    PN3    ;YES, WE GOT ALL
  1625.     POP    AX    ;GET SIGN AND SPACE COUNT
  1626.     PUSH    BX    ;SAVE REMAINDER
  1627.     DEC    AL    ;DEC SPACE COUNT
  1628.     PUSH    AX    ;SAVE NEW SIGN AND SPACE COUNT
  1629.     MOV    BX,CX    ;MOVE RESULT TO BX
  1630.     JP    PN2    ;AND DIVIDE BY 10
  1631. PN3:
  1632.     POP    CX    ;WE GOT ALL DIGITS IN
  1633. PN4:
  1634.     DEC    CL    ;THE STACK
  1635.     MOV    AL,CL    ;LOOK AT SPACE COUNT
  1636.     OR    AL,AL
  1637.     JS    PN5    ;NO LEADING BLANKS
  1638.     MOV    AL,32    ;LEADING BLANKS
  1639.     CALL    CHROUT
  1640.     JP    PN4
  1641. PN5:
  1642.     MOV    AL,CH    ;PRINT SIGN
  1643.     CALL    CHROUT    ;MAYBE, OR NULL
  1644.     MOV    DL,BL    ;LAST REMAINDER IN E
  1645. PN6:
  1646.     MOV    AL,DL    ;CHECK DIGIT IN E
  1647.     CMP    AL,10    ;10 IS FLAG FOR NO MORE
  1648.     POP    DX
  1649.     JZ    RET    ;IFF SO, RETURN
  1650.     ADD    AL,48    ;ELSE CONVERT TO ASCII
  1651.     CALL    CHROUT    ;AND PRINT THE DIGIT
  1652.     JP    PN6    ;GO BACK FOR MORE
  1653.     ;
  1654. PRTLN:
  1655.     MOV    SI,DX
  1656.     LODW
  1657.     MOV    BX,AX
  1658.     INC    DX
  1659.     INC    DX    ;MOVE POINTER
  1660. PRTLN1:    MOV    CL,5    ;PRINT 5 DIGIT LINE #
  1661.     CALL    PRTNUM
  1662.     MOV    AL,32    ;FOLLOWED BY A BLANK
  1663.     CALL    CHROUT
  1664.     SUB    AL,AL    ;AND THEN THE TEXT
  1665.     CALL    PRTSTG
  1666.     RET
  1667. ;
  1668. ;
  1669. ;
  1670. ; **** MVUP **** MVDOWN **** POPA **** PUSHA ****
  1671. ;
  1672. ; 'MVUP' MOVES A BLOCK UP FROM WHERE DX -> WHERE CX -> UNTIL
  1673. ; DX = BX
  1674. ;
  1675. ; 'MVDOWN' MOVES A BLOCK DOWN FROM WHERE DX -> TO WHERE BX->
  1676. ; UNTIL DX = CX.
  1677. ;
  1678. ; 'POPA' RESTORES THE 'FOR' LOOP VAR SAVE AREA FROM THE STACK.
  1679. ;
  1680. ; 'PUSHA' STACKS THE 'FOR' LOOP VARIABLE SAVE AREA IN THE STACK
  1681. ;
  1682. ;
  1683. MVUP:
  1684.     CMP    DX,BX    ;***MVUP***
  1685.     JZ    RET    ;DE = HL, RETURN
  1686.     MOV    SI,DX
  1687.     LODB    ;GET ONE BYTE
  1688.     MOV    DI,CX
  1689.     STOB    ;MOVE IT
  1690.     INC    DX
  1691.     INC    CX
  1692.     JP    MVUP    ;UNTIL DONE
  1693.     ;
  1694. MVDOWN:
  1695.     CMP    DX,CX
  1696.     JZ    RET    ;YES, RETURN
  1697. MD1:
  1698.     LAHF
  1699.     DEC    DX
  1700.     DEC    BX
  1701.     MOV    SI,DX
  1702.     LODB    ;BOTH POINTERS AND
  1703.     MOV    [BX],AL    ;THEN DO IT
  1704.     JP    MVDOWN    ;LOOP BACK
  1705.     ;
  1706. POPA:
  1707.     POP    CX    ;CX = RETURN ADDR
  1708.     POP    BX    ;RESTORE LOPVAR, BUT
  1709.     MOV    [LOPVAR],BX    ;=0 MEANS NO MORE
  1710.     OR    BX,BX
  1711.     JZ    PP1    ;YES, GO RETURN
  1712.     POP    BX    ;NO, RESTORE OTHERS
  1713.     MOV    [LOPINC],BX
  1714.     POP    BX
  1715.     MOV    [LOPLMT],BX
  1716.     POP    BX
  1717.     MOV    [LOPLN],BX
  1718.     POP    BX
  1719.     MOV    [LOPPT],BX
  1720. PP1:
  1721.     PUSH    CX    ;CX = RETURN ADDR
  1722.     RET
  1723.     ;
  1724. PUSHA:
  1725.     MOV    BX,STKLMT    ;****PUSHA****
  1726.     CALL    CHGSGN
  1727.     POP    CX    ;CX=RET ADDR
  1728.     ADD    BX,SP
  1729.     JC    PUSHB    ;YES, SORRY FOR THAT.
  1730.         JMP     QSORRY
  1731. PUSHB:    MOV    BX,[LOPVAR]    ;ELSE SAVE LOOP VARS
  1732.     OR    BX,BX    ;THAT WILL BE ALL
  1733.     JZ    PU1
  1734.     MOV    BX,[LOPPT]    ;ELSE, MORE TO SAVE
  1735.     PUSH    BX
  1736.     MOV    BX,[LOPLN]    ;ELSE, MORE TO SAVE
  1737.     PUSH    BX
  1738.     MOV    BX,[LOPLMT]
  1739.     PUSH    BX
  1740.     MOV    BX,[LOPINC]
  1741.     PUSH    BX
  1742.     MOV    BX,[LOPVAR]
  1743. PU1:
  1744.     PUSH    BX
  1745.     PUSH    CX    ;CX = RETURN ADDR
  1746.     RET
  1747.     ;
  1748.     ;
  1749.     ; **** OUTC **** CHKIO ****
  1750.     ;
  1751.     ;
  1752.     ; THESE ARE THE ONLY I/O ROUTINES IN TBI.
  1753.     ;
  1754.     ;
  1755.     ; 'CHKIO' CHECKS THE INPUT, IFF NO INPUT, IT WILL RETURN TO  THE
  1756.     ; CALLER WITH THE Z FLAG SET. IFF THERE IS INPUT, THE Z FLAG  IS
  1757.     ; CLEARED AND THE INPUT BYRE IS IN A. HOWEVER, IFF THE INPUT  IS
  1758.     ; A CONTROL-O, THE 'OCSW' IS COMPLIMENTED, AND THE Z FLAG IS RE-
  1759.     ; TURNED. IFF A CONTROL-C IS READ, 'CHKIO' WILL RESTART TBI  AND
  1760.     ; DOES NOT RETURN TO THE CALLER.
  1761.     ;
  1762. CRLF:    MOV    AL,0DH    ;****CRLF****
  1763. CHROUT:
  1764.     CMP    [OCSW],0
  1765.     JZ    COUT1    ;SEE IF OUTPUT REDIRECTED
  1766.     PUSH    CX    ;SAVE CX ON STACK
  1767.     PUSH    DX    ;AND DX
  1768.     PUSH    BX    ;AND BX TOO
  1769.     MOV    [OUTCAR],AL    ;SAVE CHATACTER
  1770.     MOV    DL,AL    ;PUT CHAR IN E FOR CP/M
  1771.     MOV    AH,CONOUT ;CONSOLE OUTPUT
  1772.     INT    33    ;CALL MS-DOS AND OUTPUT CHAR
  1773.     MOV    AL,[OUTCAR]    ;GET CHAR. BACK
  1774.     CMP    AL,0DH    ;WAS IT A 'CR'?
  1775.     JNZ    DONE    ;NO,DONE
  1776.     MOV    DL,0AH    ;GET LINEFEED
  1777.     MOV    AH,CONOUT ;CONSOLE OUTPUT AGAIN
  1778.     INT    33    ;CALL MS-DOS
  1779. DONE:
  1780.     MOV    AL,[OUTCAR]    ;GET CHAR BACK
  1781. IDONE:
  1782.     POP    BX    ;GET H BACK
  1783.     POP    DX    ;AND D
  1784.     POP    CX    ;THEN H
  1785.     RET    ;DONE AT LAST
  1786. COUT1:
  1787.     CMP    B,AL,0    ;IS IT NULL?
  1788.     JZ    RET    ;SKIP IT
  1789.     STOB        ;STORE AL (CHAR) IN BUFFER
  1790.     INC    [BUFFER-1] ;INCREMENT COUNTER
  1791.     RET        ;DONE
  1792. CHKIO:
  1793.     PUSH    CX    ;SAVE B ON STACK
  1794.     PUSH    DX    ;AND D
  1795.     PUSH    BX    ;THEN H
  1796.     MOV    AH,CONST ;GET CONSOLE STATUS WORD
  1797.     INT    33    ;CALL MS-DOS
  1798.     OR    AL,AL    ;SET FLAGS
  1799.     JNZ    CI1    ;IF READY, GET CHAR
  1800.     JP    IDONE    ;RESTORE AND RETURN
  1801. CI1:
  1802.     MOV    AH,1    ;CALL THE BDOS
  1803.     INT    33    ;CALL MS-DOS
  1804. CI2:
  1805.     CMP    AL,18H    ;IS TI CONTROL-X?
  1806.     JNZ    IDONE    ;RETURN AND RESTORE IF NOT
  1807.     JMP    RSTART    ;YES, RESTART TBI
  1808. LSTROM:    EQU    $    ;ALL ABOVE CAN BE ROM
  1809. OUTIO:
  1810.     OUTB    0FFH
  1811.     RET
  1812. WAITIO:
  1813.     INB    0FFH
  1814.     XOR    AL,BH
  1815.     AND    AL,BL
  1816.     JZ    WAITIO
  1817.     CALL    FINISH
  1818. INPIO:
  1819.     INB    0FFH
  1820.     MOV    BL,AL
  1821.     RET
  1822.     ;
  1823. ;
  1824. ; IGNBLNK
  1825. ;
  1826. ;    DEBLANKS WHERE DX->
  1827. ;    IF (DX)=AH THEN DX:=DX+1
  1828. ;
  1829. IGNBLNK:MOV    SI,DX
  1830. IGN1:   LODB            ;GET CHAR IN AL
  1831.     CMP    AL,32    ;IGNORE BLANKS
  1832.     JNZ    IGN2    ;IN TEXT (WHERE DX ->)
  1833.         INC     DX
  1834.         JP      IGN1
  1835. IGN2:    CMP    AL,AH    ;IS SEARCH CHARACTER FOUND AT (DX)?
  1836.     JNZ    RET    ;NO, RETURN, POINTER (DX) STAYS
  1837.     LAHF        ;SAVE RESULTS OF COMPARISON
  1838.     INC    DX    ;INC POINTER IF CHARACTER MATCHES
  1839.     SAHF        ;RETURN RESULT OF COMPARISON TO FLAGS
  1840.     RET
  1841.     ;
  1842. FINISH:    POP    AX
  1843.     CALL    FIN    ;CHECK END OF COMMAND
  1844.     JMP    QWHAT    ;PRINT "WHAT?" IFF WRONG
  1845.     ;
  1846. OUTCAR:
  1847.     DB    0    ;OUTPUT CHAR STORAGE
  1848. OCSW:
  1849.     DB    0FFH    ;OUTPUT SWITCH
  1850. CURRNT:
  1851.     DW    0    ;POINTS TO CURRENT LINE
  1852. STKGOS:
  1853.     DW    0    ;SAVES SP IN 'GOSUB'
  1854. VARNXT:
  1855.     DW    0    ;TEMP STORAGE
  1856. STKINP:
  1857.     DW    0    ;SAVES SP IN 'INPUT'
  1858. LOPVAR:
  1859.     DW    0    ;'FOR' LOOP SAVE AREA
  1860. LOPINC:
  1861.     DW    0    ;INCREMENT
  1862. LOPLMT:
  1863.     DW    0    ;LIMIT
  1864. LOPLN:
  1865.     DW    0    ;LINE NUMBER
  1866. LOPPT:
  1867.     DW    0    ;TEST POINTER
  1868. RANPNT:
  1869.     DW    0    ;RANDOM NUMBER POINTER
  1870. TXTUNF:
  1871.     DW    TXTBGN    ;-> UNFILLED TEXT AREA
  1872. TXTBGN:    DS    1
  1873. MSG1:    DB    '8086 TINY BASIC V1.1 27 JUNE 82',0DH
  1874.     ORG    2000H    ;MISC STORAGE, INCLUDING STACK
  1875. TXTEND:    EQU    $    ;TEST AREA SAVE AREA ENDS
  1876. VARBGN:
  1877.     DS    54    ;VARIABLE @(0)
  1878.     DB    80    ;MAX CHARS IN BUFFER
  1879.     DB    0    ;CHAR COUNT
  1880. BUFFER:
  1881.     DS    80    ;BUFFER MUST BE AFTER TEXT AREA
  1882. BUFEND:    EQU    $
  1883.     DS    400    ;EXTRA BYTES FOR STACK
  1884. STKLMT:    DS    100    ;TOP LIMIT FOR STACK
  1885. STACK:    EQU    $    ;STACK STARTS HERE
  1886.     END    
  1887. ə