;* THIS SECTION OF THE CODE TESTS A STRING AGAINST A TABLE.
;* WHEN A MATCH IS FOUND, CONTROL IS TRANSFERRED TO THE SECTION
;* OF CODE ACCORDING TO THE TABLE.
;*
;* AT 'EXEC' DX SHOULD POINT TO THE STRING AND BX SHOULD POINT
;* TO THE TABLE-1. AT 'DIRECT', DX SHOULD POINT TO THE STRING,
;* BX WILL BE SET UP TO POINT TO TAB1-1, WHICH IS THE TABLE OF
;* ALL DIRECT AND STATEMENT COMMANDS.
;*
;* A '.' IN THE STRING WILL TERMINATE THE TEST AND THE PARTIAL
;* MATCH WILL BE CONSIDERED AS A MATCH. E.G., 'PR.',
;* 'PRI.', 'PRIN.', OR 'PRINT' WILL ALL MATCH 'PRINT'.
;*
;* THE TABLE CONSISTS OF ANY NUMBER OF ITEMS. EACH ITEM
;* IS A STRING OF CHARACTERS WITH BIT 7 SET TO 1 IN LAST CHAR
;* A JUMP ADDRESS IS STORED FOLLOWING EACH CHARACTER ENTRY.
;*
;* END OF TABLE IS AN ITEM WITH A JUMP ADDRESS ONLY. IF THE
;* STRING DOES NOT MATCH ANY OF THE OTHER ITEMS, IT WILL
;* MATCH THIS NULL ITEM AS DEFAULT. THE DEFAULT IS INDICATED
;* BY FOLLOWING THE 80H DEFAULT INDICATOR.
;*
TAB1: EQU $ ;DIRECT COMMANDS
DM 'LIST'
DW LIST ;EXECUTION ADDRESSES
DM 'EDIT'
DW EDIT
DM 'E'
DW EDIT ;HAVE SHORT FORM DEFINED ALSO
DM 'RUN'
DW RUN
DM 'NEW'
DW NEW
DM 'LOAD'
DW DLOAD
DM 'SAVE'
DW DSAVE
DM 'BYE' ;GO BACK TO DOS (EXIT TBASIC)
DW BYE
TAB2: EQU $ ;DIRECT/STATEMENT
DM 'NEXT'
DW NEXT ;EXECUTION ADDRESSES
DM 'LET'
DW LET
DM 'OUT'
DW OUTCMD
DM 'POKE'
DW POKE
DM 'WAIT'
DW WAITCM
DM 'IF'
DW IFF
DM 'GOTO'
DW GOTO
DM 'GOSUB'
DW GOSUB
DM 'RETURN'
DW RETURN
DM 'REM'
DW REM
DM 'FOR'
DW FOR
DM 'INPUT'
DW INPUT
DM 'PRINT'
DW PRINT
DM 'STOP'
DW STOP
DB 128 ;SIGNALS END
;REMEMBER TO MOVE DEFAULT DOWN.
DW DEFLT ;LAST POSIBILITY
TAB4: EQU $ ;FUNCTIONS
DM 'RND'
DW RND
DM 'INP'
DW INP
DM 'PEEK'
DW PEEK
DM 'USR'
DW USR
DM 'ABS'
DW ABS
DM 'SIZE'
DW SIZE
DB 128 ;SIGNALS END
;YOU CAN ADD MORE FUNCTIONS BUT REMEMBER
;TO MOVE XP40 DOWN
DW XP40
TAB5: EQU $ ;"TO" IN "FOR"
DM 'TO'
TAB5A: DW FR1
DB 128
DW QWHAT
TAB6: EQU $ ;"STEP" IN "FOR"
DM 'STEP'
TAB6A: DW FR2
DB 128
DW FR3
TAB8: EQU $ ;RELATION OPERATORS
DM '>='
DW XP11 ;EXECUTION ADDRESS
DM '#'
DW XP12
DM '>'
DW XP13
DM '='
DW XP15
DM '<='
DW XP14
DM '<'
DW XP16
DB 128
DW XP17
;
; END OF PARSER ACTION TABLE
;
;
; AT ENTRY BX -> COMMAND TABLE (ABOVE)
; DX -> COMMAND LINE (I.E. "BUFFER")
;
DIRECT:
MOV BX,TAB1-1 ;***DIRECT***
;*
EXEC: EQU $ ;***EXEC***
EX0:
MOV AH,0
CALL IGNBLNK ;IGNORE LEADING BLANKS
PUSH DX ;SAVE POINTER
MOV SI,DX
EX1: LODB ;GET CHAR WHERE DX ->
INC DX ;PRESERVE POINTER
CMP AL,'.' ;WE DECLARE A MATCH
JZ EX4
INC BX
MOV AH,[BX]
AND AH,127 ;STRIP BIT 7
CMP AL,AH ;COMPARISON NOW EASY
JZ EX2
; NO MATCH - CHECK NEXT ENTRY
EX0A: CMP B,[BX],128 ;BYTE COMPARE
JNC EX0B
INC BX
JP EX0A
; AT THIS POINT HAVE LAST LETTER
EX0B: ADD BX,3 ;GET PAST EXECUTION ADDRESS
CMP B,[BX],128 ;FOUND DEFAULT?
JZ EX3A ;IF SO, EXECUTE DEFAULT
DEC BX ;CORRECT FOR PRE-INCREMENT
POP DX ;RESTORE POINTER
JP EX0 ;LOOK SOME MORE FOR A MATCH
EX4: INC BX
CMP B,[BX],128
JC EX4
JP EX3
;
EX3A: DEC SI
JP EX3 ;CORRECT SI FOR DEFAULT EXECUTION
EX2: CMP B,[BX],128 ;END OF RESERVED WORD?
JC EX1 ;NO - CHECK SOME MORE
; AT THIS POINT NEED TO GET EXECUTION ADDRESS
EX3: INC BX ;BX -> EXECUTION ADDRESS
POP AX ;CLEAR STACK
MOV DX,SI ;RESET POINTER
JMP [BX] ;DO IT
;*
;
;
; WHAT FOLLOWS IS THE CODE TO ECECUTE DIRECT AND STATEMENT COM-
; MANDS. CONTROL IS TRANSFERED TO THESE POINTS VIA THE COMMAND
; TABLE LOOKUP CODE OF 'DIRECT' AND 'EXEC' IN THE LAST SECTION.
; AFTER THE COMMAND IS EXECUTED, CONTROL IS TRANSFERRED TO
; OTHER SECTIONS AS FOLLOWS:
;
; FOR 'LIST','NEW', ANS 'STOP': GO BACK TO 'RSTART'
;
; FOR 'RUN',: GO EXECUTE THE FIRST STORED LINE IFF ANY; ELSE
; GO BACK TO RSTART.
;
; FOR 'GOTO' AND 'GOSUB': GO EXECUTE THE TARGET LINE.
;
; FOR 'RETURN' AND 'NEXT': GO BACK TO SAVED RETURN LINE.
;
; FOR ALL OTHERS: IFF 'CURRNT' -> 0, GO TO 'RSTART', ELSE
; GO EXECUTE NEXT COMMAND. (THIS IS DONE
; IN 'FINISH'.)
;
;
; ****NEW****STOP****RUN (& FRIENDS)****GOTO****
;
; 'NEW(CR)' SETS 'TXTUNF' TO POINT TO 'TXTBGN'
;
; 'STOP(CR)' GOES BACK TO 'RSTART'
;
; 'RUN(CR)' FINDS THE FIRST STROED LINE, STORES ITS ADDRESS
; (IN 'CURRNT'), AND START TO EXECUTE IT. NOTE THAT ONLY
; THOSE COMMANDS IN TAB2 ARE LEGAL FOR STORED PROGRAMS.
;
; THERE ARE THREE MORE ENTRIES IN 'RUN':
;
; 'RUNNXL' FINDS NEXT LINE, STORES ITS ADDR AND EXEC IT.
; 'RUNTSL' STORES THE ADDRESS OF THIS LINE AND EXECUTES IT
; 'RUNSML' CONTINUES THE EXECUTION ON SAME LINE.
;
; 'GOTO(EXPR)' EVALUATES THE EXPRESSION, FINDS THE TARGET LINE,
; AND JUMPS TO 'RUNTSL' TO DO IT.
;
; 'DLOAD' LOADS A NAMES PROGRAM FROM DISK (ANYNAME.TBI)
;
; 'DSAVE' SAVES A NAMES PROGRAM ON DISK
;
; 'FCBSET' SETS UP THE MSDOS FILE CONTROL BLOCK FOR SUBSEQUENT
; DISK I/O.
;
;
NEW:
MOV W,[TXTUNF],TXTBGN
;
STOP:
CALL ENDCHK ;****STOP(CR)****
JMP RSTART
;
RUN:
CALL ENDCHK ;****RUN(CR)****
MOV DX,TXTBGN ;FIRST SAVED LINE
;
RUNNXL:
MOV BX,0 ;****RUNNXL****
CALL FNDLNP ;FIND WHATEVER LINE
JNC RUNTSL ;C: PASSED TXTUNF, QUIT
JMP RSTART
;
RUNTSL:
XCHG DX,BX ;****RUNTSL****
MOV [CURRNT],BX ;SET 'CURRNT"->LINE #
XCHG DX,BX
INC DX
INC DX
;
RUNSML:
CALL CHKIO ;****RUNSML****
MOV BX,TAB2-1 ;FIND COMMAND IN TABLE 2
JMP EXEC ;AND EXECUTE IT
;
GOTO:
CALL EXP ;****GOTO(EXPR)****
PUSH DX ;SAVE FOR ERROR ROUTINE
CALL ENDCHK ;MUST FIND A 0DH (CR)
CALL FNDLN ;FIND THE TARGET LINE
JZ GT1 ;NO SUCH LINE #
JMP AHOW
GT1: POP AX
JP RUNTSL ;GO DO IT
;
; BDOS EQUATES (FOR MS-DOS)
;
BYE: EQU 0 ;BDOS EXIT ADDRESS
FCB: EQU 5CH
SETDMA: EQU 26
OPEN: EQU 15
READD: EQU 20
WRITED: EQU 21
CLOSE: EQU 16
MAKE: EQU 22
BCONIN: EQU 10 ;BUFFERED CONSOLE INPUT
DELETE: EQU 19
CONOUT: EQU 2 ;CONSOLE OUTPUT
CONST: EQU 11 ;CONSOLE STATUS
;
;
DLOAD:
MOV AH,0
CALL IGNBLNK ;IGNORE BLANKS
PUSH BX ;SAVE H
CALL FCBSET ;SET UP FILE CONTROL BLOCK
PUSH DX ;SAVE THE REST
PUSH CX ;SAVE THE REST
MOV DX,FCB ;GET FCB ADDR
MOV AH,OPEN ;PREPARE TO OPEN FILE
INT 33 ;CALL MS-DOS TO OPEN FILE
CMP AL,0FFH ;IS IT THERE?
JNZ DL1 ;NO, SEND ERROR
JMP QHOW
DL1: XOR AL,AL ;CLEAR A
MOV [FCB+32],AL ;START AT RECORD 0
MOV DX,TXTBGN ;GET BEGINNING
LOAD:
PUSH DX ;SAVE DMA ADDRESS
MOV AH,SETDMA
INT 33 ;CALL MS-DOS TO SET DAM ADDR
MOV AH,READD
MOV DX,FCB
INT 33 ;CALL MS-DOS TO READ SECTOR
CMP AL,1 ;DONE?
JC RDMORE ;NO, READ MORE
JZ LL1
LOAD1: JMP QHOW ;BAD READ OR NO DELIMITER
LL1: MOV AH,CLOSE
MOV DX,FCB
INT 33 ;CALL MS-DOS TO CLOSE FILE
POP BP ;DMA ADDR IN BP
SUB BP,100H ;BACKUP
MOV CX,100H ;MAX LOOPS
RDM1: INC BP ;PRE INC
CMP W,[BP],0 ;FOUND DELIMITER?
LOOPNZ RDM1 ;KEEP LOOKING
CMP CL,0 ;MAC LOOPS EXECUTED?
JZ LOAD1 ;GIVE ERROR IF SO
MOV [TXTUNF],BP ;UPDATE POINTER
POP CX ;GET OLD REG BACK
POP DX ;GET OLD REG BACK
POP BX ;GET OLD REG BACK
CALL FINISH ;FINISH
RDMORE:
POP DX ;GET DMA ADDR
MOV BX,80H ;GET 128
ADD BX,DX ;ADD IT TO DMA ADDR
XCHG DX,BX ;BACK IN D
JMP LOAD ;AND READ SOME MORE
;
DSAVE:
CMP W,[TXTUNF],TXTBGN ;SEE IF ANYTHING TO SAVE
JNZ DS1A
JMP QWHAT
DS1A:
MOV BP,[TXTUNF]
MOV W,[BP],0 ;SET DELIMITER
MOV AH,0
CALL IGNBLNK ;IGNORE BLANKS
PUSH BX ;SAVE BX
CALL FCBSET ;SETUP FCB
PUSH DX
PUSH CX ;SAVE OTHERS
MOV DX,FCB
MOV AH,DELETE
INT 33 ;CALL MS-DOS TO ERASE FILE
MOV DX,FCB
MOV AH,MAKE
INT 33 ;CALL MS-DOS TO MAKE A NEW ONE
CMP AL,0FFH ;IS THERE SPACE?
JNZ DS1
JMP QHOW ;NO, ERROR
DS1: XOR AL,AL ;CLEAR A
MOV [FCB+32],AL ;START AT RECORD 0
MOV DX,TXTBGN ;GET BEGINNING
SAVE:
PUSH DX ;SAVE DMA ADDR
MOV AH,SETDMA
INT 33 ;CALL MS-DOS TO SET DMA ADDR
MOV AH,WRITED
MOV DX,FCB
INT 33 ;CALL MS-DOS TO WRITE SECTOR
OR AL,AL ;SET FLAGS
JZ SS1 ;IF NOT ZERO, ERROR
JMP QHOW
SS1: POP DX ;GET DMA ADDR BACK
MOV AX,DX
CMP AX,[TXTUNF] ;SEE IF DONE
JZ SAVDON
JNC SAVDON ;JUMP IF DONE
WRITMOR:
MOV BX,80H
ADD BX,DX
XCHG DX,BX ;GET IT TO D
JP SAVE
SAVDON:
MOV AH,CLOSE
MOV DX,FCB
INT 33 ;CALL MS-DOS TO CLOSE FILE
POP CX ;GET REGS BACK
POP DX ;GET REGS BACK
POP BX ;GET REGS BACK
CALL FINISH
;
FCBSET:
MOV BX,FCB ;GET FCB ADDR
MOV B,[BX],0 ;CLEAR ENTRY TYPE
FNCLR:
INC BX
MOV B,[BX],' ' ;CLEAR TO SPACE
MOV AX,FCB+8
CMP AX,BX ;DONE?
JNZ FNCLR ;NO, DO IT AGAIN
INC BX
MOV B,[BX],'T' ;SET FILE TYPE TO 'TBI'
INC BX
MOV B,[BX],'B'
INC BX
MOV B,[BX],'I'
EXRC:
INC BX
MOV B,[BX],0
MOV AX,FCB+15
CMP AX,BX
JNZ EXRC ;NO, CONTINUE
MOV BX,FCB+1 ;GET FILENAME START
FN:
MOV SI,DX
LODB ;GET CHAR
CMP AL,0DH ;IS IT A 'CR'
JZ RET ;YES, DONE
CMP AL,'!' ;LEGAL CHAR?
JNC FN1 ;NO, SEND ERROR
JMP QWHAT
FN1: CMP AL,'[' ;AGAIN
JC FN2 ;DITTO
JMP QWHAT
FN2: MOV [BX],AL ;SAVE IT IN FCB
INC BX
INC DX
MOV AX,FCB+9
CMP AX,BX ;LAST?
JNZ FN ;NO, CONTINUE
RET ;TRUNCATE AT EIGHT CHARS
;
;
; ****LIST**** AND ****PRINT**** AND ****EDIT****
;
; LIST HAS TWO FORMS:
; 'LIST(CR)' LISTS ALL SAVED LINES
; 'LIST #(CR)' START LIST AT THIS LINE #
; YOU CAN STOP LISTING BY CONTROL C KEY
;
; PRINT COMMAND IS 'PRINT ....;' OR 'PRINT ....(CR)'
; WHERE '....' IS A LIST OF EXPRESIONS, FORMATS, BACKARROWS, AND
; STRINGS. THESE ITEMS ARE SEPERATED BY COMMAS.
;
; A FORMAT IS A POUND SIGN FOLLOWED BY A NUMBER. IT CONTROLS THE
; NUMBER OF SPACES THE VALUE OF AN EXPRESSION IS TO BE PRINTED.
; TED. IT STAYS EFFECTIVE FOR THE REST OF THE PRINT, UNLESS
; CHANGED BY ANOTHER FORMAT. IF NO FORMAT SPEC, 6 POSITIONS
; WILL BE USED.
;
; A STRING IS QUOTED IN A PAIR OF SINGLE QUOTES OR DOUBLE
; QUOTES.
;
; A BACK-ARROW MEANS GENERATE A (CR) WITHOUT (LF).
;
; A (CRLF) IS GENERATED AFTER THE ENTIRE LIST HAS BEEN PRINT OR
; IF THE LIST IS A NULL LIST. HOWEVER IF THE LIST ENDED WITH A
; COMMA, NO (CR) IS GENERATED.
;
;
LIST:
CALL TSTNUM ;TEST IFF THERE IS A #
CALL ENDCHK ;IFF NO # WE GET A 0
CALL FNDLN ;FIND THIS OR NEXT LINE
LS1:
JNC LS2 ;C: PASSED TXTUNF
JMP RSTART
LS2: CALL PRTLN ;PRINT THE LINE
CALL CHKIO ;SEE IF ^X OR ^C
CALL FNDLNP ;FIND NEXT LINE
JP LS1 ;LOOP BACK
;
;
EDIT:
CALL TSTNUM ;TEST IF THERE IS A #
CALL ENDCHK ;AT END?
CALL FNDLN ;FIND SPEC LINE OR NEXT LINE
PUSH DX ;SAVE LINE #
JNC ED2 ;C: PASSED TXTUNF
POP DX ;THROW AWAY LINE #
ED1: JMP RSTART
ED2:
CALL PRTLN ;PRINT THE LINE
POP DX ;GET LINE # BACK
MOV B,[OCSW],0 ;DIRECT OUTPUT TO BUFFER
MOV B,[BUFFER-1],0 ;CLEAR CHAR COUNT
MOV B,[PRTLN1+1],4 ;PRINT ONE LESS SPACE
MOV DI,BUFFER ;PREPARE TO MOVE
CALL PRTLN
MOV B,[OCSW],0FFH ;REDIRECT OUTPUT TO CONSOLE
DEC [BUFFER-1] ;AVOID CR?
MOV B,[PRTLN1+1],5 ;RESTORE PRTLN
JMP ST3 ;PROMPT AND GETLINE ONLY
PRINT:
MOV CL,6 ;C:= # OF SPACES
MOV AH,';' ;CHECK FOR ';' IN IGNBLNK
CALL IGNBLNK ;IGNORE BLANKS
JNZ PR2 ;JUMP IF ';' NOT FOUND
CALL CRLF ;GIVE CR,LF AND
JMP RUNSML ;CONTINUE SAME LINE
PR2:
MOV AH,0DH
CALL IGNBLNK
JNZ PR0
CALL CRLF ;ALSO GIVE CRLF AND
JMP RUNNXL ;GOTO NEXT LINE
PR0:
MOV AH,'#'
CALL IGNBLNK
JNZ PR1
CALL EXP ;YES, EVALUATE EXPR
MOV CL,BL ;AND SAVE IT IN C
JP PR3 ;LOOK FOR MORE TO PRINT
PR1:
CALL QTSTG ;OR IS IT A STRING?
JP PR8 ;IFF NOT, MUST BE EXPRESSION
PR3:
MOV AH,','
CALL IGNBLNK
JNZ PR6
CALL FIN ;IN THE LIST
JP PR0 ;LIST CONTINUES
PR6:
CALL CRLF ;LIST ENDS
CALL FINISH
PR8:
CALL EXP ;EVAL THE EXPR
PUSH CX
CALL PRTNUM ;PRINT THE VALUE
POP CX
JP PR3 ;MORE TO PRINT?
;
;
; ****GOSUB**** AND ****RETURN****
;
; 'GOSUB (EXPR);' OR 'GOSUB EXPR(CR)' IS LIKE THE 'GOTO' COMMAND
; EXCEPT THAT THE CURRENT TEXT POINTER, STACK POINTER ETC. ARE
; SAVED SO THAT EXECUTION CAN BE CONTINUED AFTER THE SUBROUTINE
; 'RETURN'. IN ORDER THAT 'GOSUB' CAN BE NESTED (AND EVEN RECUR-
; SIVE), THE SAVE AREA MUST BE STACKED. THE STACK POINTER IS
; SAVED IN 'STKGOS'. THE OLD 'STKGOS' IS SAVED IN THE STACK. IF
; WE ARE IN THE MAIN ROUTINE, 'STKGOS' IS ZERO (THIS WAS DONE BY
; THE "MAIN" SECTION OF THE CODE), BUT WE STILL SAVE IT AS
; A FLAG FOR NO FURTHER RETURNS.
;
; 'RETURN(CR)' UNDOES EVERYTHING THAT 'GOSUB' DID, AND THUS RE-
; TURNS THE EXECUTION TO THE COMMAND AFTER THE MOST RECENT 'GO-
; SUB'. IFF 'STKGOS' IS ZERO, IT INDICATES THAT WE NEVER HAD A
; 'GOSUB' AND IS THUS AN ERROR.
;
;
GOSUB:
CALL PUSHA ;SAVE THE CURRENT 'FOR'
CALL EXP ;PARAMETERS
PUSH DX
CALL FNDLN ;FIND THE TARGET LINE
JZ GS1 ;NOT THERE, SAY "HOW?"
JMP AHOW
GS1: MOV BX,[CURRNT] ;FOUND IT, SAVE OLD
PUSH BX ;'CURRNT' OLD 'STKGOS'
MOV BX,[STKGOS]
PUSH BX
MOV BX,0 ;AND LOAD NEW ONES
MOV [LOPVAR],BX
ADD BX,SP
MOV [STKGOS],BX
JMP RUNTSL ;THEN RUN THAT LINE
RETURN:
CALL ENDCHK ;THERE MUST BE A 0DH
MOV BX,[STKGOS] ;OLD STACK POINTER
OR BX,BX
JNZ RET1 ;SO, WE SAY: "WHAT?"
JMP QWHAT
RET1: XCHG BX,SP ;ELSE RESTORE IT
POP BX ;ELSE RESTORE IT
MOV [STKGOS],BX ;AND THE OLD 'STKGOS'
POP BX
MOV [CURRNT],BX ;AND THE OLD 'CURRNT'
POP DX ;OLD TEXT POINTER
CALL POPA ;OLD "FOR" PARAMETERS
CALL FINISH ;AND WE ARE BACK HOME
;
;
; ****FOR**** AND ****NEXT****
;
;
; 'FOR' HAS TWO FORMS:
; 'FOR VAR=EXP1 TO EXP2 STEP EXP3'
; 'FOR VAR=EXP1 TO EXP2'
; THE SECOND FORM MEANS THE SAME AS THE FIRST FORM WITH EXP3=1.
;
; TBI WILL FIND THE VARIABLE VAR AND SET ITS VALUE TO THE CUR-
; RENT VALUE OF EXP1. IT ALSO EVALUATES EXP2 AND EXP3 AND
; SAVES ALL OF THESE TOGETHER WITH THE TEXT POINTER ETC IN
; THE 'FOR' SAVE AREA, WHICH CONSISTS OF 'LOPVAR', 'LOPINC',
; 'LOPLMT', 'LOPLN', AND 'LOPPT'. IFF THERE IS ALREADY SOME-
; THING IN THE SAVE AREA (THIS IS INDICATED BY A NON-ZERO
; 'LOPVAR'), THEN THE OLD SAVE AREA IS SAVED IN THE STACK BE-
; FORE THE NEW ONE OVERWRITES IT.
;
; TBI WILL THEN DIG IN THE STACK AND FIND OUT IFF THIS
; SAME VARIABLE WAS USED IN ANOTHER CURRENTLY ACTIVE FOR
; LOOP. IT THAT IS THE CASE THEN THE OLD 'FOR' LOOP IS DE-
; IVATED (PURGED FROM THE STACK).
;
; 'NEXT VAR' SERVES AS THE LOGICAL (NOT NECESSARILLY PHYSICAL)
; END OF THE 'FOR' LOOP. THE CONTROL VARIABLE VAR. IS CHECKED
; WITH THE 'LOPVAR'. IFF THEY ARE NOT THE SAME, TBI DIGGS IN
; THE STACK TO FIND THE RIGHT ONE AND PURGES ALL THOSE THAT
; DID NOT MATCH. EITHER WAY, TBI THEN ADDS THE 'STEP' TO THAT
; VARIABLE AND CHECKS THE RESULT WITH THE LIMIT. IFF IT IS
; WITHIN THE LIMIT, CONTROL LOOPS BACK TO THE COMMAND FOLLOW-
; ING THE 'FOR'. IFF OUTSIDE THE LIMIT, THE SAVE AREA IS PURG-
; ED AND EXECUTION CONTINUES.
;
;
FOR:
CALL PUSHA ;SAVE THE OLD SAVE AREA
CALL SETVAL ;SET THE CONTROL VAR.
DEC BX
MOV [LOPVAR],BX ;SAVE TGAT
MOV BX,TAB5-1 ;USE 'EXEC' TO LOOK
JMP EXEC ;FOR THE WORD 'TO'
FR1:
CALL EXP ;EVALUATE THE LIMIT
MOV [LOPLMT],BX ;SAVE THAT
MOV BX,TAB6-1 ;USED 'EXEC' TO LOOK
JMP EXEC ;FOR THE WORD 'STEP'
FR2:
CALL EXP ;FOUND IT, GET STEP
JP FR4 ;FOUND IT, GET STEP
FR3:
MOV BX,1 ;NOT FOUND, SET TO ONE
FR4:
MOV [LOPINC],BX ;SAVE THAT TOO
FR5:
MOV BX,[CURRNT] ;SAVE CURRENT LINE #
MOV [LOPLN],BX
XCHG DX,BX ;AND TEXT POINTER
MOV [LOPPT],BX
MOV CX,10 ;DIG INTO STACK TO
MOV BX,[LOPVAR] ;FIND 'LOPVAR'
XCHG DX,BX
MOV BX,CX ;BX:=10 NOW
ADD BX,SP
JP FR7A
FR7:
ADD BX,CX
FR7A: MOV AX,[BX] ;GET THAT OLD 'LOPVAR'
OR AX,AX
JZ FR8 ;0 SAYS NO MORE IN IT
CMP AX,DX ;SAME AS THIS ONE?
JNZ FR7
XCHG DX,BX
MOV BX,0 ;THE OTHER HALF?
ADD BX,SP
MOV CX,BX
MOV BX,10
ADD BX,DX
CALL MVDOWN ;AND PURGE 10 WORDS
XCHG BX,SP ;IN THE STACK
FR8:
MOV BX,[LOPPT] ;JOB DONE, RESTORE DE
XCHG DX,BX
CALL FINISH ;AND CONTINUE
;
NEXT:
CALL TSTV ;GET ADDR OF VAR
JNC NX4 ;NO VARIABLE, "WHAT?"
JMP QWHAT
NX4: MOV [VARNXT],BX ;YES, SAVE IT
NX0:
PUSH DX ;SAVE TEXT POINTER
XCHG DX,BX
MOV BX,[LOPVAR] ;GET VAR IN 'FOR'
MOV AL,BH
OR AL,BL ;0 SAY NEVER HAD ONE
JNZ NX5 ;SO WE ASK: "WHAT?"
JMP AWHAT
NX5: CMP DX,BX ;ELSE WE CHECK THEM
JZ NX3 ;OK, THEY AGREE
POP DX ;NO, LET'S SEE
CALL POPA ;PURGE CURRENT LOOP
MOV BX,[VARNXT] ;AND POP ONE LEVEL
JMP NX0 ;GO CHECK AGAIN
NX3:
MOV DL,[BX] ;COME HERE WHEN AGREED
INC BX
MOV DH,[BX] ;DE = VAL OF VAR
MOV BX,[LOPINC]
PUSH BX
ADD BX,DX
XCHG DX,BX ;ADD ONE STEP
MOV BX,[LOPVAR] ;PUT IT BACK
MOV [BX],DL
INC BX
MOV [BX],DH
MOV BX,[LOPLMT] ;HL-> LIMIT
POP AX
XCHG AH,AL
OR AX,AX
JNS NX1 ;STEP > 0
XCHG DX,BX
NX1:
CALL CKHLDE ;COMPARE WITH LIMIT
POP DX ;RESTORE TEXT POINTER
JC NX2 ;OUTSIDE LIMIT
MOV BX,[LOPLN] ;WITHIN LIMIT, GO
MOV [CURRNT],BX ;BACK TO THE SAVED
MOV BX,[LOPPT] ;'CURRNT' AND TEXT
XCHG DX,BX ;POINTER
CALL FINISH ;POINTER
NX2:
CALL POPA ;PURGE THIS LOOP
CALL FINISH
;
;
; ****REM**** AND ****IF**** AND ****LET*****
;
;
; 'REM' CAN BE FOLLOWED BY ANYTHING AND IS IGNORED BY TBI. TBI
; TREATS IT LIKE AN 'IF' WITH A FALSE CONDITION.
;
; 'IF' IS FOLLOWED BY AN EXPR. AS A CONDITION AND ONE OR MORE
; COMMANDS (INCLUDING OTHER 'IF'S) SEPERATED BY SEMI-COLONS.
; NOTE THAT THE WORD 'THEN' IS NOT USED. TBI EVALUATES THE
; EXPR. IFF IT IS NON-ZERO, EXECUTION CONTINUES. IFF THE EXPR.
; IS ZERO, THE COMMANDS THAT FOLLOW ARE IGNORED AND EXECUTION
; CONTINUES AT THE NEXT LINE.
;
; 'IPUT' COMMANS IS LIKE THE 'PRINT' COMMAND, AND IS FOLLOWED
; BY A LIST OF ITEMS. IFF THE ITEM IS A STRING IN SINGLE OR
; DOUBLE QUOTES, OR IS A BACK-ARROW, IT HAS THE SAME EFFEDT AS
; PRINTED OUT FOLLOWED BY A COLON. THEN TBI WAITS FOR AN EXPR.
; TO BE TYPEN IN. THE VARIABLE IS THEN SET TO THE VALUE OF
; THIS EXPR. IFF THE VARIABLE IS PROCEDED BY A STRING PRINTED
; FOLLOWED BY A COLON. TBI THEN WAITS FOR INPUT EXPR. AND SETS
; THE VARIABLE TO THE VALUE OF THE EXPR.
;
; IFF THE INPUT EXPR. IS INVALID, TBI WILL PRINT "WHAT?" ,
; "HOW?",OR "SORRY" AND REPRINT THE PROMPT AND REDO THE INPUT.
; THE EXECUTION WILL NOT TERMINATE UNLESS YOU TYPE CONTROL-C .
; THIS IS HANDLED IN 'INPERR'.
;
; 'LET' IS FOLLOWED BY A LIST OF ITEMS SEPERATED BY COMMAS .
; EACH ITEM CONSISTS OF A VARIABLE, AN EQUAL SIGN, AND AN
; EXPR. TBI EVALUATES THE EXPR. AND SETS THE VARIABLE TO THAT
; VALUE. TBI WILL ALSO HANDLE 'LET' COMMAND WITHOUT THE WORD
; 'LET'. THIS IS DONE BY 'DEFLT'.
;
;
;
REM:
MOV BX,0 ;****REM****
JP IFF1A ;JUMP AROUND EXPR
;
IFF:
CALL EXP ;****IF****
IFF1A: CMP BX,0 ;IS THE EXPR = 0?
JZ IFF1 ;NO, CONTINUE
JMP RUNSML
IFF1: CALL FNDSKP ;YES, SIKP REST OF LINE
JC IFF2 ;YES, SIKP REST OF LINE
JMP RUNTSL
IFF2: JMP RSTART ;YES, SIKP REST OF LINE
;
INPERR:
MOV BX,[STKINP] ;****INPERR****
XCHG BX,SP ;RESTORE OLD STACK POINTER
POP BX ;AND OLD 'CURRNT'
MOV [CURRNT],BX
POP DX
POP DX ;REDO INPUT
;
INPUT: EQU $ ;****INPUT****
IP1:
PUSH DX ;SAVE IN CASE OF ERROR
CALL QTSTG ;IS NEXT ITEM A STRING?
JP IP2 ;NO
CALL TSTV ;YES, BUT FOLLOWED BY A
JC IP4 ;VARIABLE? NO.
JP IP3 ;YES. INPUT VAR.
IP2:
PUSH DX ;SAVE FOR 'PRTSTG'
CALL TSTV ;MUST BE A VAR NOW
JNC IP2A ;"WHAT" IT IS NOT!
JMP QWHAT
IP2A: MOV SI,DX
LODB ;GET READY FOR 'RTSTG'
MOV CL,AL
SUB AL,AL
MOV DI,DX
STOB
POP DX
CALL PRTSTG ;PRINT STRING AS PROMPT
MOV AL,CL
DEC DX
MOV DI,DX
STOB
IP3:
PUSH DX
XCHG DX,BX
MOV BX,[CURRNT] ;ALSO SAVE 'CURRNT'
PUSH BX
MOV BX,IP1
MOV [CURRNT],BX ;NEG NUMBER AS FLAG
MOV [STKINP],SP
PUSH DX ;OLD HL
MOV AL,':' ;PRINT THIS TOO
CALL GETLN ;AND GET A LINE
②◆ג@≡p≥⓪'½⇦ó,⑥!*ú#"⌐⇦¥É('ñº*)É*'É!*ú#"⌐╱à⇦íáª&⇦ó¼(⇦¥ó½ ª*á¬"É$º(*¬╱à⇦º'¿⇦É⓪⓪⓪⓪⓪⓪⓪íáº⓪!"É③íáª&⓪"º"!ñ%ôåà⇦º'¿⇦É⇦¥íáº⓪!"É③íáª&⓪"º"!ñ%ôåà⇦º'¿⇦É⇦¥íáº⓪!"É③íáª&⓪"º"!ñ%ôåà⇦¿'¿⇦ó,⇦¥ºÑû#ó¬⓪'ª"⓪$&╱à⇦¼!ñ#äó,⑥!,⇦¥ºÑû#ó¬⓪'ª"⓪$&╱à⇦ªº½⇦¡í,.û",╱à⇦¿'¿⇦í,⇦¥úó¬⓪'ª"⓪③í¬⌐)'*③åà⇦ªº½⇦¡í¬⌐)'*.û!,╱à⇦¿'¿⇦ó,⇦¥áº"⓪#ó¬⓪'ª"⓪*"¼*⓪('ñº*"⌐╱à$¿ə╱à⇦¿'¿⇦á¼╱à⇦ªº½⇦áñ⑥③û③åà⇦íáª&⇦ñúº!&'%åà SO THAT EXECUTION CAN BE CONTINUED AFTER THE SUBROUTINE
; 'RETURN'. IN ORDER THAT 'GOSUB' CAN BE NESTED (AND EVEN RECUR-
; SIVE), THE SAVE AREA MUST BE STACKED. THE STACK POINTER IS
; SAVED IN 'STKGOS'. THE OLD 'STKGOS' IS SAVED IN THE STACK. IF
; WE ARE IN THE MAIN ROUTINE, 'STKGOS' IS ZERO (THIS WAS DONE BY
; THE "MAIN" SECTION OF THE CODE), BUT WE STILL SAVE IT AS
; A FLAG FOR NO FURTHER RETURNS.
;
; 'RETURN(CR)' UNDOES EVERYTHING THAT 'GOSUB' DID, AND THUS RE-
; TURNS THE EXECUTION TO THE COMMAND AFTER THE MOST RECENT 'GO-
; SUB'. IFF 'STKGOS' IS ZERO, IT INDICATES THAT WE NEVER HAD A
; 'GOSUB' AND IS THUS AN ERROR.
;
;
GOSUB:
CALL PUSHA ;SAVE THE CURRENT 'FOR'
CALL EXP ;PARAMETERS
PUSH DX
CALL FNDLN ;FIND THE TARGET LINE
JZ GS1 ;NOT THERE, SAY "HOW?"
JMP AHOW
GS1: MOV BX,[CURRNT] ;FOUND IT, SAVE OLD
PUSH BX ;'CURRNT' OLD 'STKGOS'
MOV BX,[STKGOS]
PUSH BX
MOV BX,0 ;AND LOAD NEW ONES
MOV [LOPVAR],BX
ADD BX,SP
MOV [STKGOS],BX
JMP RUNTSL ;THEN RUN THAT LINE
RETURN:
CALL ENDCHK ;THERE MUST BE A 0DH
MOV BX,[STKGOS] ;OLD STACK POINTER
OR BX,BX
JNZ RET1 ;SO, WE SAY: "WHAT?"
JMP QWHAT
RET1: XCHG BX,SP ;ELSE RESTORE IT
POP BX ;ELSE RESTORE IT
MOV [STKGOS],BX ;AND THE OLD 'STKGOS'
POP BX
MOV [CURRNT],BX ;AND THE OLD 'CURRNT'
POP DX ;OLD TEXT POINTER
CALL POPA ;OLD "FOR" PARAMETERS
CALL FINISH ;AND WE ARE BACK HOME
;
;
; ****FOR**** AND ****NEXT****
;
;
; 'FOR' HAS TWO FORMS:
; 'FOR VAR=EXP1 TO EXP2 STEP EXP3'
; 'FOR VAR=EXP1 TO EXP2'
; THE SECOND FORM MEANS THE SAME AS THE FIRST FORM WITH EXP3=1.
;
; TBI WILL FIND THE VARIABLE VAR AND SET ITS VALUE TO THE CUR-
; RENT VALUE OF EXP1. IT ALSO EVALUATES EXP2 AND EXP3 AND
; SAVES ALL OF THESE TOGETHER WITH THE TEXT POINTER ETC IN
; THE 'FOR' SAVE AREA, WHICH CONSISTS OF 'LOPVAR', 'LOPINC',
; 'LOPLMT', 'LOPLN', AND 'LOPPT'. IFF THERE IS ALREADY SOME-
; THING IN THE SAVE AREA (THIS IS INDICATED BY A NON-ZERO
; 'LOPVAR'), THEN THE OLD SAVE AREA IS SAVED IN THE STACK BE-
; FORE THE NEW ONE OVERWRITES IT.
;
; TBI WILL THEN DIG IN THE STACK AND FIND OUT IFF THIS
; SAME VARIABLE WAS USED IN ANOTHER CURRENTLY ACTIVE FOR
; LOOP. IT THAT IS THE CASE THEN THE OLD 'FOR' LOOP IS DE-
; IVATED (PURGED FROM THE STACK).
;
; 'NEXT VAR' SERVES AS THE LOGICAL (NOT NECESSARILLY PHYSICAL)
; END OF THE 'FOR' LOOP. THE CONTROL VARIABLE VAR. IS CHECKED
; WITH THE 'LOPVAR'. IFF THEY ARE NOT THE SAME, TBI DIGGS IN
; THE STACK TO FIND THE RIGHT ONE AND PURGES ALL THOSE THAT
; DID NOT MATCH. EITHER WAY, TBI THEN ADDS THE 'STEP' TO THAT
; VARIABLE AND CHECKS THE RESULT WITH THE LIMIT. IFF IT IS
; WITHIN THE LIMIT, CONTROL LOOPS BACK TO THE COMMAND FOLLOW-
; ING THE 'FOR'. IFF OUTSIDE THE LIMIT, THE SAVE AREA IS PURG-
; ED AND EXECUTION CONTINUES.
;
;
FOR:
CALL PUSHA ;SAVE THE OLD SAVE AREA
CALL SETVAL ;SET THE CONTROL VAR.
DEC BX
MOV [LOPVAR],BX ;SAVE TGAT
MOV BX,TAB5-1 ;USE 'EXEC' TO LOOK
JMP EXEC ;FOR THE WORD 'TO'
FR1:
CALL EXP ;EVALUATE THE LIMIT
MOV [LOPLMT],BX ;SAVE THAT
MOV BX,TAB6-1 ;USED 'EXEC' TO LOOK
JMP EXEC ;FOR THE WORD 'STEP'
FR2:
CALL EXP ;FOUND IT, GET STEP
JP FR4 ;FOUND IT, GET STEP
FR3:
MOV BX,1 ;NOT FOUND, SET TO ONE
FR4:
MOV [LOPINC],BX ;SAVE THAT TOO
FR5:
MOV BX,[CURRNT] ;SAVE CURRENT LINE #
MOV [LOPLN],BX
XCHG DX,BX ;AND TEXT POINTER
MOV [LOPPT],BX
MOV CX,10 ;DIG INTO STACK TO
MOV BX,[LOPVAR] ;FIND 'LOPVAR'
XCHG DX,BX
MOV BX,CX ;BX:=10 NOW
ADD BX,SP
JP FR7A
FR7:
ADD BX,CX
FR7A: MOV AX,[BX] ;GET THAT OLD 'LOPVAR'
OR AX,AX
JZ FR8 ;0 SAYS NO MORE IN IT
CMP AX,DX ;SAME AS THIS ONE?
JNZ FR7
XCHG DX,BX
MOV BX,0 ;THE OTHER HALF?
ADD BX,SP
MOV CX,BX
MOV BX,10
ADD BX,DX
CALL MVDOWN ;AND PURGE 10 WORDS
XCHG BX,SP ;IN THE STACK
FR8:
MOV BX,[LOPPT] ;JOB DONE, RESTORE DE
XCHG DX,BX
CALL FINISH ;AND CONTINUE
;
NEXT:
CALL TSTV ;GET ADDR OF VAR
JNC NX4 ;NO VARIABLE, "WHAT?"
JMP QWHAT
NX4: MOV [VARNXT],BX ;YES, SAVE IT
NX0:
PUSH DX ;SAVE TEXT POINTER
XCHG DX,BX
MOV BX,[LOPVAR] ;GET VAR IN 'FOR'
MOV AL,BH
OR AL,BL ;0 SAY NEVER HAD ONE
JNZ NX5 ;SO WE ASK: "WHAT?"
JMP AWHAT
NX5: CMP DX,BX ;ELSE WE CHECK THEM
JZ NX3 ;OK, THEY AGREE
POP DX ;NO, LET'S SEE
CALL POPA ;PURGE CURRENT LOOP
MOV BX,[VARNXT] ;AND POP ONE LEVEL
JMP NX0 ;GO CHECK AGAIN
NX3:
MOV DL,[BX] ;COME HERE WHEN AGREED
INC BX
MOV DH,[BX] ;DE = VAL OF VAR
MOV BX,[LOPINC]
PUSH BX
ADD BX,DX
XCHG DX,BX ;ADD ONE STEP
MOV BX,[LOPVAR] ;PUT IT BACK
MOV [BX],DL
INC BX
MOV [BX],DH
MOV BX,[LOPLMT] ;HL-> LIMIT
POP AX
XCHG AH,AL
OR AX,AX
JNS NX1 ;STEP > 0
XCHG DX,BX
NX1:
CALL CKHLDE ;COMPARE WITH LIMIT
POP DX ;RESTORE TEXT POINTER
JC NX2 ;OUTSIDE LIMIT
MOV BX,[LOPLN] ;WITHIN LIMIT, GO
MOV [CURRNT],BX ;BACK TO THE SAVED
MOV BX,[LOPPT] ;'CURRNT' AND TEXT
XCHG DX,BX ;POINTER
CALL FINISH ;POINTER
NX2:
CALL POPA ;PURGE THIS LOOP
CALL FINISH
;
;
; ****REM**** AND ****IF**** AND ****LET*****
;
;
; 'REM' CAN BE FOLLOWED BY ANYTHING AND IS IGNORED BY TBI. TBI
; TREATS IT LIKE AN 'IF' WITH A FALSE CONDITION.
;
; 'IF' IS FOLLOWED BY AN EXPR. AS A CONDITION AND ONE OR MORE
; COMMANDS (INCLUDING OTHER 'IF'S) SEPERATED BY SEMI-COLONS.
; NOTE THAT THE WORD 'THEN' IS NOT USED. TBI EVALUATES THE
; EXPR. IFF IT IS NON-ZERO, EXECUTION CONTINUES. IFF THE EXPR.
; IS ZERO, THE COMMANDS THAT FOLLOW ARE IGNORED AND EXECUTION
; CONTINUES AT THE NEXT LINE.
;
; 'IPUT' COMMANS IS LIKE THE 'PRINT' COMMAND, AND IS FOLLOWED
; BY A LIST OF ITEMS. IFF THE ITEM IS A STRING IN SINGLE OR
; DOUBLE QUOTES, OR IS A BACK-ARROW, IT HAS THE SAME EFFEDT AS
; PRINTED OUT FOLLOWED BY A COLON. THEN TBI WAITS FOR AN EXPR.
; TO BE TYPEN IN. THE VARIABLE IS THEN SET TO THE VALUE OF
; THIS EXPR. IFF THE VARIABLE IS PROCEDED BY A STRING PRINTED
; FOLLOWED BY A COLON. TBI THEN WAITS FOR INPUT EXPR. AND SETS
; THE VARIABLE TO THE VALUE OF THE EXPR.
;
; IFF THE INPUT EXPR. IS INVALID, TBI WILL PRINT "WHAT?" ,
; "HOW?",OR "SORRY" AND REPRINT THE PROMPT AND REDO THE INPUT.
; THE EXECUTION WILL NOT TERMINATE UNLESS YOU TYPE CONTROL-C .
; THIS IS HANDLED IN 'INPERR'.
;
; 'LET' IS FOLLOWED BY A LIST OF ITEMS SEPERATED BY COMMAS .
; EACH ITEM CONSISTS OF A VARIABLE, AN EQUAL SIGN, AND AN
; EXPR. TBI EVALUATES THE EXPR. AND SETS THE VARIABLE TO THAT
; VALUE. TBI WILL ALSO HANDLE 'LET' COMMAND WITHOUT THE WORD
; 'LET'. THIS IS DONE BY 'DEFLT'.
;
;
;
REM:
MOV BX,0 ;****REM**
POK2: CALL FINISH
PEEK:
CALL PARN
MOV BL,[BX]
MOV BH,0
RET
JMP QWHAT
USR:
PUSH CX
MOV AH,'('
CALL IGNBLNK
JNZ QWT
CALL EXP ;EXPR
MOV AH,')'
CALL IGNBLNK ;EXPR
JNZ PASPRM
PUSH DX
MOV DX,USRET
PUSH DX
PUSH BX
RET ;CALL USR ROUTINE
PASPRM:
MOV AH,','
CALL IGNBLNK
JNZ USRET1
PUSH BX
CALL EXP
MOV AH,')'
CALL IGNBLNK
JNZ USRET1
POP CX
PUSH DX
MOV DX,USRET
PUSH DX
PUSH CX
RET ;CALL USR ROUTINE
USRET:
POP DX
USRET1: POP CX
RET
QWT: JMP QWHAT
;
;
; ****DIVIDE**** AND ****CHKSGN****
; ****CHKSGN**** AND ****CKHLDE****
;
;
; 'DIVIDE DIVIDES BX BY DX, RESULT IN CX, REMAINDER IN BX
;
; 'CHKSGN' CHECKS SIGN OF BX. IFF +, NO CHANGE. IFF -, CHANGE
; SIGN AND FLIP SIGN OF C
;
; 'CHGSGN' CHANGES SIGN OF BX AND CL UNCONDITIONALLY.
;
; 'CKHLDE' CHECK SIGN OF BX AND DX. IFF DIFFERENT, BX AND DX
; ARE INTERCHANGED. IFF SAME SIGN, NOT INTERCHANGED. EITHER
; CASE, BX AND DX ARE THEN COMPARED TO SET THE FLAGS.
;
;
DIVIDE:
PUSH DX ;PRESERVE DX ACCROSS CALL
PUSH DX
XOR DX,DX
POP CX
MOV AX,BX
IDIV AX,CX
MOV CX,AX ;QUOTIENT
MOV BX,DX ;REMAINDER
POP DX ;DX RESTORED
RET
;
CHKSGN:
OR BX,BX ;SET FLAGS TO CHECK SIGN
JNS RET ;IFF -, CHANGE SIGN
;
CHGSGN:
NOT BX ;****CHGSGN****
INC BX
XOR CH,128
RET
;
CKHLDE:
MOV AL,BH
XOR AL,DH ;SAME SIGN?
JNS CK1 ;YES, COMPARE
XCHG DX,BX
CK1:
CMP BX,DX
RET
;
;
; ****SETVAL**** AND ****FIN**** AND ****ENDCHK****
; ****ERROR**** AND FRIENDS
;
;
; 'SETVAL' EXPECTS A VARIABLE, FOLLOWED BY AN EQUAL SIGN AND
; THEN AN EXPR. IT EVALUATES THE EXPR AND SETS THE VARIABLE
; TO THAT VALUE.
;
; 'FIN' CHECKS THE END OF A COMMAND. IFF IT ENDED WITH ";" ,
; EXECUTION CONTINUES. IFF IT ENDED WITH A CR, IT FINDS THE
; NEXT LINE AND CONTINUES FROM THERE.
;
; 'ENDCHK' CHECKS IFF A COMMAND IS ENDED WITH A CR, THIS IS
; REQUIRED IN CERTAIN COMMANDS. (GOTO, RETURN, AND STOP,ETC)
;
; 'ERROR' PRINTS THE STRING POINTED BY DX (AND ENDS WITH A
; CR). IT THEN PRINTS THE LINE POINTED BY 'CURRNT' WITH A ?.
; INSERTED AT WHERE THE OLD TEXT POINTER (SHOULD BE ON TOP
; OF THE STACK) POINTS TO. EXECUTION OF TB IS STOPPED AND
; TBI IS RESTARTED. HOWEVER, IFF 'CURRNT' -> ZERO (INDICAT -
; ING A DIRECT COMMAND), THE DIRECT COMMAND IS NOT PRINTED ,
; AND IFF 'CURRNT' -> NEGATIVE # (INDICATING 'INPUT' COMMAND
; THE INPUT LINE IS NOT PRINTED AND EXECUTION IS NOT TERMIN-
; ATED BUR CONTINUED AT 'INPERR').
;
; RELATED TO 'ERROR' ARE THE FOLLOWING:
;
; 'QWHAT' SAVES TEXT POINTER IN STACK AND GETS MESSAGE
; "WHAT?"
; 'AWHAT' JUST GETS MESSAGE "WHAT?" AND JUMPS TO ERROR
;
; 'QSORRY' AND 'ASORRY' DO THE SAME KIND OF THING.
;
; 'QHOW' AND 'AHOW' IN THE ZERO PAGE SECTION ALSO DO
; THIS.
;
;
SETVAL:
CALL TSTV ;SEE IT IT'S A VARIABLE
JC QWHAT ;"WHAT" NO VARIABLE
PUSH BX ;SAVE ADDR OF VARIABLE
MOV AH,'='
CALL IGNBLNK
JNZ SV1
CALL EXP
MOV CX,BX ;VALUE IN CX NOW
POP BX ;GET ADDR
MOV [BX],CL ;SAVE VALUE
INC BX
MOV [BX],CH ;SAVE VALUE
RET
SV1:
JMP QWHAT ;NO '=' SIGN
;
FIN:
MOV AH,';'
CALL IGNBLNK
JNZ FI1
POP AX
JMP RUNSML
FI1:
MOV AH,0DH
CALL IGNBLNK
JNZ RET
POP AX
JMP RUNNXL ;RUN NEXT LINE
FI2:
RET ;ELSE RETURN TO CALLER
;
ENDCHK:
MOV AH,0DH ;END WITH CR?
CALL IGNBLNK
JZ RET ;OK, ELSE SAY "WHAT?"
;
QWHAT:
PUSH DX ;****QWHAT****
AWHAT:
MOV DX,WHAT ;****AWHAT****
ERROR:
SUB AL,AL ;****ERROR****
CALL PRTSTG ;PRINT 'WHAT?','HOW?'
POP DX
MOV SI,DX
LODB
PUSH AX ;SAVE THE CHARACTER
SUB AL,AL ;AND PUT A ZERO THERE
MOV DI,DX
STOB
MOV BX,[CURRNT] ;GET CURRENT LINE #
CMP W,[CURRNT],0 ;DIRECT COMMAND?
JNZ ERR1 ;IFF ZERO, JUST RESTART
JP ERR2 ;SAVE A BYTE
ERR1: MOV AL,[BX] ;IFF NEGATIVE,
OR AL,AL
JNS ERR1A
JMP INPERR ;REDO INPUT
ERR1A: CALL PRTLN ;ELSE PRINT THE LINE
DEC DX
POP AX
MOV DI,DX
STOB ;RESTORE THE CHAR
MOV AL,63 ;PRINT A '?'
CALL CHROUT
SUB AL,AL ;AND THE REST OF THE
CALL PRTSTG ;LINE
ERR2: JMP RSTART
QSORRY:
PUSH DX ;****QSORRY****
ASORRY:
MOV DX,SORRY ;****ASORRY****
JP ERROR
;
;
; ****GETLN**** AND ****FNDLN****
;
;
; 'GETLN' READS AN INPUT LINE INTO 'BUFFER'. IT FIRST PROMPTS
; THE CHARACTER IN A (GIVEN BY THE CALLER), THEN IT FILLS THE
; BUFFER AND ECHOS IT. IT USES BDOS PRIMITIVES TO ACCOMPLISH
; THIS. ONCE A FULL LINE IS READ IN, 'GETLN' RETURNS.
;
; 'FNDLN' FINDS A LINE WITH A GIVEN LINE #(IN BX) IN THE TEXT
; SAVE AREA. DX IS USED AS THE TEXT POINTER. IFF THE LINE IS
; FOUND, DX WILL POINT TO THE BEGINNING OF THAT LINE IFF THAT
; LINE (I.E. THE LOW BYTE OF THE LINE #), AND FLAGS ARE NC&Z.
; IFF THAT LINE IS NOT THERE AND A LINE WITH A HIGHER LINE #
; IS FOUND, DX POINTS TO THERE AND FLAGS ARE NC&NZ. IFF WE
; REACHED THE END OF TEXT SAVE AREA AND CANNOT FIND THE LINE,
; FLAGS ARE C&NZ.
; 'FNDLN' WILL INITIALIZE DX TO THE BEGINNING OF THE TEXT
; SAVE AREA TO START THE SEARCH. SOME OTHER ENTRIES OF THIS
; ROUTINE WILL NOT INITIALIZE DX AND DO THE SEARCH.
;
; 'FNDLNP' WILL START WITH DX AND SEARCH FOR THE LINE #.
;
; 'FNDNXT' WILL BUMP DX BY 2, FIND A 0DH AND THEN START THE
; SEARCH.
; 'FNDSKP' USES DX TO FIND A CR, AND THEN STARTS THE SEARCH.