;*************************************************************** ;* ;* ;* TINY BASIC FOR INTEL 8086 ;* ;* ;* VERSION: 1.1 ;* ;* BY ;* ;* MICHAEL SULLIVAN ;* BASED ;* ON ;* LI-CHEN WANG'S ;* ;* 8080 TINY BASIC ;* ;* ;* 27 JUNE 1982 ;* ;* @COPYLEFT ;* ALL WRONGS RESERVED ;* ;* NOTE: ;* 8080 REGISTERS HAVE BEEN MAPPED AS FOLLOWS: ;* ;* 8080 8086 ;* ------------------------------------- ;* ;* BC <-> CX ;* DE <-> DX ;* HL <-> BX ;* ;* ;* VERS 1.1 - SUPPORT MS-DOS INTERUPT I/O ;* IMPROVE RND ACTION ;* SUPPORT TIME AND DATE FROM MS-DOS ;* ;************************************************************** ; ; ORG 100H ;STANDARD MS-DOS START ADDR. START: MOV SP,STACK ;SET UP STACK MOV DX,MSG1 ;GET SIGN-ON MSG CALL PRTSTG ;SEND IT MOV B,[BUFFER-2],80H ;INIT CMD LINE BUFFER ; ; MAIN ; ; THIS IS THE MAIN LOOP THAT COLLECTS THE TINY BASIC PROGRAM ; AND STORES IT IN MEMORY. ; ; AT START, IT PRINTS OUT "(CR)OK(LF)", AND INITIALIZES THE ; STACK AND SOME OTHER INTERNAL VARIABLES. THEN IT PROMPTS ; ">" AND READS A LINE. IF THE LINE STARTS WITH A NONZERO ; NUMBER, THIS NUMBER IS THE LINE NUMBER. THE LINE NUMBER ; (IN 16 BIT BINARY) AND THE REST OF THE LINE (INCLUDING ; ITS (CR))IS STORED IN MEMORY. IF A LINE WITH THE SAME ; LINE NUMBER IS ALREADY THERE, IT IS REPLACED BY THE NEW ; ONE. IF THE REST OF THE LINE CONSISTS OF A (CR) ONLY, IT ; IS STORED AND ANY EXISTING LINE WITH THE SAME LINE ; NUMBER IS DELETED. ; ; AFTER A LINE IS INSERTED, REPLACED, OR DELETED, THE ; PROGRAM LOOPS BACK AND ASKS FOR ANOTHER LINE. THIS LOOP ; WILL BE TERMINATED WHEN IT READS A LINE WITH ZERO OR NO ; LINE NUMBER: CONTROL IS THEN TRANSFERED TO "DIRECT". ; ; THE TINY BASIC PROGRAM SAVE AREA STARTS AT THE MEMORY ; LOCATION LABELED "TXTBGN" AND ENDS AT "TXTEND". WE ALWAYS ; FILL THIS AREA STARTING AT "TXTBGN", THE UNFILLED PORTION ; POINTED TO BY THE CONTENTS OF THE MEMORY LOCATION LABELED ; "TXTUNF". ; ; THE MEMORY LOCATION "CURRNT" POINTS TO THE LINE NUMBER ; THAT IS CURRENTLY BEING INTERPRETED. WHILE WE AR IN THIS ; LOOP OR WHILE WE ARE INTERPRETING A DIRECT COMMAND ; (SEE NEXT SECTION), "CURRNT" SHOULD POINT TO A 0. ; RSTART: MOV SP,STACK ;SET STACK POINTER ST1: CALL CRLF MOV DX,OK ;DE->STRING SUB AL,AL CALL PRTSTG ;PRINT PROMPT MOV W,[CURRNT],0 ;CURRENT LINE # = 0 ST2: MOV W,[LOPVAR],0 MOV W,[STKGOS],0 ST3: MOV AL,'>' ;PROMPT ">" NOW CALL GETLN ;READ A LINE PUSH DI ;DI -> END OF LINE ST3A: MOV DX,BUFFER ;DX -> BEGINNING OF LINE CALL TSTNUM ;TEST IF IT'S A NUMBER MOV AH,0 CALL IGNBLNK OR BX,BX ;BX:= VALUE OF # OR 0 IF NO # FOUND POP CX ;CX -> END OF LINE JNZ ST3B JMP DIRECT ST3B: DEC DX DEC DX MOV AX,BX ;GET LINE # MOV DI,DX STOW ;VALUE OF LINE # THERE PUSH CX PUSH DX ;BX,DX -> BEGIN,END MOV AX,CX SUB AX,DX PUSH AX ;AX:= # BYTES IN LINE CALL FNDLN ;FIND THIS LINE IN SAVE PUSH DX ;AREA, DX -> SAVE AREA JNZ ST4 ;NZ:NOT FOUND, INSERT PUSH DX ;Z:FOUND, DELERE IT CALL FNDNXT ;FIND NEXT LINE ;DE -> NEXT LIE POP CX ;CX -> LINE TO BE DELETED MOV BX,[TXTUNF] ;BX -> UNFILLED SAVE AREA CALL MVUP ;MOVE UP TO DELETE MOV BX,CX ;TXTUNF -> UNFILLED AREA MOV [TXTUNF],BX ;UPDATE ST4: POP CX ;GET READY TO INSERT MOV BX,[TXTUNF] ;BUT FIRST CHECK IF POP AX ;AX = # CHARS IN LINE PUSH BX ;IS 3 (LINE # AND CR) CMP AL,3 ;THEN DO NOT INSERT JZ RSTART ;MUST CLEAR THE STACK ADD AX,BX ;COMPUTE NEW TSTUNF MOV BX,AX ;BX -> NEW UNFILLED AREA ST4A: MOV DX,TXTEND ;CHECK TO SEE IF THERE CMP BX,DX ;IS ENOUGH SPACE JC ST4B ;SORRY, NO ROOM FOR IT JMP QSORRY ST4B: MOV [TXTUNF],BX ;OK, UPDATE TXTUNF POP DX ;DX -> OLD UNFILLED AREA CALL MVDOWN POP DX ;DX -> BEGIN, BX -> END POP BX CALL MVUP ;MOVE NEW LINE TO SAVE AREA JP ST3 TSTV: MOV AH,64 ;TEST VARIABLES CALL IGNBLNK JC RET TSTV1: JNZ TV1 ;NOT @ ARRAY CALL PARN ;@ SHOULD BE FOLLOWED ADD BX,BX JNC SS1B ;IS INDEX TOO BIG? JMP QHOW SS1B: PUSH DX ;WILL IT OVERWRITE XCHG DX,BX ;TEXT? CALL SIZE ;FIND SIZE OF FREE CMP BX,DX ;AND CHECK THAT JNC SS1A ;IFF SO, SAY "SORRY" JMP ASORRY SS1A: MOV BX,VARBGN ;IFF NOT, GET ADDRESS SUB BX,DX ;OF @(EXPR) AND PUT IT POP DX ;IN HL RET ;C FLAG IS CLEARED TV1: CMP AL,27 ;NOT @, IS IT A TO Z? CMC: ;IFF NOT, RETURN C FLAG JC RET ;IFF NOT, RETURN C FLAG INC DX TV1A: MOV BX,VARBGN ;COMPUTE ADDRESS OF MOV AH,0 ;CLEAR UPPER BYTE ADD AX,AX ;AX:=AX*2 (WORD STORAGE) ADD BX,AX ;BX:=VARBGN+2*AL RET ;USE CARRY AS ERROR INDICATOR ; ; TSTNUM - AT ENTRY DX -> BUFFER OF ASCII CHARACTERS ; TSTNUM: MOV BX,0 ;****TSTNUM**** MOV CH,BH ;TEST IFF THE TEXT IS MOV AH,0 ;FOR CMP IN IGNBLNK CALL IGNBLNK ;A NUMBER. TN1: CMP AL,'0' ;IFF NOT, RETURN 0 IN JC RET ;B AND HL CMP AL,':' ;IFF NUMBERS, CONVERT JNC RET ;TO BINARY IN BX AND MOV AL,0F0H ;SET AL TO # OF DIGITS AND AL,BH ;IFF BH>255, THERE IS NO JNZ QHOW ;ROOM FOR NEXT DIGIT INC CH ;CH COUNTS NUMBER OF DIGITS PUSH CX MOV AX,BX ;BX:=10*BX+(NEW DIGIT) MOV CX,10 PUSH DX ;SAVE DX MUL AX,CX MOV BX,AX ;PARTIAL RESULT NOW IN BX POP DX ;RESTORE MOV SI,DX LODB ;ASCII DIGIT IN AL NOW SUB AL,48 ;CONVERT TO BINARY MOV AH,0 ADD BX,AX ;FULL RESULT NOW IN BX POP CX LODB ;REPEAT FOR MORE DIGITS LAHF ;SAVE FLAGS INC DX SAHF ;RESTORE FLAGS JNS TN1 ;QUIT IF NO NUM OR OVERFLOW QHOW: PUSH DX ;****ERROR: "HOW?"**** AHOW: MOV DX,HOW JMP ERROR HOW: DB 'HOW?',0DH OK: DB 'OK',0DH WHAT: DB 'WHAT?',0DH SORRY: DB 'SORRY',0DH ; ;* ;********************************************************** ;* ;* *** TABLES *** DIRECT *** & EXEC *** ;* ;* 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 IP3A: MOV DX,BUFFER ; POINTS TO BUFFER CALL EXP ;EVALUATE INPUT NOP ;CAN BE 'CALL ENDCHK' NOP ;CAN BE 'CALL ENDCHK' NOP ;CAN BE 'CALL ENDCHK' POP DX ;OK,GET OLD HL XCHG DX,BX ;OK,GET OLD HL MOV [BX],DX POP BX ;GET OLD 'CURRNT' MOV [CURRNT],BX POP DX ;AND GET OLD TEXT POINTER IP4: POP AX MOV AH,',' CALL IGNBLNK JNZ IP5 JP IP1 ;YES, MORE ITEMS IP5: CALL FINISH ; DEFLT: MOV SI,DX LODB ;****DEFLT**** CMP AL,0DH ;EMPTY LINE IS OK JZ LT1 ;ELSE IT IS 'LET' ; LET: CALL SETVAL ;****LET**** MOV AH,',' CALL IGNBLNK JNZ LT1 JP LET ;ITEM BY ITEM LT1: CALL FINISH ;UNTIL FINISH ; ; ; ****EXPR**** ; ; 'EXPR' EVALUATES ARITHMETICAL OR LOGICAL EXPRESSIONS. ; ::= ; ; ; WHERE IS ONE OF THE OPERATORS IN TAB8 AND THE RE- ; SULT OF THESE OPERATIONS IS 1 IFF TRUE AND 0 IFF FALSE. ; ; ::=(+ OR -)(+ OR -(....) ; ; WHERE () ARE OPTIONAL AND (....) ARE OPTIONAL REPEATS. ; ; ::=(<* OR />)(....) ; ::= ; ; () ; ; IS RECURSIVE SO THAT VARIABLE '@' CAN HAVE AN EXPR ; AS INDEX, FUCTIONS CAN HAVE AN AS ARGUMENTS, AND ; CAN BE AN IN PARANTHESES. ; ; EXP: CALL EXPR2 PUSH BX EXPR1: MOV BX,TAB8-1 ;LOOKUP REL.OP JMP EXEC ;GO DO IT XP11: CALL XP18 JC RET ;NO RETURN HL=0 MOV BL,AL ;YES, RETURN HL=1 RET XP12: CALL XP18 JZ RET ;FALSE, RETURN HL=0 MOV BL,AL ;TRUE, RETURN HL=1 RET XP13: CALL XP18 ;REL.OP '>' JZ RET ;FALSE JC RET ;ALSO FALSE, HL=0 MOV BL,AL ;TRUE, HL=1 RET XP14: CALL XP18 ;REL OP '<=' MOV BL,AL ;SET HL=1 JZ RET ;REL. TRUE, RETURN JC RET ;REL. TRUE, RETURN MOV BL,BH ;ELSE SET HL=0 RET XP15: CALL XP18 ;REL OP '=' JNZ RET ;FALSE, RETURN HL=0 MOV BL,AL ;ELSE SET HL=1 RET XP16: CALL XP18 ;REL.OP '<' JNC RET ;FALSE, RETURN HL=0 MOV BL,AL ;ELSE SET HL=1 RET XP17: POP BX ;NOT REL OP RET ;RETURN HL= XP18: MOV AL,CL ;SUBROUTINE FOR ALL POP BX ;REL.OP'S POP CX ;REL.OP'S PUSH BX ;REVERSE TOP OF STACK PUSH CX ;REVERSE TOP OF STACK MOV CL,AL CALL EXPR2 ;GET 2ND EXPRESSION XCHG DX,BX ;VALUE IN DE NOW POP AX PUSH BX MOV BX,AX ;LAST 3 INSTR FOR XTHL INST! CALL CKHLDE ;COMPARE 1ST WITH SECOND POP DX MOV BX,0 ;SET HL=0, A=1 MOV AL,1 ;SET HL=0, A=1 RET ; EXPR2: MOV AH,'-' CALL IGNBLNK ;NEGATIVE SIGN? JNZ XP21 MOV BX,0 ;YES, FAKE '0-' JP XP26 ;TREAT LIKE SUBTRACT XP21: MOV AH,'+' ;POSITIVE SIGN? CALL IGNBLNK XP22: CALL EXPR3 ;1ST XP23: MOV AH,'+' CALL IGNBLNK ;ADD? JNZ XP25 ;NOTE OFFSET WHAS 21 BYTES IN 8080 VERSION PUSH BX ;YES, SAVE VALUE CALL EXPR3 ;GET 2ND XP24: XCHG DX,BX ;2ND IN DE POP AX ;THIS + NEXT 2 LINES FOR 8080 XTHL INST!! PUSH BX MOV BX,AX ;BX <-> [SP] NOW, [SP]->BUFFER,BX=OLD EXPR3 ADD BX,DX POP DX JNO XP23 ;CHECK FOR OVERFLOW XP24A: JMP QHOW ;ELSE WE HAVE OVERFLOW XP25: MOV AH,'-' CALL IGNBLNK ;SUBTRACT? JNZ RET XP26: PUSH BX ;YES, SAVE 1ST CALL EXPR3 ;GET 2ND CALL CHGSGN JP XP24 ; EXPR3: CALL EXPR4 ;GET 1ST XP31: MOV AH,'*' CALL IGNBLNK ;MULTIPLY? JNZ XP34 PUSH BX ;YES, SAVE 1ST CALL EXPR4 ;AND GET 2ND XCHG DX,BX ;2ND IN DE NOW POP AX ;SUBSITUTE FOR 8080 XTHL PUSH BX IMUL AX,DX ;AX:=AX*DX JO XP32 ;SEE INTEL BOOK ON OVERFLOW FLAG MOV BX,AX ;RESULT NOW IN BX JP XP35 ;LOOK FOR MORE XP34: MOV AH,'/' CALL IGNBLNK ;DIVIDE? JNZ RET PUSH BX ;YES, SAVE 1ST CALL EXPR4 ;AND GET SECOND ONE XCHG DX,BX ;PUT 2ND IN DE POP AX ;REPLACEMENT FOR XTHL PUSH BX MOV BX,AX OR DX,DX JNZ XP34A ;SAY "HOW?" XP32: JMP AHOW XP34A: CALL DIVIDE ;USE SUBROUTINE MOV BX,CX ;GET RESULT MOV CX,6 ;SIX SPACES XP35: POP DX ;AND TEXT POINTER JP XP31 ;LOOK FOR MORE TERMS ; EXPR4: MOV BX,TAB4-1 ;FIND FUCNTION IN TAB4 JMP EXEC ;AND GOT DO IT XP40: CALL TSTV ;NO, NOT A FUNCTION JC XP41 ;NOR A VARIABLE MOV AL,[BX] ;VARIABLE LAHF INC BX SAHF MOV BH,[BX] ;VALUE IN HL MOV BL,AL ;VALUE IN HL RET XP41: CALL TSTNUM ;OR IS IT A NUMBER? MOV AL,CH ;# OF DIGITS OR AL,AL JNZ RET ;OK PARN: MOV AH,'(' CALL IGNBLNK ;NO DIGIT, MUST BE JNZ PARN1 CALL EXP ;"(EXPR)" PARN1: MOV AH,')' CALL IGNBLNK ;"(EXPR)" JNZ XP43 ;******WHY CHECK THIS?****** XP42: RET XP43: JMP QWHAT ;ELSE SAY: "WHAT?" ; RND: CALL PARN ;****RND(EXPR)**** OR BX,BX JNS RND1 ;MUST BE POSITIVE JNZ RND1 ;AND NON-ZERO JMP QHOW RND1: PUSH CX PUSH DX MOV AH,2CH ;GET TIME INT 33 ;ASK MS-DOS MOV AX,327 MOV DH,0 MUL AX,DX ; 0<=AX<=32700 XCHG DX,BX MOV BX,AX CALL DIVIDE ;RND(N)=MOD(M,N)+1 POP DX POP CX INC BX RET ; ABS: CALL PARN ;****ABS(EXPR)**** CALL CHKSGN ;CHECK SIGN OR AX,BX JNS RET ;OK JMP QHOW ;SO SAY: "HOW?" SIZE: MOV BX,[TXTUNF] ;****SIZE**** PUSH DX ;GET THE NUMBER OF FREE XCHG DX,BX ;BYTES BETWEEN 'TXTUNF' SIZEA: MOV BX,VARBGN ;AND 'VARBGN' SUB BX,DX POP DX RET ; ; ; ****OUT**** AND ****INP**** AND ****WAIT**** AND ; ****POKE**** AND ****PEEK**** AND ****USR**** ; ; ; 'OUT I,J(,K,L)' ; ; OUTPUTS EXPRESSION 'J' TO PORT 'I', AND MAY BE REPEATED AS ; IN DATA 'L' TO PORT 'K' AS MANY TIMES AS NEEDED. THIS COM- ; MAND MODIFIES *, A SMALL SECTION OF CODE ABOVE ADDRESS 2K. ; ; 'INP (I)' ; ; THIS FUNCTION RETURNDS DATA READ FROM INPUT PORT 'I' AS ; ITS VALUE. IT ALSO MODIFIES CODE JUST ABOVE 2K. ; ; 'WAIT I,J,K' ; ; THIS COMMAND READS THE STATUS OF PORT 'I', EXCLUSIVE OR'S ; THE RESULT WITH 'K', IF THE RESULT IS ONE, OR IF NOT WITH ; ZERO, AND'S WITH 'J' AND RETURNS WHEN THE RESULT IS NON- ; ZERO. ITS MODIFIED CODE IS ALSO ABOVE 2K. ; ; 'POKE I,J(,K,L) ; ; THIS COMMAND WORKS LIKE OUT EXCEPT THAT IT PUTS DATA 'J' ; INTO MEMORY LOCATION 'I'. ; ; 'PEEK (I)' ; ; THIS FUNCTION WORKS LIKE INP EXCEPT THAT IT PUTS DATA 'J' ; FROM MEMORY LOCATION 'I'. ; ; 'USR(I(,J))' ; ; USR CALL A MACHINE LANGUAGE SUBROUTINE AT LOCATION 'I' IF ; THE OPTIONAL PARAMETER 'J' IS USED ITS VALUE IS PASSED IN ; HL. THE VALUE OF THE FUNCTION SHOULD BE RETURNED IN HL. ; ; OUTCMD: CALL EXP MOV AL,BL MOV [OUTIO+1],AL MOV AH,',' CALL IGNBLNK JZ OUT1 ;FOUND MORE TO WORK ON JMP QWHAT OUT1: CALL EXP MOV AL,BL CALL OUTIO MOV AH,',' CALL IGNBLNK JNZ OUTCMD1 JP OUTCMD OUTCMD1:CALL FINISH WAITCM: CALL EXP MOV AL,BL MOV [WAITIO+1],AL MOV AH,',' CALL IGNBLNK JZ WT1 JMP QWHAT WT1: CALL EXP PUSH BX MOV AH,',' CALL IGNBLNK JNZ WAIT1 CALL EXP MOV AL,BL POP BX MOV BL,AL JP WAIT2 WAIT1: MOV BH,0 WAIT2: JMP WAITIO INP: CALL PARN MOV AL,BL MOV [INPIO+1],AL MOV BX,0 JMP INPIO JP QWT POKE: CALL EXP PUSH BX MOV AH,',' CALL IGNBLNK JZ POK1 JMP QWHAT POK1: CALL EXP MOV AL,BL POP BX MOV [BX],AL MOV AH,',' CALL IGNBLNK JNZ POK2 JP POKE 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. ; ; ; GETLN: CALL CHROUT ;****GETLN**** GL1: MOV DX,BUFFER-2 PUSH DX MOV AH,BCONIN ;BUFFERED CONSOLE INPUT INT 33 ;CALL MS-DOS POP DX ADD DL,[BUFFER-1] INC DX INC DX INC DX MOV DI,DX ;FOR CONSISTANCY PUSH DX CALL CRLF ;NEED CRLF POP DX RET ;WE'VE GOT A LINE ; ; AT ENTRY BX -> LINE # TO BE FOUND ; FNDLN: OR BX,BX ;CHECK SIGN OF BX JNS FND1 ;IT CAN'T BE - JMP QHOW ;ERROR FND1: MOV DX,TXTBGN ; FNDLNP: FL1: PUSH BX ;SAVE LINE # MOV BX,[TXTUNF] ;CHECK IFF WE PASSED END DEC BX CMP BX,DX ;SUBSTITUTE FOR CALL 4 POP BX ;GET LINE # BACK JC RET ;C, NZ PASSED END MOV SI,DX LODW CMP AX,BX JC FL2 RET ;NC,Z:FOUND;NC,NZ:NOT FOUND ; FNDNXT: ;****FNDNXT**** INC DX FL2: INC DX ; FNDSKP: MOV SI,DX LODB ;****FNDSKP**** CMP AL,0DH ;TRY TO FIND CR JNZ FL2 ;KEEP LOOKING INC DX JP FL1 ;CHECK IFF END OF TEXT ; ; ; **** PRTSTG **** QTSTG **** PRTNUM **** PRTLN **** ; ; ; 'PRTSTG PRINTS A STRING POINTED TO BY DX. IT STOPS PRINTING ; AND RETURNS TO CALLER WHEN EITHER A 0DH IS PRINTED OR WHEN ; THE NEXT BYTE IS THE SAMES AS WHAT WAS IN A ( GIVEN BY THE ; CALLER). OLD AL IS STORED IN CH, OLD CH IS LOST. ; ; 'QTSTG' LOOKS FOR A BACK-SLASH, SINGLE QUOTE, OR DOUBLE ; QUOTE. IFF NONE OF THESE, RETURN TO CALLER. IF BACK SLASH \ ; OUTPUT A ODH WITHOUT A LF. IFF SINGLE OR DOUBLE QUOTE,PRINT ; THE STRING IN THE QUOTE AND DEMANDS A MATCHING UNQUOTE. AF- ; TER THE PRINTING THE NEXT 3 BYTES OF THE CALLER IS SKIPPED ; OVER (USUALLY A JMP INSTRUCTION). ; ; 'PRTNUM' PRINTS THE NUMBER IN HL. LEADING BLANKS ARE ADDED ; IFF NEEDED TO PAD THE NUMBER OF SPACES TO THE NUMBER IN C. ; NOWEVER, IFF THE NUMBER OF DIGITS IS LARGER THAN THE NUMBER ; IN C, ALL DIGITS ARE PRINTED ANYWAY. NEGATIVE SIGN IS ALSO ; PRINTED AND COUNTED IN, POSITIVE SIGN IS NOT. ; ; 'PRTLN' PRINTS A SAVED TEXT LINE WITH LINE # AND ALL. ; ; ; PRTSTG: MOV CH,AL ;****PRTSTG**** PS1: MOV SI,DX LODB ;GET A CHAR LAHF ;PRESERVE FLAGS INC DX SAHF ;RESTORE FLAGS CMP AL,CH ;SAME AS OLD A? JNZ PS2 ;YES, RETURN RET PS2: CALL CHROUT ;ELSE, PRINT IT CMP AL,0DH ;WAS IT A CR? JNZ PS1 ;NO, NEXT RET ; QTSTG: MOV AH,'"' CALL IGNBLNK JNZ QT3 MOV AL,34 ;IT IS A '"' QT1: CALL PRTSTG ;PRINT UNTIL ANOTHER CMP AL,0DH ;WAS LAST ONE A CR? POP BX ;RETURN ADDRESS JNZ QT2 ;WAS CR, RUN NEXT LINE JMP RUNNXL QT2: INC BX ;SKIPS TWO BYTES ON RETURN!!!! INC BX JMP BX ;JUMP TO ADDRESS IN BX QT3: MOV AH,39 ;IS IT A SINGLE QUOTE (')? CALL IGNBLNK JNZ QT4 MOV AL,39 ;YES, DO SAME JP QT1 ;AS IN ' " ' QT4: MOV AH,'\' CALL IGNBLNK ;IS IT BACK-SLASH?('\') JNZ QT5 MOV AL,141 ;YES, 0DH WITHOUT LF! CALL CHROUT ;DO IT TWICE CALL CHROUT ;TO GIVE TTY ENOUGH TIME POP BX ;RETURN ADDRESS JP QT2 QT5: RET ;NONE OF THE ABOVE ; ; ON ENTRY BX = BINARY #,CL = # SPACES ; PRTNUM: PUSH DX ;****PRTNUM**** MOV DX,10 ;DECIMAL PUSH DX ;SAVE AS A FLAG MOV CH,DH ;CH=SIGN DEC CL ;CL=SPACES CALL CHKSGN ;CHECK SIGN JNS PN1 ;NO SIGN MOV CH,45 ;CH=SIGN DEC CL ;'-' TAKES SPACE PN1: PUSH CX ;SAVE SIGN % SPACE PN2: CALL DIVIDE ;DIVIDE BX BY 10 (IN DX) OR CX,CX ;CX HAS QUOTIENT JZ PN3 ;YES, WE GOT ALL POP AX ;GET SIGN AND SPACE COUNT PUSH BX ;SAVE REMAINDER DEC AL ;DEC SPACE COUNT PUSH AX ;SAVE NEW SIGN AND SPACE COUNT MOV BX,CX ;MOVE RESULT TO BX JP PN2 ;AND DIVIDE BY 10 PN3: POP CX ;WE GOT ALL DIGITS IN PN4: DEC CL ;THE STACK MOV AL,CL ;LOOK AT SPACE COUNT OR AL,AL JS PN5 ;NO LEADING BLANKS MOV AL,32 ;LEADING BLANKS CALL CHROUT JP PN4 PN5: MOV AL,CH ;PRINT SIGN CALL CHROUT ;MAYBE, OR NULL MOV DL,BL ;LAST REMAINDER IN E PN6: MOV AL,DL ;CHECK DIGIT IN E CMP AL,10 ;10 IS FLAG FOR NO MORE POP DX JZ RET ;IFF SO, RETURN ADD AL,48 ;ELSE CONVERT TO ASCII CALL CHROUT ;AND PRINT THE DIGIT JP PN6 ;GO BACK FOR MORE ; PRTLN: MOV SI,DX LODW MOV BX,AX INC DX INC DX ;MOVE POINTER PRTLN1: MOV CL,5 ;PRINT 5 DIGIT LINE # CALL PRTNUM MOV AL,32 ;FOLLOWED BY A BLANK CALL CHROUT SUB AL,AL ;AND THEN THE TEXT CALL PRTSTG RET ; ; ; ; **** MVUP **** MVDOWN **** POPA **** PUSHA **** ; ; 'MVUP' MOVES A BLOCK UP FROM WHERE DX -> WHERE CX -> UNTIL ; DX = BX ; ; 'MVDOWN' MOVES A BLOCK DOWN FROM WHERE DX -> TO WHERE BX-> ; UNTIL DX = CX. ; ; 'POPA' RESTORES THE 'FOR' LOOP VAR SAVE AREA FROM THE STACK. ; ; 'PUSHA' STACKS THE 'FOR' LOOP VARIABLE SAVE AREA IN THE STACK ; ; MVUP: CMP DX,BX ;***MVUP*** JZ RET ;DE = HL, RETURN MOV SI,DX LODB ;GET ONE BYTE MOV DI,CX STOB ;MOVE IT INC DX INC CX JP MVUP ;UNTIL DONE ; MVDOWN: CMP DX,CX JZ RET ;YES, RETURN MD1: LAHF DEC DX DEC BX MOV SI,DX LODB ;BOTH POINTERS AND MOV [BX],AL ;THEN DO IT JP MVDOWN ;LOOP BACK ; POPA: POP CX ;CX = RETURN ADDR POP BX ;RESTORE LOPVAR, BUT MOV [LOPVAR],BX ;=0 MEANS NO MORE OR BX,BX JZ PP1 ;YES, GO RETURN POP BX ;NO, RESTORE OTHERS MOV [LOPINC],BX POP BX MOV [LOPLMT],BX POP BX MOV [LOPLN],BX POP BX MOV [LOPPT],BX PP1: PUSH CX ;CX = RETURN ADDR RET ; PUSHA: MOV BX,STKLMT ;****PUSHA**** CALL CHGSGN POP CX ;CX=RET ADDR ADD BX,SP JC PUSHB ;YES, SORRY FOR THAT. JMP QSORRY PUSHB: MOV BX,[LOPVAR] ;ELSE SAVE LOOP VARS OR BX,BX ;THAT WILL BE ALL JZ PU1 MOV BX,[LOPPT] ;ELSE, MORE TO SAVE PUSH BX MOV BX,[LOPLN] ;ELSE, MORE TO SAVE PUSH BX MOV BX,[LOPLMT] PUSH BX MOV BX,[LOPINC] PUSH BX MOV BX,[LOPVAR] PU1: PUSH BX PUSH CX ;CX = RETURN ADDR RET ; ; ; **** OUTC **** CHKIO **** ; ; ; THESE ARE THE ONLY I/O ROUTINES IN TBI. ; ; ; 'CHKIO' CHECKS THE INPUT, IFF NO INPUT, IT WILL RETURN TO THE ; CALLER WITH THE Z FLAG SET. IFF THERE IS INPUT, THE Z FLAG IS ; CLEARED AND THE INPUT BYRE IS IN A. HOWEVER, IFF THE INPUT IS ; A CONTROL-O, THE 'OCSW' IS COMPLIMENTED, AND THE Z FLAG IS RE- ; TURNED. IFF A CONTROL-C IS READ, 'CHKIO' WILL RESTART TBI AND ; DOES NOT RETURN TO THE CALLER. ; CRLF: MOV AL,0DH ;****CRLF**** CHROUT: CMP [OCSW],0 JZ COUT1 ;SEE IF OUTPUT REDIRECTED PUSH CX ;SAVE CX ON STACK PUSH DX ;AND DX PUSH BX ;AND BX TOO MOV [OUTCAR],AL ;SAVE CHATACTER MOV DL,AL ;PUT CHAR IN E FOR CP/M MOV AH,CONOUT ;CONSOLE OUTPUT INT 33 ;CALL MS-DOS AND OUTPUT CHAR MOV AL,[OUTCAR] ;GET CHAR. BACK CMP AL,0DH ;WAS IT A 'CR'? JNZ DONE ;NO,DONE MOV DL,0AH ;GET LINEFEED MOV AH,CONOUT ;CONSOLE OUTPUT AGAIN INT 33 ;CALL MS-DOS DONE: MOV AL,[OUTCAR] ;GET CHAR BACK IDONE: POP BX ;GET H BACK POP DX ;AND D POP CX ;THEN H RET ;DONE AT LAST COUT1: CMP B,AL,0 ;IS IT NULL? JZ RET ;SKIP IT STOB ;STORE AL (CHAR) IN BUFFER INC [BUFFER-1] ;INCREMENT COUNTER RET ;DONE CHKIO: PUSH CX ;SAVE B ON STACK PUSH DX ;AND D PUSH BX ;THEN H MOV AH,CONST ;GET CONSOLE STATUS WORD INT 33 ;CALL MS-DOS OR AL,AL ;SET FLAGS JNZ CI1 ;IF READY, GET CHAR JP IDONE ;RESTORE AND RETURN CI1: MOV AH,1 ;CALL THE BDOS INT 33 ;CALL MS-DOS CI2: CMP AL,18H ;IS TI CONTROL-X? JNZ IDONE ;RETURN AND RESTORE IF NOT JMP RSTART ;YES, RESTART TBI LSTROM: EQU $ ;ALL ABOVE CAN BE ROM OUTIO: OUTB 0FFH RET WAITIO: INB 0FFH XOR AL,BH AND AL,BL JZ WAITIO CALL FINISH INPIO: INB 0FFH MOV BL,AL RET ; ; ; IGNBLNK ; ; DEBLANKS WHERE DX-> ; IF (DX)=AH THEN DX:=DX+1 ; IGNBLNK:MOV SI,DX IGN1: LODB ;GET CHAR IN AL CMP AL,32 ;IGNORE BLANKS JNZ IGN2 ;IN TEXT (WHERE DX ->) INC DX JP IGN1 IGN2: CMP AL,AH ;IS SEARCH CHARACTER FOUND AT (DX)? JNZ RET ;NO, RETURN, POINTER (DX) STAYS LAHF ;SAVE RESULTS OF COMPARISON INC DX ;INC POINTER IF CHARACTER MATCHES SAHF ;RETURN RESULT OF COMPARISON TO FLAGS RET ; FINISH: POP AX CALL FIN ;CHECK END OF COMMAND JMP QWHAT ;PRINT "WHAT?" IFF WRONG ; OUTCAR: DB 0 ;OUTPUT CHAR STORAGE OCSW: DB 0FFH ;OUTPUT SWITCH CURRNT: DW 0 ;POINTS TO CURRENT LINE STKGOS: DW 0 ;SAVES SP IN 'GOSUB' VARNXT: DW 0 ;TEMP STORAGE STKINP: DW 0 ;SAVES SP IN 'INPUT' LOPVAR: DW 0 ;'FOR' LOOP SAVE AREA LOPINC: DW 0 ;INCREMENT LOPLMT: DW 0 ;LIMIT LOPLN: DW 0 ;LINE NUMBER LOPPT: DW 0 ;TEST POINTER RANPNT: DW 0 ;RANDOM NUMBER POINTER TXTUNF: DW TXTBGN ;-> UNFILLED TEXT AREA TXTBGN: DS 1 MSG1: DB '8086 TINY BASIC V1.1 27 JUNE 82',0DH ORG 2000H ;MISC STORAGE, INCLUDING STACK TXTEND: EQU $ ;TEST AREA SAVE AREA ENDS VARBGN: DS 54 ;VARIABLE @(0) DB 80 ;MAX CHARS IN BUFFER DB 0 ;CHAR COUNT BUFFER: DS 80 ;BUFFER MUST BE AFTER TEXT AREA BUFEND: EQU $ DS 400 ;EXTRA BYTES FOR STACK STKLMT: DS 100 ;TOP LIMIT FOR STACK STACK: EQU $ ;STACK STARTS HERE END