Skip to content

Instantly share code, notes, and snippets.

@maly
Created September 11, 2020 11:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maly/813858080d3fed142f2554af392ae964 to your computer and use it in GitHub Desktop.
Save maly/813858080d3fed142f2554af392ae964 to your computer and use it in GitHub Desktop.
0000 ;*************************************************************
0000 ;
0000 ; TINY BASIC FOR INTEL 8080
0000 ; VERSION 2.0
0000 ; BY LI-CHEN WANG
0000 ; MODIFIED AND TRANSLATED
0000 ; TO INTEL MNEMONICS
0000 ; BY ROGER RAUSKOLB
0000 ; 10 OCTOBER,1976
0000 ; @COPYLEFT
0000 ; ALL WRONGS RESERVED
0000 ;
0000 ;*************************************************************
0000 ;
0000 ; *** ZERO PAGE SUBROUTINES ***
0000 ;
0000 ; THE 8080 INSTRUCTION SET LETS YOU HAVE 8 ROUTINES IN LOW
0000 ; MEMORY THAT MAY BE CALLED BY RST N, N BEING 0 THROUGH 7.
0000 ; THIS IS A ONE BYTE INSTRUCTION AND HAS THE SAME POWER AS
0000 ; THE THREE BYTE INSTRUCTION CALL LLHH. TINY BASIC WILL
0000 ; USE RST 0 AS START AND RST 1 THROUGH RST 7 FOR
0000 ; THE SEVEN MOST FREQUENTLY USED SUBROUTINES.
0000 ; TWO OTHER SUBROUTINES (CRLF AND TSTNUM) ARE ALSO IN THIS
0000 ; SECTION. THEY CAN BE REACHED ONLY BY 3-BYTE CALLS.
0000 ;
0000 ;
0000 .ENGINE alpha
0000 .macro DWA,
0000 ;
0000 DB >%%1 + 128
0000 DB <%%1
0000 .endm
0000
0000 ;
1000 .ORG 1000H
1000 31 FF FF START: LXI SP,STACK ;*** COLD START ***
1003 3E FF MVI A,0FFH
1005 C3 FD 16 JMP INIT
1008 ;
1008 ;
1008 3E 0D CRLF: MVI A,CR ;*** CRLF ***
100A ;
100A RST2:
100A OUTC:
100A F5 PUSH PSW ;*** OUTC OR RST 2 ***
100B 3A 03 80 LDA OCSW ;PRINT CHARACTER ONLY
100E B7 ORA A ;IF OCSW SWITCH IS ON
100F C3 27 17 JMP OC2 ;REST OF THIS IS AT OC2
1012 ;
1012 RST3:
1012 EXPR:
1012 CD D2 13 CALL EXPR2 ;*** EXPR OR RST 3 ***
1015 E5 PUSH H ;EVALUATE AN EXPRESSION
1016 C3 8E 13 JMP EXPR1 ;REST OF IT AT EXPR1
1019 57 DB "W"
101A ;
101A RST4:
101A COMP:
101A 7C MOV A,H ;*** COMP OR RST 4 ***
101B BA CMP D ;COMPARE HL WITH DE
101C C0 RNZ ;RETURN CORRECT C AND
101D 7D MOV A,L ;Z FLAGS
101E BB CMP E ;BUT OLD A IS LOST
101F C9 RET
1020 41 4E DB "AN"
1022 ;
1022 RST5:
1022 IGNBLK:
1022 1A SS1: LDAX D ;*** IGNBLK/RST 5 ***
1023 FE 20 CPI 20H ;IGNORE BLANKS
1025 C0 RNZ ;IN TEXT (WHERE DE->)
1026 13 INX D ;AND RETURN THE FIRST
1027 C3 22 10 JMP SS1 ;NON-BLANK CHAR. IN A
102A ;
102A RST6:
102A FINISH:
102A F1 POP PSW ;*** FINISH/RST 6 ***
102B CD 4A 15 CALL FIN ;CHECK END OF COMMAND
102E C3 63 15 JMP QWHAT ;PRINT "WHAT?" IF WRONG
1031 47 DB "G"
1032 ;
1032 RST7:
1032 TSTV:
1032 CD 22 10 CALL IGNBLK ;*** TSTV OR RST 7 ***
1035 D6 40 SUI 40H ;TEST VARIABLES
1037 D8 RC ;C:NOT A VARIABLE
1038 C2 56 10 JNZ TV1 ;NOT "@" ARRAY
103B 13 INX D ;IT IS THE "@" ARRAY
103C CD 89 14 CALL PARN ;@ SHOULD BE FOLLOWED
103F 29 DAD H ;BY (EXPR) AS ITS INDEX
1040 DA A4 10 JC QHOW ;IS INDEX TOO BIG?
1043 D5 PUSH D ;WILL IT OVERWRITE
1044 EB XCHG ;TEXT?
1045 CD E8 14 CALL SIZE ;FIND SIZE OF FREE
1048 CD 1A 10 CALL COMP ;AND CHECK THAT
104B DA 93 15 JC ASORRY ;IF SO, SAY "SORRY"
104E 21 00 FC LXI H,VARBGN ;IF NOT GET ADDRESS
1051 CD 0B 15 CALL SUBDE ;OF @(EXPR) AND PUT IT
1054 D1 POP D ;IN HL
1055 C9 RET ;C FLAG IS CLEARED
1056 FE 1B TV1: CPI 1BH ;NOT @, IS IT A TO Z?
1058 3F CMC ;IF NOT RETURN C FLAG
1059 D8 RC
105A 13 INX D ;IF A THROUGH Z
105B 21 00 FC LXI H,VARBGN ;COMPUTE ADDRESS OF
105E 07 RLC ;THAT VARIABLE
105F 85 ADD L ;AND RETURN IT IN HL
1060 6F MOV L,A ;WITH C FLAG CLEARED
1061 3E 00 MVI A,0
1063 8C ADC H
1064 67 MOV H,A
1065 C9 RET
1066 ;
1066 RST1:
1066 TSTC:
1066 E3 XTHL ;*** TSTC OR RST 1 ***
1067 CD 22 10 CALL IGNBLK ;IGNORE BLANKS AND
106A BE CMP M ;TEST CHARACTER
106B 23 TC1: INX H ;COMPARE THE BYTE THAT
106C CA 76 10 JZ TC2 ;FOLLOWS THE RST INST.
106F C5 PUSH B ;WITH THE TEXT (DE->)
1070 4E MOV C,M ;IF NOT =, ADD THE 2ND
1071 06 00 MVI B,0 ;BYTE THAT FOLLOWS THE
1073 09 DAD B ;RST TO THE OLD PC
1074 C1 POP B ;I.E., DO A RELATIVE
1075 1B DCX D ;JUMP IF NOT =
1076 13 TC2: INX D ;IF =, SKIP THOSE BYTES
1077 23 INX H ;AND CONTINUE
1078 E3 XTHL
1079 C9 RET
107A ;
107A 21 00 00 TSTNUM: LXI H,0 ;*** TSTNUM ***
107D 44 MOV B,H ;TEST IF THE TEXT IS
107E CD 22 10 CALL IGNBLK ;A NUMBER
1081 FE 30 TN1: CPI 30H ;IF NOT, RETURN 0 IN
1083 D8 RC ;B AND HL
1084 FE 3A CPI 3AH ;IF NUMBERS, CONVERT
1086 D0 RNC ;TO BINARY IN HL AND
1087 3E F0 MVI A,0F0H ;SET B TO # OF DIGITS
1089 A4 ANA H ;IF H>255, THERE IS NO
108A C2 A4 10 JNZ QHOW ;ROOM FOR NEXT DIGIT
108D 04 INR B ;B COUNTS # OF DIGITS
108E C5 PUSH B
108F 44 MOV B,H ;HL=10*HL+(NEW DIGIT)
1090 4D MOV C,L
1091 29 DAD H ;WHERE 10* IS DONE BY
1092 29 DAD H ;SHIFT AND ADD
1093 09 DAD B
1094 29 DAD H
1095 1A LDAX D ;AND (DIGIT) IS FROM
1096 13 INX D ;STRIPPING THE ASCII
1097 E6 0F ANI 0FH ;CODE
1099 85 ADD L
109A 6F MOV L,A
109B 3E 00 MVI A,0
109D 8C ADC H
109E 67 MOV H,A
109F C1 POP B
10A0 1A LDAX D ;DO THIS DIGIT AFTER
10A1 F2 81 10 JP TN1 ;DIGIT. S SAYS OVERFLOW
10A4 D5 QHOW: PUSH D ;*** ERROR "HOW?" ***
10A5 11 AB 10 AHOW: LXI D,HOW
10A8 C3 67 15 JMP ERROR
10AB 48 4F 57 3F HOW: DB "HOW?"
10AF 0D DB CR
10B0 4F 4B OK: DB "OK"
10B2 0D DB CR
10B3 57 48 41 54 3F WHAT: DB "WHAT?"
10B8 0D DB CR
10B9 53 4F 52 52 59 SORRY: DB "SORRY"
10BE 0D DB CR
10BF ;
10BF ;*************************************************************
10BF ;
10BF ; *** MAIN ***
10BF ;
10BF ; THIS IS THE MAIN LOOP THAT COLLECTS THE TINY BASIC PROGRAM
10BF ; AND STORES IT IN THE MEMORY.
10BF ;
10BF ; AT START, IT PRINTS OUT "(CR)OK(CR)", AND INITIALIZES THE
10BF ; STACK AND SOME OTHER INTERNAL VARIABLES. THEN IT PROMPTS
10BF ; ">" AND READS A LINE. IF THE LINE STARTS WITH A NON-ZERO
10BF ; NUMBER, THIS NUMBER IS THE LINE NUMBER. THE LINE NUMBER
10BF ; (IN 16 BIT BINARY) AND THE REST OF THE LINE (INCLUDING CR)
10BF ; IS STORED IN THE MEMORY. IF A LINE WITH THE SAME LINE
10BF ; NUMBER IS ALREADY THERE, IT IS REPLACED BY THE NEW ONE. IF
10BF ; THE REST OF THE LINE CONSISTS OF A CR ONLY, IT IS NOT STORED
10BF ; AND ANY EXISTING LINE WITH THE SAME LINE NUMBER IS DELETED.
10BF ;
10BF ; AFTER A LINE IS INSERTED, REPLACED, OR DELETED, THE PROGRAM
10BF ; LOOPS BACK AND ASKS FOR ANOTHER LINE. THIS LOOP WILL BE
10BF ; TERMINATED WHEN IT READS A LINE WITH ZERO OR NO LINE
10BF ; NUMBER; AND CONTROL IS TRANSFERED TO "DIRECT".
10BF ;
10BF ; TINY BASIC PROGRAM SAVE AREA STARTS AT THE MEMORY LOCATION
10BF ; LABELED "TXTBGN" AND ENDS AT "TXTEND". WE ALWAYS FILL THIS
10BF ; AREA STARTING AT "TXTBGN", THE UNFILLED PORTION IS POINTED
10BF ; BY THE CONTENT OF A MEMORY LOCATION LABELED "TXTUNF".
10BF ;
10BF ; THE MEMORY LOCATION "CURRNT" POINTS TO THE LINE NUMBER
10BF ; THAT IS CURRENTLY BEING INTERPRETED. WHILE WE ARE IN
10BF ; THIS LOOP OR WHILE WE ARE INTERPRETING A DIRECT COMMAND
10BF ; (SEE NEXT SECTION). "CURRNT" SHOULD POINT TO A 0.
10BF ;
10BF 31 FF FF RSTART: LXI SP,STACK
10C2 CD 08 10 ST1: CALL CRLF ;AND JUMP TO HERE
10C5 11 B0 10 LXI D,OK ;DE->STRING
10C8 97 SUB A ;A=0
10C9 CD 07 16 CALL PRTSTG ;PRINT STRING UNTIL CR
10CC 21 D3 10 LXI H,ST2+1 ;LITERAL 0
10CF 22 04 80 SHLD CURRNT ;CURRENT->LINE # = 0
10D2 21 00 00 ST2: LXI H,0
10D5 22 0C 80 SHLD LOPVAR
10D8 22 06 80 SHLD STKGOS
10DB 3E 3E ST3: MVI A,3EH ;PROMPT ">" AND
10DD CD 99 15 CALL GETLN ;READ A LINE
10E0 D5 PUSH D ;DE->END OF LINE
10E1 11 37 FC LXI D,BUFFER ;DE->BEGINNING OF LINE
10E4 CD 7A 10 CALL TSTNUM ;TEST IF IT IS A NUMBER
10E7 CD 22 10 CALL IGNBLK
10EA 7C MOV A,H ;HL=VALUE OF THE # OR
10EB B5 ORA L ;0 IF NO # WAS FOUND
10EC C1 POP B ;BC->END OF LINE
10ED CA 05 18 JZ DIRECT
10F0 1B DCX D ;BACKUP DE AND SAVE
10F1 7C MOV A,H ;VALUE OF LINE # THERE
10F2 12 STAX D
10F3 1B DCX D
10F4 7D MOV A,L
10F5 12 STAX D
10F6 C5 PUSH B ;BC,DE->BEGIN, END
10F7 D5 PUSH D
10F8 79 MOV A,C
10F9 93 SUB E
10FA F5 PUSH PSW ;A=# OF BYTES IN LINE
10FB CD DD 15 CALL FNDLN ;FIND THIS LINE IN SAVE
10FE D5 PUSH D ;AREA, DE->SAVE AREA
10FF C2 12 11 JNZ ST4 ;NZ:NOT FOUND, INSERT
1102 D5 PUSH D ;Z:FOUND, DELETE IT
1103 CD FB 15 CALL FNDNXT ;FIND NEXT LINE
1106 ;DE->NEXT LINE
1106 C1 POP B ;BC->LINE TO BE DELETED
1107 2A 18 80 LHLD TXTUNF ;HL->UNFILLED SAVE AREA
110A CD 9E 16 CALL MVUP ;MOVE UP TO DELETE
110D 60 MOV H,B ;TXTUNF->UNFILLED AREA
110E 69 MOV L,C
110F 22 18 80 SHLD TXTUNF ;UPDATE
1112 C1 ST4: POP B ;GET READY TO INSERT
1113 2A 18 80 LHLD TXTUNF ;BUT FIRST CHECK IF
1116 F1 POP PSW ;THE LENGTH OF NEW LINE
1117 E5 PUSH H ;IS 3 (LINE # AND CR)
1118 FE 03 CPI 3 ;THEN DO NOT INSERT
111A CA BF 10 JZ RSTART ;MUST CLEAR THE STACK
111D 85 ADD L ;COMPUTE NEW TXTUNF
111E 6F MOV L,A
111F 3E 00 MVI A,0
1121 8C ADC H
1122 67 MOV H,A ;HL->NEW UNFILLED AREA
1123 11 00 FC LXI D,TXTEND ;CHECK TO SEE IF THERE
1126 CD 1A 10 CALL COMP ;IS ENOUGH SPACE
1129 D2 92 15 JNC QSORRY ;SORRY, NO ROOM FOR IT
112C 22 18 80 SHLD TXTUNF ;OK, UPDATE TXTUNF
112F D1 POP D ;DE->OLD UNFILLED AREA
1130 CD A9 16 CALL MVDOWN
1133 D1 POP D ;DE->BEGIN, HL->END
1134 E1 POP H
1135 CD 9E 16 CALL MVUP ;MOVE NEW LINE TO SAVE
1138 C3 DB 10 JMP ST3 ;AREA
113B ;
113B ;*************************************************************
113B ;
113B ; WHAT FOLLOWS IS THE CODE TO EXECUTE DIRECT AND STATEMENT
113B ; COMMANDS. CONTROL IS TRANSFERED TO THESE POINTS VIA THE
113B ; COMMAND TABLE LOOKUP CODE OF "DIRECT" AND "EXEC" IN LAST
113B ; SECTION. AFTER THE COMMAND IS EXECUTED, CONTROL IS
113B ; TRANSFERED TO OTHERS SECTIONS AS FOLLOWS:
113B ;
113B ; FOR "LIST", "NEW", AND "STOP": GO BACK TO "RSTART"
113B ; FOR "RUN": GO EXECUTE THE FIRST STORED LINE IF ANY, ELSE
113B ; GO BACK TO "RSTART".
113B ; FOR "GOTO" AND "GOSUB": GO EXECUTE THE TARGET LINE.
113B ; FOR "RETURN" AND "NEXT": GO BACK TO SAVED RETURN LINE.
113B ; FOR ALL OTHERS: IF "CURRENT" -> 0, GO TO "RSTART", ELSE
113B ; GO EXECUTE NEXT COMMAND. (THIS IS DONE IN "FINISH".)
113B ;*************************************************************
113B ;
113B ; *** NEW *** STOP *** RUN (& FRIENDS) *** & GOTO ***
113B ;
113B ; "NEW(CR)" SETS "TXTUNF" TO POINT TO "TXTBGN"
113B ;
113B ; "STOP(CR)" GOES BACK TO "RSTART"
113B ;
113B ; "RUN(CR)" FINDS THE FIRST STORED LINE, STORE ITS ADDRESS (IN
113B ; "CURRENT"), AND START EXECUTE IT. NOTE THAT ONLY THOSE
113B ; COMMANDS IN TAB2 ARE LEGAL FOR STORED PROGRAM.
113B ;
113B ; THERE ARE 3 MORE ENTRIES IN "RUN":
113B ; "RUNNXL" FINDS NEXT LINE, STORES ITS ADDR. AND EXECUTES IT.
113B ; "RUNTSL" STORES THE ADDRESS OF THIS LINE AND EXECUTES IT.
113B ; "RUNSML" CONTINUES THE EXECUTION ON SAME LINE.
113B ;
113B ; "GOTO EXPR(CR)" EVALUATES THE EXPRESSION, FIND THE TARGET
113B ; LINE, AND JUMP TO "RUNTSL" TO DO IT.
113B ;
113B CD 5D 15 NEW: CALL ENDCHK ;*** NEW(CR) ***
113E 21 1A 80 LXI H,TXTBGN
1141 22 18 80 SHLD TXTUNF
1144 ;
1144 CD 5D 15 STOP: CALL ENDCHK ;*** STOP(CR) ***
1147 C3 BF 10 JMP RSTART
114A ;
114A C3 00 00 BYE: JMP 0
114D ;
114D CD 5D 15 RUN: CALL ENDCHK ;*** RUN(CR) ***
1150 11 1A 80 LXI D,TXTBGN ;FIRST SAVED LINE
1153 ;
1153 21 00 00 RUNNXL: LXI H,0 ;*** RUNNXL ***
1156 CD E5 15 CALL FNDLP ;FIND WHATEVER LINE #
1159 DA BF 10 JC RSTART ;C:PASSED TXTUNF, QUIT
115C ;
115C EB RUNTSL: XCHG ;*** RUNTSL ***
115D 22 04 80 SHLD CURRNT ;SET "CURRENT"->LINE #
1160 EB XCHG
1161 13 INX D ;BUMP PASS LINE #
1162 13 INX D
1163 ;
1163 CD 41 17 RUNSML: CALL CHKIO ;*** RUNSML ***
1166 21 7F 17 LXI H,TAB2-1 ;FIND COMMAND IN TAB2
1169 C3 08 18 JMP EXEC ;AND EXECUTE IT
116C ;
116C CD 12 10 GOTO: CALL EXPR ;*** GOTO EXPR ***
116F D5 PUSH D ;SAVE FOR ERROR ROUTINE
1170 CD 5D 15 CALL ENDCHK ;MUST FIND A CR
1173 CD DD 15 CALL FNDLN ;FIND THE TARGET LINE
1176 C2 A5 10 JNZ AHOW ;NO SUCH LINE #
1179 F1 POP PSW ;CLEAR THE PUSH DE
117A C3 5C 11 JMP RUNTSL ;GO DO IT
117D ;
117D ;
117D OUTP:
117D CD 12 10 CALL EXPR
1180 7D MOV a,l
1181 32 01 80 STA inram+1
1184 3E D3 MVI a,0xd3
1186 32 00 80 STA inram
1189 3E C9 MVI a,0xc9
118B 32 02 80 STA inram+2
118E ;
118E CD 66 10 CALL tstc
1191 2C DB ","
1192 0A DB op2-$-1
1193 ;
1193 CD 12 10 CALL EXPR
1196 7D MOV a,l
1197 ;
1197 CD 00 80 CALL inram
119A C3 63 11 JMP runsml
119D C3 A5 10 OP2: JMP ahow
11A0 ;
11A0 ;*************************************************************
11A0 ;
11A0 ; *** LIST *** & PRINT ***
11A0 ;
11A0 ; LIST HAS TWO FORMS:
11A0 ; "LIST(CR)" LISTS ALL SAVED LINES
11A0 ; "LIST #(CR)" START LIST AT THIS LINE #
11A0 ; YOU CAN STOP THE LISTING BY CONTROL C KEY
11A0 ;
11A0 ; PRINT COMMAND IS "PRINT ....;" OR "PRINT ....(CR)"
11A0 ; WHERE "...." IS A LIST OF EXPRESIONS, FORMATS, BACK-
11A0 ; ARROWS, AND STRINGS. THESE ITEMS ARE SEPERATED BY COMMAS.
11A0 ;
11A0 ; A FORMAT IS A POUND SIGN FOLLOWED BY A NUMBER. IT CONTROLS
11A0 ; THE NUMBER OF SPACES THE VALUE OF A EXPRESION IS GOING TO
11A0 ; BE PRINTED. IT STAYS EFFECTIVE FOR THE REST OF THE PRINT
11A0 ; COMMAND UNLESS CHANGED BY ANOTHER FORMAT. IF NO FORMAT IS
11A0 ; SPECIFIED, 6 POSITIONS WILL BE USED.
11A0 ;
11A0 ; A STRING IS QUOTED IN A PAIR OF SINGLE QUOTES OR A PAIR OF
11A0 ; DOUBLE QUOTES.
11A0 ;
11A0 ; A BACK-ARROW MEANS GENERATE A (CR) WITHOUT (LF)
11A0 ;
11A0 ; A (CRLF) IS GENERATED AFTER THE ENTIRE LIST HAS BEEN
11A0 ; PRINTED OR IF THE LIST IS A NULL LIST. HOWEVER IF THE LIST
11A0 ; ENDED WITH A COMMA, NO (CRLF) IS GENERATED.
11A0 ;
11A0 CD 7A 10 LIST: CALL TSTNUM ;TEST IF THERE IS A #
11A3 CD 5D 15 CALL ENDCHK ;IF NO # WE GET A 0
11A6 CD DD 15 CALL FNDLN ;FIND THIS OR NEXT LINE
11A9 DA BF 10 LS1: JC RSTART ;C:PASSED TXTUNF
11AC CD 89 16 CALL PRTLN ;PRINT THE LINE
11AF CD 41 17 CALL CHKIO ;STOP IF HIT CONTROL-C
11B2 CD E5 15 CALL FNDLP ;FIND NEXT LINE
11B5 C3 A9 11 JMP LS1 ;AND LOOP BACK
11B8 ;
11B8 0E 06 PRINT: MVI C,6 ;C = # OF SPACES
11BA CD 66 10 CALL TSTC ;IF NULL LIST & ";"
11BD 3B DB 3BH
11BE 06 DB PR2-$-1
11BF CD 08 10 CALL CRLF ;GIVE CR-LF AND
11C2 C3 63 11 JMP RUNSML ;CONTINUE SAME LINE
11C5 CD 66 10 PR2: CALL TSTC ;IF NULL LIST (CR)
11C8 0D DB CR
11C9 06 DB PR0-$-1
11CA CD 08 10 CALL CRLF ;ALSO GIVE CR-LF AND
11CD C3 53 11 JMP RUNNXL ;GO TO NEXT LINE
11D0 CD 66 10 PR0: CALL TSTC ;ELSE IS IT FORMAT?
11D3 23 DB "#"
11D4 07 DB PR1-$-1
11D5 CD 12 10 CALL EXPR ;YES, EVALUATE EXPR.
11D8 4D MOV C,L ;AND SAVE IT IN C
11D9 C3 E2 11 JMP PR3 ;LOOK FOR MORE TO PRINT
11DC CD 15 16 PR1: CALL QTSTG ;OR IS IT A STRING?
11DF C3 F3 11 JMP PR8 ;IF NOT, MUST BE EXPR.
11E2 CD 66 10 PR3: CALL TSTC ;IF ",", GO FIND NEXT
11E5 2C DB ","
11E6 06 DB PR6-$-1
11E7 CD 4A 15 CALL FIN ;IN THE LIST.
11EA C3 D0 11 JMP PR0 ;LIST CONTINUES
11ED CD 08 10 PR6: CALL CRLF ;LIST ENDS
11F0 CD 2A 10 CALL FINISH
11F3 CD 12 10 PR8: CALL EXPR ;EVALUATE THE EXPR
11F6 C5 PUSH B
11F7 CD 45 16 CALL PRTNUM ;PRINT THE VALUE
11FA C1 POP B
11FB C3 E2 11 JMP PR3 ;MORE TO PRINT?
11FE ;
11FE ;*************************************************************
11FE ;
11FE ; *** GOSUB *** & RETURN ***
11FE ;
11FE ; "GOSUB EXPR;" OR "GOSUB EXPR (CR)" IS LIKE THE "GOTO"
11FE ; COMMAND, EXCEPT THAT THE CURRENT TEXT POINTER, STACK POINTER
11FE ; ETC. ARE SAVE SO THAT EXECUTION CAN BE CONTINUED AFTER THE
11FE ; SUBROUTINE "RETURN". IN ORDER THAT "GOSUB" CAN BE NESTED
11FE ; (AND EVEN RECURSIVE), THE SAVE AREA MUST BE STACKED.
11FE ; THE STACK POINTER IS SAVED IN "STKGOS", THE OLD "STKGOS" IS
11FE ; SAVED IN THE STACK. IF WE ARE IN THE MAIN ROUTINE, "STKGOS"
11FE ; IS ZERO (THIS WAS DONE BY THE "MAIN" SECTION OF THE CODE),
11FE ; BUT WE STILL SAVE IT AS A FLAG FOR NO FURTHER "RETURN"S.
11FE ;
11FE ; "RETURN(CR)" UNDOS EVERYTHING THAT "GOSUB" DID, AND THUS
11FE ; RETURN THE EXECUTION TO THE COMMAND AFTER THE MOST RECENT
11FE ; "GOSUB". IF "STKGOS" IS ZERO, IT INDICATES THAT WE
11FE ; NEVER HAD A "GOSUB" AND IS THUS AN ERROR.
11FE ;
11FE CD D4 16 GOSUB: CALL PUSHA ;SAVE THE CURRENT "FOR"
1201 CD 12 10 CALL EXPR ;PARAMETERS
1204 D5 PUSH D ;AND TEXT POINTER
1205 CD DD 15 CALL FNDLN ;FIND THE TARGET LINE
1208 C2 A5 10 JNZ AHOW ;NOT THERE. SAY "HOW?"
120B 2A 04 80 LHLD CURRNT ;FOUND IT, SAVE OLD
120E E5 PUSH H ;"CURRNT" OLD "STKGOS"
120F 2A 06 80 LHLD STKGOS
1212 E5 PUSH H
1213 21 00 00 LXI H,0 ;AND LOAD NEW ONES
1216 22 0C 80 SHLD LOPVAR
1219 39 DAD SP
121A 22 06 80 SHLD STKGOS
121D C3 5C 11 JMP RUNTSL ;THEN RUN THAT LINE
1220 CD 5D 15 RETURN: CALL ENDCHK ;THERE MUST BE A CR
1223 2A 06 80 LHLD STKGOS ;OLD STACK POINTER
1226 7C MOV A,H ;0 MEANS NOT EXIST
1227 B5 ORA L
1228 CA 63 15 JZ QWHAT ;SO, WE SAY: "WHAT?"
122B F9 SPHL ;ELSE, RESTORE IT
122C E1 POP H
122D 22 06 80 SHLD STKGOS ;AND THE OLD "STKGOS"
1230 E1 POP H
1231 22 04 80 SHLD CURRNT ;AND THE OLD "CURRNT"
1234 D1 POP D ;OLD TEXT POINTER
1235 CD B8 16 CALL POPA ;OLD "FOR" PARAMETERS
1238 CD 2A 10 CALL FINISH ;AND WE ARE BACK HOME
123B ;
123B ;*************************************************************
123B ;
123B ; *** FOR *** & NEXT ***
123B ;
123B ; "FOR" HAS TWO FORMS:
123B ; "FOR VAR=EXP1 TO EXP2 STEP EXP3" AND "FOR VAR=EXP1 TO EXP2"
123B ; THE SECOND FORM MEANS THE SAME THING AS THE FIRST FORM WITH
123B ; EXP3=1. (I.E., WITH A STEP OF +1.)
123B ; TBI WILL FIND THE VARIABLE VAR, AND SET ITS VALUE TO THE
123B ; CURRENT VALUE OF EXP1. IT ALSO EVALUATES EXP2 AND EXP3
123B ; AND SAVE ALL THESE TOGETHER WITH THE TEXT POINTER ETC. IN
123B ; THE "FOR" SAVE AREA, WHICH CONSISTS OF "LOPVAR", "LOPINC",
123B ; "LOPLMT", "LOPLN", AND "LOPPT". IF THERE IS ALREADY SOME-
123B ; THING IN THE SAVE AREA (THIS IS INDICATED BY A NON-ZERO
123B ; "LOPVAR"), THEN THE OLD SAVE AREA IS SAVED IN THE STACK
123B ; BEFORE THE NEW ONE OVERWRITES IT.
123B ; TBI WILL THEN DIG IN THE STACK AND FIND OUT IF THIS SAME
123B ; VARIABLE WAS USED IN ANOTHER CURRENTLY ACTIVE "FOR" LOOP.
123B ; IF THAT IS THE CASE, THEN THE OLD "FOR" LOOP IS DEACTIVATED.
123B ; (PURGED FROM THE STACK..)
123B ;
123B ; "NEXT VAR" SERVES AS THE LOGICAL (NOT NECESSARILLY PHYSICAL)
123B ; END OF THE "FOR" LOOP. THE CONTROL VARIABLE VAR. IS CHECKED
123B ; WITH THE "LOPVAR". IF THEY ARE NOT THE SAME, TBI DIGS IN
123B ; THE STACK TO FIND THE RIGHT ONE AND PURGES ALL THOSE THAT
123B ; DID NOT MATCH. EITHER WAY, TBI THEN ADDS THE "STEP" TO
123B ; THAT VARIABLE AND CHECK THE RESULT WITH THE LIMIT. IF IT
123B ; IS WITHIN THE LIMIT, CONTROL LOOPS BACK TO THE COMMAND
123B ; FOLLOWING THE "FOR". IF OUTSIDE THE LIMIT, THE SAVE AREA
123B ; IS PURGED AND EXECUTION CONTINUES.
123B ;
123B CD D4 16 FOR: CALL PUSHA ;SAVE THE OLD SAVE AREA
123E CD 31 15 CALL SETVAL ;SET THE CONTROL VAR.
1241 2B DCX H ;HL IS ITS ADDRESS
1242 22 0C 80 SHLD LOPVAR ;SAVE THAT
1245 21 E0 17 LXI H,TAB5-1 ;USE "EXEC" TO LOOK
1248 C3 08 18 JMP EXEC ;FOR THE WORD "TO"
124B CD 12 10 FR1: CALL EXPR ;EVALUATE THE LIMIT
124E 22 10 80 SHLD LOPLMT ;SAVE THAT
1251 21 E6 17 LXI H,TAB6-1 ;USE "EXEC" TO LOOK
1254 C3 08 18 JMP EXEC ;FOR THE WORD "STEP"
1257 CD 12 10 FR2: CALL EXPR ;FOUND IT, GET STEP
125A C3 60 12 JMP FR4
125D 21 01 00 FR3: LXI H,1H ;NOT FOUND, SET TO 1
1260 22 0E 80 FR4: SHLD LOPINC ;SAVE THAT TOO
1263 2A 04 80 FR5: LHLD CURRNT ;SAVE CURRENT LINE #
1266 22 12 80 SHLD LOPLN
1269 EB XCHG ;AND TEXT POINTER
126A 22 14 80 SHLD LOPPT
126D 01 0A 00 LXI B,0AH ;DIG INTO STACK TO
1270 2A 0C 80 LHLD LOPVAR ;FIND "LOPVAR"
1273 EB XCHG
1274 60 MOV H,B
1275 68 MOV L,B ;HL=0 NOW
1276 39 DAD SP ;HERE IS THE STACK
1277 3E DB 3EH
1278 09 FR7: DAD B ;EACH LEVEL IS 10 DEEP
1279 7E MOV A,M ;GET THAT OLD "LOPVAR"
127A 23 INX H
127B B6 ORA M
127C CA 99 12 JZ FR8 ;0 SAYS NO MORE IN IT
127F 7E MOV A,M
1280 2B DCX H
1281 BA CMP D ;SAME AS THIS ONE?
1282 C2 78 12 JNZ FR7
1285 7E MOV A,M ;THE OTHER HALF?
1286 BB CMP E
1287 C2 78 12 JNZ FR7
128A EB XCHG ;YES, FOUND ONE
128B 21 00 00 LXI H,0H
128E 39 DAD SP ;TRY TO MOVE SP
128F 44 MOV B,H
1290 4D MOV C,L
1291 21 0A 00 LXI H,0AH
1294 19 DAD D
1295 CD A9 16 CALL MVDOWN ;AND PURGE 10 WORDS
1298 F9 SPHL ;IN THE STACK
1299 2A 14 80 FR8: LHLD LOPPT ;JOB DONE, RESTORE DE
129C EB XCHG
129D CD 2A 10 CALL FINISH ;AND CONTINUE
12A0 ;
12A0 CD 32 10 NEXT: CALL TSTV ;GET ADDRESS OF VAR.
12A3 DA 63 15 JC QWHAT ;NO VARIABLE, "WHAT?"
12A6 22 08 80 SHLD VARNXT ;YES, SAVE IT
12A9 D5 NX0: PUSH D ;SAVE TEXT POINTER
12AA EB XCHG
12AB 2A 0C 80 LHLD LOPVAR ;GET VAR. IN "FOR"
12AE 7C MOV A,H
12AF B5 ORA L ;0 SAYS NEVER HAD ONE
12B0 CA 64 15 JZ AWHAT ;SO WE ASK: "WHAT?"
12B3 CD 1A 10 CALL COMP ;ELSE WE CHECK THEM
12B6 CA C3 12 JZ NX3 ;OK, THEY AGREE
12B9 D1 POP D ;NO, LET'S SEE
12BA CD B8 16 CALL POPA ;PURGE CURRENT LOOP
12BD 2A 08 80 LHLD VARNXT ;AND POP ONE LEVEL
12C0 C3 A9 12 JMP NX0 ;GO CHECK AGAIN
12C3 5E NX3: MOV E,M ;COME HERE WHEN AGREED
12C4 23 INX H
12C5 56 MOV D,M ;DE=VALUE OF VAR.
12C6 2A 0E 80 LHLD LOPINC
12C9 E5 PUSH H
12CA 7C MOV A,H
12CB AA XRA D
12CC 7A MOV A,D
12CD 19 DAD D ;ADD ONE STEP
12CE FA D5 12 JM NX4
12D1 AC XRA H
12D2 FA F9 12 JM NX5
12D5 EB NX4: XCHG
12D6 2A 0C 80 LHLD LOPVAR ;PUT IT BACK
12D9 73 MOV M,E
12DA 23 INX H
12DB 72 MOV M,D
12DC 2A 10 80 LHLD LOPLMT ;HL->LIMIT
12DF F1 POP PSW ;OLD HL
12E0 B7 ORA A
12E1 F2 E5 12 JP NX1 ;STEP > 0
12E4 EB XCHG ;STEP < 0
12E5 CD 27 15 NX1: CALL CKHLDE ;COMPARE WITH LIMIT
12E8 D1 POP D ;RESTORE TEXT POINTER
12E9 DA FB 12 JC NX2 ;OUTSIDE LIMIT
12EC 2A 12 80 LHLD LOPLN ;WITHIN LIMIT, GO
12EF 22 04 80 SHLD CURRNT ;BACK TO THE SAVED
12F2 2A 14 80 LHLD LOPPT ;"CURRNT" AND TEXT
12F5 EB XCHG ;POINTER
12F6 CD 2A 10 CALL FINISH
12F9 E1 NX5: POP H
12FA D1 POP D
12FB CD B8 16 NX2: CALL POPA ;PURGE THIS LOOP
12FE CD 2A 10 CALL FINISH
1301 ;
1301 ;*************************************************************
1301 ;
1301 ; *** REM *** IF *** INPUT *** & LET (& DEFLT) ***
1301 ;
1301 ; "REM" CAN BE FOLLOWED BY ANYTHING AND IS IGNORED BY TBI.
1301 ; TBI TREATS IT LIKE AN "IF" WITH A FALSE CONDITION.
1301 ;
1301 ; "IF" IS FOLLOWED BY AN EXPR. AS A CONDITION AND ONE OR MORE
1301 ; COMMANDS (INCLUDING OTHER "IF"S) SEPERATED BY SEMI-COLONS.
1301 ; NOTE THAT THE WORD "THEN" IS NOT USED. TBI EVALUATES THE
1301 ; EXPR. IF IT IS NON-ZERO, EXECUTION CONTINUES. IF THE
1301 ; EXPR. IS ZERO, THE COMMANDS THAT FOLLOWS ARE IGNORED AND
1301 ; EXECUTION CONTINUES AT THE NEXT LINE.
1301 ;
1301 ; "INPUT" COMMAND IS LIKE THE "PRINT" COMMAND, AND IS FOLLOWED
1301 ; BY A LIST OF ITEMS. IF THE ITEM IS A STRING IN SINGLE OR
1301 ; DOUBLE QUOTES, OR IS A BACK-ARROW, IT HAS THE SAME EFFECT AS
1301 ; IN "PRINT". IF AN ITEM IS A VARIABLE, THIS VARIABLE NAME IS
1301 ; PRINTED OUT FOLLOWED BY A COLON. THEN TBI WAITS FOR AN
1301 ; EXPR. TO BE TYPED IN. THE VARIABLE IS THEN SET TO THE
1301 ; VALUE OF THIS EXPR. IF THE VARIABLE IS PROCEDED BY A STRING
1301 ; (AGAIN IN SINGLE OR DOUBLE QUOTES), THE STRING WILL BE
1301 ; PRINTED FOLLOWED BY A COLON. TBI THEN WAITS FOR INPUT EXPR.
1301 ; AND SET THE VARIABLE TO THE VALUE OF THE EXPR.
1301 ;
1301 ; IF THE INPUT EXPR. IS INVALID, TBI WILL PRINT "WHAT?",
1301 ; "HOW?" OR "SORRY" AND REPRINT THE PROMPT AND REDO THE INPUT.
1301 ; THE EXECUTION WILL NOT TERMINATE UNLESS YOU TYPE CONTROL-C.
1301 ; THIS IS HANDLED IN "INPERR".
1301 ;
1301 ; "LET" IS FOLLOWED BY A LIST OF ITEMS SEPERATED BY COMMAS.
1301 ; EACH ITEM CONSISTS OF A VARIABLE, AN EQUAL SIGN, AND AN EXPR.
1301 ; TBI EVALUATES THE EXPR. AND SET THE VARIABLE TO THAT VALUE.
1301 ; TBI WILL ALSO HANDLE "LET" COMMAND WITHOUT THE WORD "LET".
1301 ; THIS IS DONE BY "DEFLT".
1301 ;
1301 21 00 00 REM: LXI H,0H ;*** REM ***
1304 3E DB 3EH ;THIS IS LIKE "IF 0"
1305 ;
1305 CD 12 10 IFF: CALL EXPR ;*** IF ***
1308 7C MOV A,H ;IS THE EXPR.=0?
1309 B5 ORA L
130A C2 63 11 JNZ RUNSML ;NO, CONTINUE
130D CD FD 15 CALL FNDSKP ;YES, SKIP REST OF LINE
1310 D2 5C 11 JNC RUNTSL ;AND RUN THE NEXT LINE
1313 C3 BF 10 JMP RSTART ;IF NO NEXT, RE-START
1316 ;
1316 2A 0A 80 INPERR: LHLD STKINP ;*** INPERR ***
1319 F9 SPHL ;RESTORE OLD SP
131A E1 POP H ;AND OLD "CURRNT"
131B 22 04 80 SHLD CURRNT
131E D1 POP D ;AND OLD TEXT POINTER
131F D1 POP D ;REDO INPUT
1320 ;
1320 INPUT: ;*** INPUT ***
1320 D5 IP1: PUSH D ;SAVE IN CASE OF ERROR
1321 CD 15 16 CALL QTSTG ;IS NEXT ITEM A STRING?
1324 C3 30 13 JMP IP2 ;NO
1327 CD 32 10 CALL TSTV ;YES, BUT FOLLOWED BY A
132A DA 6E 13 JC IP4 ;VARIABLE? NO.
132D C3 42 13 JMP IP3 ;YES. INPUT VARIABLE
1330 D5 IP2: PUSH D ;SAVE FOR "PRTSTG"
1331 CD 32 10 CALL TSTV ;MUST BE VARIABLE NOW
1334 DA 63 15 JC QWHAT ;"WHAT?" IT IS NOT?
1337 1A LDAX D ;GET READY FOR "PRTSTR"
1338 4F MOV C,A
1339 97 SUB A
133A 12 STAX D
133B D1 POP D
133C CD 07 16 CALL PRTSTG ;PRINT STRING AS PROMPT
133F 79 MOV A,C ;RESTORE TEXT
1340 1B DCX D
1341 12 STAX D
1342 D5 IP3: PUSH D ;SAVE TEXT POINTER
1343 EB XCHG
1344 2A 04 80 LHLD CURRNT ;ALSO SAVE "CURRNT"
1347 E5 PUSH H
1348 21 20 13 LXI H,IP1 ;A NEGATIVE NUMBER
134B 22 04 80 SHLD CURRNT ;AS A FLAG
134E 21 00 00 LXI H,0H ;SAVE SP TOO
1351 39 DAD SP
1352 22 0A 80 SHLD STKINP
1355 D5 PUSH D ;OLD HL
1356 3E 3A MVI A,3AH ;PRINT THIS TOO
1358 CD 99 15 CALL GETLN ;AND GET A LINE
135B 11 37 FC LXI D,BUFFER ;POINTS TO BUFFER
135E CD 12 10 CALL EXPR ;EVALUATE INPUT
1361 00 NOP ;CAN BE "CALL ENDCHK"
1362 00 NOP
1363 00 NOP
1364 D1 POP D ;OK, GET OLD HL
1365 EB XCHG
1366 73 MOV M,E ;SAVE VALUE IN VAR.
1367 23 INX H
1368 72 MOV M,D
1369 E1 POP H ;GET OLD "CURRNT"
136A 22 04 80 SHLD CURRNT
136D D1 POP D ;AND OLD TEXT POINTER
136E F1 IP4: POP PSW ;PURGE JUNK IN STACK
136F CD 66 10 CALL TSTC ;IS NEXT CH. ","?
1372 2C DB ","
1373 03 DB IP5-$-1
1374 C3 20 13 JMP IP1 ;YES, MORE ITEMS.
1377 CD 2A 10 IP5: CALL FINISH
137A ;
137A 1A DEFLT: LDAX D ;*** DEFLT ***
137B FE 0D CPI CR ;EMPTY LINE IS OK
137D CA 8B 13 JZ LT1 ;ELSE IT IS "LET"
1380 ;
1380 CD 31 15 LET: CALL SETVAL ;*** LET ***
1383 CD 66 10 CALL TSTC ;SET VALUE TO VAR.
1386 2C DB ","
1387 03 DB LT1-$-1
1388 C3 80 13 JMP LET ;ITEM BY ITEM
138B CD 2A 10 LT1: CALL FINISH ;UNTIL FINISH
138E ;
138E ;*************************************************************
138E ;
138E ; *** EXPR ***
138E ;
138E ; "EXPR" EVALUATES ARITHMETICAL OR LOGICAL EXPRESSIONS.
138E ; <EXPR>::<EXPR2>
138E ; <EXPR2><REL.OP.><EXPR2>
138E ; WHERE <REL.OP.> IS ONE OF THE OPERATORS IN TAB8 AND THE
138E ; RESULT OF THESE OPERATIONS IS 1 IF TRUE AND 0 IF FALSE.
138E ; <EXPR2>::=(+ OR -)<EXPR3>(+ OR -<EXPR3>)(....)
138E ; WHERE () ARE OPTIONAL AND (....) ARE OPTIONAL REPEATS.
138E ; <EXPR3>::=<EXPR4>(* OR /><EXPR4>)(....)
138E ; <EXPR4>::=<VARIABLE>
138E ; <FUNCTION>
138E ; (<EXPR>)
138E ; <EXPR> IS RECURSIVE SO THAT VARIABLE "@" CAN HAVE AN <EXPR>
138E ; AS INDEX, FUNCTIONS CAN HAVE AN <EXPR> AS ARGUMENTS, AND
138E ; <EXPR4> CAN BE AN <EXPR> IN PARANTHESE.
138E ;
138E ;EXPR: CALL EXPR2 ;THIS IS AT LOC. 18
138E ; PUSH H ;SAVE <EXPR2> VALUE
138E 21 EE 17 EXPR1: LXI H,TAB8-1 ;LOOKUP REL.OP.
1391 C3 08 18 JMP EXEC ;GO DO IT
1394 CD BD 13 XP11: CALL XP18 ;REL.OP.">="
1397 D8 RC ;NO, RETURN HL=0
1398 6F MOV L,A ;YES, RETURN HL=1
1399 C9 RET
139A CD BD 13 XP12: CALL XP18 ;REL.OP."#"
139D C8 RZ ;FALSE, RETURN HL=0
139E 6F MOV L,A ;TRUE, RETURN HL=1
139F C9 RET
13A0 CD BD 13 XP13: CALL XP18 ;REL.OP.">"
13A3 C8 RZ ;FALSE
13A4 D8 RC ;ALSO FALSE, HL=0
13A5 6F MOV L,A ;TRUE, HL=1
13A6 C9 RET
13A7 CD BD 13 XP14: CALL XP18 ;REL.OP."<="
13AA 6F MOV L,A ;SET HL=1
13AB C8 RZ ;REL. TRUE, RETURN
13AC D8 RC
13AD 6C MOV L,H ;ELSE SET HL=0
13AE C9 RET
13AF CD BD 13 XP15: CALL XP18 ;REL.OP."="
13B2 C0 RNZ ;FALSE, RETURN HL=0
13B3 6F MOV L,A ;ELSE SET HL=1
13B4 C9 RET
13B5 CD BD 13 XP16: CALL XP18 ;REL.OP."<"
13B8 D0 RNC ;FALSE, RETURN HL=0
13B9 6F MOV L,A ;ELSE SET HL=1
13BA C9 RET
13BB E1 XP17: POP H ;NOT .REL.OP
13BC C9 RET ;RETURN HL=<EXPR2>
13BD 79 XP18: MOV A,C ;SUBROUTINE FOR ALL
13BE E1 POP H ;REL.OP.'S
13BF C1 POP B
13C0 E5 PUSH H ;REVERSE TOP OF STACK
13C1 C5 PUSH B
13C2 4F MOV C,A
13C3 CD D2 13 CALL EXPR2 ;GET 2ND <EXPR2>
13C6 EB XCHG ;VALUE IN DE NOW
13C7 E3 XTHL ;1ST <EXPR2> IN HL
13C8 CD 27 15 CALL CKHLDE ;COMPARE 1ST WITH 2ND
13CB D1 POP D ;RESTORE TEXT POINTER
13CC 21 00 00 LXI H,0H ;SET HL=0, A=1
13CF 3E 01 MVI A,1
13D1 C9 RET
13D2 ;
13D2 CD 66 10 EXPR2: CALL TSTC ;NEGATIVE SIGN?
13D5 2D DB "-"
13D6 06 DB XP21-$-1
13D7 21 00 00 LXI H,0H ;YES, FAKE "0-"
13DA C3 04 14 JMP XP26 ;TREAT LIKE SUBTRACT
13DD CD 66 10 XP21: CALL TSTC ;POSITIVE SIGN? IGNORE
13E0 2B DB "+"
13E1 00 DB XP22-$-1
13E2 CD 0E 14 XP22: CALL EXPR3 ;1ST <EXPR3>
13E5 CD 66 10 XP23: CALL TSTC ;ADD?
13E8 2B DB "+"
13E9 15 DB XP25-$-1
13EA E5 PUSH H ;YES, SAVE VALUE
13EB CD 0E 14 CALL EXPR3 ;GET 2ND <EXPR3>
13EE EB XP24: XCHG ;2ND IN DE
13EF E3 XTHL ;1ST IN HL
13F0 7C MOV A,H ;COMPARE SIGN
13F1 AA XRA D
13F2 7A MOV A,D
13F3 19 DAD D
13F4 D1 POP D ;RESTORE TEXT POINTER
13F5 FA E5 13 JM XP23 ;1ST AND 2ND SIGN DIFFER
13F8 AC XRA H ;1ST AND 2ND SIGN EQUAL
13F9 F2 E5 13 JP XP23 ;SO IS RESULT
13FC C3 A4 10 JMP QHOW ;ELSE WE HAVE OVERFLOW
13FF CD 66 10 XP25: CALL TSTC ;SUBTRACT?
1402 2D DB "-"
1403 92 DB XP42-$-1
1404 E5 XP26: PUSH H ;YES, SAVE 1ST <EXPR3>
1405 CD 0E 14 CALL EXPR3 ;GET 2ND <EXPR3>
1408 CD 15 15 CALL CHGSGN ;NEGATE
140B C3 EE 13 JMP XP24 ;AND ADD THEM
140E ;
140E CD 72 14 EXPR3: CALL EXPR4 ;GET 1ST <EXPR4>
1411 CD 66 10 XP31: CALL TSTC ;MULTIPLY?
1414 2A DB "*"
1415 2D DB XP34-$-1
1416 E5 PUSH H ;YES, SAVE 1ST
1417 CD 72 14 CALL EXPR4 ;AND GET 2ND <EXPR4>
141A 06 00 MVI B,0H ;CLEAR B FOR SIGN
141C CD 12 15 CALL CHKSGN ;CHECK SIGN
141F E3 XTHL ;1ST IN HL
1420 CD 12 15 CALL CHKSGN ;CHECK SIGN OF 1ST
1423 EB XCHG
1424 E3 XTHL
1425 7C MOV A,H ;IS HL > 255 ?
1426 B7 ORA A
1427 CA 30 14 JZ XP32 ;NO
142A 7A MOV A,D ;YES, HOW ABOUT DE
142B B2 ORA D
142C EB XCHG ;PUT SMALLER IN HL
142D C2 A5 10 JNZ AHOW ;ALSO >, WILL OVERFLOW
1430 7D XP32: MOV A,L ;THIS IS DUMB
1431 21 00 00 LXI H,0H ;CLEAR RESULT
1434 B7 ORA A ;ADD AND COUNT
1435 CA 64 14 JZ XP35
1438 19 XP33: DAD D
1439 DA A5 10 JC AHOW ;OVERFLOW
143C 3D DCR A
143D C2 38 14 JNZ XP33
1440 C3 64 14 JMP XP35 ;FINISHED
1443 CD 66 10 XP34: CALL TSTC ;DIVIDE?
1446 2F DB "/"
1447 4E DB XP42-$-1
1448 E5 PUSH H ;YES, SAVE 1ST <EXPR4>
1449 CD 72 14 CALL EXPR4 ;AND GET THE SECOND ONE
144C 06 00 MVI B,0H ;CLEAR B FOR SIGN
144E CD 12 15 CALL CHKSGN ;CHECK SIGN OF 2ND
1451 E3 XTHL ;GET 1ST IN HL
1452 CD 12 15 CALL CHKSGN ;CHECK SIGN OF 1ST
1455 EB XCHG
1456 E3 XTHL
1457 EB XCHG
1458 7A MOV A,D ;DIVIDE BY 0?
1459 B3 ORA E
145A CA A5 10 JZ AHOW ;SAY "HOW?"
145D C5 PUSH B ;ELSE SAVE SIGN
145E CD F5 14 CALL DIVIDE ;USE SUBROUTINE
1461 60 MOV H,B ;RESULT IN HL NOW
1462 69 MOV L,C
1463 C1 POP B ;GET SIGN BACK
1464 D1 XP35: POP D ;AND TEXT POINTER
1465 7C MOV A,H ;HL MUST BE +
1466 B7 ORA A
1467 FA A4 10 JM QHOW ;ELSE IT IS OVERFLOW
146A 78 MOV A,B
146B B7 ORA A
146C FC 15 15 CM CHGSGN ;CHANGE SIGN IF NEEDED
146F C3 11 14 JMP XP31 ;LOOK FOR MORE TERMS
1472 ;
1472 21 C9 17 EXPR4: LXI H,TAB4-1 ;FIND FUNCTION IN TAB4
1475 C3 08 18 JMP EXEC ;AND GO DO IT
1478 CD 32 10 XP40: CALL TSTV ;NO, NOT A FUNCTION
147B DA 83 14 JC XP41 ;NOR A VARIABLE
147E 7E MOV A,M ;VARIABLE
147F 23 INX H
1480 66 MOV H,M ;VALUE IN HL
1481 6F MOV L,A
1482 C9 RET
1483 CD 7A 10 XP41: CALL TSTNUM ;OR IS IT A NUMBER
1486 78 MOV A,B ;# OF DIGIT
1487 B7 ORA A
1488 C0 RNZ ;OK
1489 CD 66 10 PARN: CALL TSTC
148C 28 DB "("
148D 09 DB XP43-$-1
148E CD 12 10 CALL EXPR ;"(EXPR)"
1491 CD 66 10 CALL TSTC
1494 29 DB ")"
1495 01 DB XP43-$-1
1496 C9 XP42: RET
1497 C3 63 15 XP43: JMP QWHAT ;ELSE SAY: "WHAT?"
149A ;
149A CD 89 14 RND: CALL PARN ;*** RND(EXPR) ***
149D 7C MOV A,H ;EXPR MUST BE +
149E B7 ORA A
149F FA A4 10 JM QHOW
14A2 B5 ORA L ;AND NON-ZERO
14A3 CA A4 10 JZ QHOW
14A6 D5 PUSH D ;SAVE BOTH
14A7 E5 PUSH H
14A8 2A 16 80 LHLD RANPNT ;GET MEMORY AS RANDOM
14AB 11 38 18 LXI D,LSTROM ;NUMBER
14AE CD 1A 10 CALL COMP
14B1 DA B7 14 JC RA1 ;WRAP AROUND IF LAST
14B4 21 00 10 LXI H,START
14B7 5E RA1: MOV E,M
14B8 23 INX H
14B9 56 MOV D,M
14BA 22 16 80 SHLD RANPNT
14BD E1 POP H
14BE EB XCHG
14BF C5 PUSH B
14C0 CD F5 14 CALL DIVIDE ;RND(N)=MOD(M,N)+1
14C3 C1 POP B
14C4 D1 POP D
14C5 23 INX H
14C6 C9 RET
14C7 ;
14C7 CD 89 14 ABS: CALL PARN ;*** ABS(EXPR) ***
14CA 1B DCX D
14CB CD 12 15 CALL CHKSGN ;CHECK SIGN
14CE 13 INX D
14CF C9 RET
14D0 ;
14D0 ;
14D0 INFN:
14D0 CD 89 14 CALL PARN
14D3 7D MOV a,l
14D4 32 01 80 STA inram+1
14D7 3E DB MVI a,0xDB ;instruction IN
14D9 32 00 80 STA inram
14DC 3E C9 MVI a,0xc9 ;instruction RET
14DE 32 02 80 STA inram+2
14E1 CD 00 80 CALL inram
14E4 6F MOV l,a
14E5 26 00 MVI h,0
14E7 C9 RET
14E8 2A 18 80 SIZE: LHLD TXTUNF ;*** SIZE ***
14EB D5 PUSH D ;GET THE NUMBER OF FREE
14EC EB XCHG ;BYTES BETWEEN "TXTUNF"
14ED 21 00 FC LXI H,VARBGN ;AND "VARBGN"
14F0 CD 0B 15 CALL SUBDE
14F3 D1 POP D
14F4 C9 RET
14F5 ;
14F5 ;*************************************************************
14F5 ;
14F5 ; *** DIVIDE *** SUBDE *** CHKSGN *** CHGSGN *** & CKHLDE ***
14F5 ;
14F5 ; "DIVIDE" DIVIDES HL BY DE, RESULT IN BC, REMAINDER IN HL
14F5 ;
14F5 ; "SUBDE" SUBSTRACTS DE FROM HL
14F5 ;
14F5 ; "CHKSGN" CHECKS SIGN OF HL. IF +, NO CHANGE. IF -, CHANGE
14F5 ; SIGN AND FLIP SIGN OF B.
14F5 ;
14F5 ; "CHGSGN" CHECKS SIGN N OF HL AND B UNCONDITIONALLY.
14F5 ;
14F5 ; "CKHLDE" CHECKS SIGN OF HL AND DE. IF DIFFERENT, HL AND DE
14F5 ; ARE INTERCHANGED. IF SAME SIGN, NOT INTERCHANGED. EITHER
14F5 ; CASE, HL DE ARE THEN COMPARED TO SET THE FLAGS.
14F5 ;
14F5 E5 DIVIDE: PUSH H ;*** DIVIDE ***
14F6 6C MOV L,H ;DIVIDE H BY DE
14F7 26 00 MVI H,0
14F9 CD 00 15 CALL DV1
14FC 41 MOV B,C ;SAVE RESULT IN B
14FD 7D MOV A,L ;(REMINDER+L)/DE
14FE E1 POP H
14FF 67 MOV H,A
1500 0E FF DV1: MVI C,0FFH ;RESULT IN C
1502 0C DV2: INR C ;DUMB ROUTINE
1503 CD 0B 15 CALL SUBDE ;DIVIDE BY SUBTRACT
1506 D2 02 15 JNC DV2 ;AND COUNT
1509 19 DAD D
150A C9 RET
150B ;
150B 7D SUBDE: MOV A,L ;*** SUBDE ***
150C 93 SUB E ;SUBSTRACT DE FROM
150D 6F MOV L,A ;HL
150E 7C MOV A,H
150F 9A SBB D
1510 67 MOV H,A
1511 C9 RET
1512 ;
1512 7C CHKSGN: MOV A,H ;*** CHKSGN ***
1513 B7 ORA A ;CHECK SIGN OF HL
1514 F0 RP ;IF -, CHANGE SIGN
1515 ;
1515 7C CHGSGN: MOV A,H ;*** CHGSGN ***
1516 F5 PUSH PSW
1517 2F CMA ;CHANGE SIGN OF HL
1518 67 MOV H,A
1519 7D MOV A,L
151A 2F CMA
151B 6F MOV L,A
151C 23 INX H
151D F1 POP PSW
151E AC XRA H
151F F2 A4 10 JP QHOW
1522 78 MOV A,B ;AND ALSO FLIP B
1523 EE 80 XRI 80H
1525 47 MOV B,A
1526 C9 RET
1527 ;
1527 7C CKHLDE: MOV A,H
1528 AA XRA D ;SAME SIGN?
1529 F2 2D 15 JP CK1 ;YES, COMPARE
152C EB XCHG ;NO, XCH AND COMP
152D CD 1A 10 CK1: CALL COMP
1530 C9 RET
1531 ;
1531 ;*************************************************************
1531 ;
1531 ; *** SETVAL *** FIN *** ENDCHK *** & ERROR (& FRIENDS) ***
1531 ;
1531 ; "SETVAL" EXPECTS A VARIABLE, FOLLOWED BY AN EQUAL SIGN AND
1531 ; THEN AN EXPR. IT EVALUATES THE EXPR. AND SET THE VARIABLE
1531 ; TO THAT VALUE.
1531 ;
1531 ; "FIN" CHECKS THE END OF A COMMAND. IF IT ENDED WITH "?,
1531 ; EXECUTION CONTINUES. IF IT ENDED WITH A CR, IT FINDS THE
1531 ; NEXT LINE AND CONTINUE FROM THERE.
1531 ;
1531 ; "ENDCHK" CHECKS IF A COMMAND IS ENDED WITH CR. THIS IS
1531 ; REQUIRED IN CERTAIN COMMANDS. (GOTO, RETURN, AND STOP ETC.)
1531 ;
1531 ; "ERROR" PRINTS THE STRING POINTED BY DE (AND ENDS WITH CR).
1531 ; IT THEN PRINTS THE LINE POINTED BY "CURRNT" WITH A "?"
1531 ; INSERTED AT WHERE THE OLD TEXT POINTER (SHOULD BE ON TOP
1531 ; OF THE STACK) POINTS TO. EXECUTION OF TB IS STOPPED
1531 ; AND TBI IS RESTARTED. HOWEVER, IF "CURRNT" -> ZERO
1531 ; (INDICATING A DIRECT COMMAND), THE DIRECT COMMAND IS NOT
1531 ; PRINTED. AND IF "CURRNT" -> NEGATIVE # (INDICATING "INPUT"
1531 ; COMMAND), THE INPUT LINE IS NOT PRINTED AND EXECUTION IS
1531 ; NOT TERMINATED BUT CONTINUED AT "INPERR".
1531 ;
1531 ; RELATED TO "ERROR" ARE THE FOLLOWING:
1531 ; "QWHAT" SAVES TEXT POINTER IN STACK AND GET MESSAGE "WHAT?"
1531 ; "AWHAT" JUST GET MESSAGE "WHAT?" AND JUMP TO "ERROR".
1531 ; "QSORRY" AND "ASORRY" DO SAME KIND OF THING.
1531 ; "AHOW" AND "AHOW" IN THE ZERO PAGE SECTION ALSO DO THIS.
1531 ;
1531 CD 32 10 SETVAL: CALL TSTV ;*** SETVAL ***
1534 DA 63 15 JC QWHAT ;"WHAT?" NO VARIABLE
1537 E5 PUSH H ;SAVE ADDRESS OF VAR.
1538 CD 66 10 CALL TSTC ;PASS "=" SIGN
153B 3D DB "="
153C 0A DB SV1-$-1
153D CD 12 10 CALL EXPR ;EVALUATE EXPR.
1540 44 MOV B,H ;VALUE IS IN BC NOW
1541 4D MOV C,L
1542 E1 POP H ;GET ADDRESS
1543 71 MOV M,C ;SAVE VALUE
1544 23 INX H
1545 70 MOV M,B
1546 C9 RET
1547 C3 63 15 SV1: JMP QWHAT ;NO "=" SIGN
154A ;
154A CD 66 10 FIN: CALL TSTC ;*** FIN ***
154D 3B DB 3BH
154E 04 DB FI1-$-1
154F F1 POP PSW ;";", PURGE RET. ADDR.
1550 C3 63 11 JMP RUNSML ;CONTINUE SAME LINE
1553 CD 66 10 FI1: CALL TSTC ;NOT ";", IS IT CR?
1556 0D DB CR
1557 04 DB FI2-$-1
1558 F1 POP PSW ;YES, PURGE RET. ADDR.
1559 C3 53 11 JMP RUNNXL ;RUN NEXT LINE
155C C9 FI2: RET ;ELSE RETURN TO CALLER
155D ;
155D CD 22 10 ENDCHK: CALL IGNBLK ;*** ENDCHK ***
1560 FE 0D CPI CR ;END WITH CR?
1562 C8 RZ ;OK, ELSE SAY: "WHAT?"
1563 ;
1563 D5 QWHAT: PUSH D ;*** QWHAT ***
1564 11 B3 10 AWHAT: LXI D,WHAT ;*** AWHAT ***
1567 97 ERROR: SUB A ;*** ERROR ***
1568 CD 07 16 CALL PRTSTG ;PRINT "WHAT?", "HOW?"
156B D1 POP D ;OR "SORRY"
156C 1A LDAX D ;SAVE THE CHARACTER
156D F5 PUSH PSW ;AT WHERE OLD DE ->
156E 97 SUB A ;AND PUT A 0 THERE
156F 12 STAX D
1570 2A 04 80 LHLD CURRNT ;GET CURRENT LINE #
1573 E5 PUSH H
1574 7E MOV A,M ;CHECK THE VALUE
1575 23 INX H
1576 B6 ORA M
1577 D1 POP D
1578 CA BF 10 JZ RSTART ;IF ZERO, JUST RESTART
157B 7E MOV A,M ;IF NEGATIVE,
157C B7 ORA A
157D FA 16 13 JM INPERR ;REDO INPUT
1580 CD 89 16 CALL PRTLN ;ELSE PRINT THE LINE
1583 1B DCX D ;UPTO WHERE THE 0 IS
1584 F1 POP PSW ;RESTORE THE CHARACTER
1585 12 STAX D
1586 3E 3F MVI A,3FH ;PRINT A "?"
1588 CD 0A 10 CALL OUTC
158B 97 SUB A ;AND THE REST OF THE
158C CD 07 16 CALL PRTSTG ;LINE
158F C3 BF 10 JMP RSTART ;THEN RESTART
1592 ;
1592 D5 QSORRY: PUSH D ;*** QSORRY ***
1593 11 B9 10 ASORRY: LXI D,SORRY ;*** ASORRY ***
1596 C3 67 15 JMP ERROR
1599 ;
1599 ;*************************************************************
1599 ;
1599 ; *** GETLN *** FNDLN (& FRIENDS) ***
1599 ;
1599 ; "GETLN" READS A INPUT LINE INTO "BUFFER". IT FIRST PROMPT
1599 ; THE CHARACTER IN A (GIVEN BY THE CALLER), THEN IT FILLS
1599 ; THE BUFFER AND ECHOS. IT IGNORES LF'S AND NULLS, BUT STILL
1599 ; ECHOS THEM BACK. RUB-OUT IS USED TO CAUSE IT TO DELETE
1599 ; THE LAST CHARACTER (IF THERE IS ONE), AND ALT-MOD IS USED TO
1599 ; CAUSE IT TO DELETE THE WHOLE LINE AND START IT ALL OVER.
1599 ; CR SIGNALS THE END OF A LINE, AND CAUSE "GETLN" TO RETURN.
1599 ;
1599 ; "FNDLN" FINDS A LINE WITH A GIVEN LINE # (IN HL) IN THE
1599 ; TEXT SAVE AREA. DE IS USED AS THE TEXT POINTER. IF THE
1599 ; LINE IS FOUND, DE WILL POINT TO THE BEGINNING OF THAT LINE
1599 ; (I.E., THE LOW BYTE OF THE LINE #), AND FLAGS ARE NC & Z.
1599 ; IF THAT LINE IS NOT THERE AND A LINE WITH A HIGHER LINE #
1599 ; IS FOUND, DE POINTS TO THERE AND FLAGS ARE NC & NZ. IF
1599 ; WE REACHED THE END OF TEXT SAVE AREA AND CANNOT FIND THE
1599 ; LINE, FLAGS ARE C & NZ.
1599 ; "FNDLN" WILL INITIALIZE DE TO THE BEGINNING OF THE TEXT SAVE
1599 ; AREA TO START THE SEARCH. SOME OTHER ENTRIES OF THIS
1599 ; ROUTINE WILL NOT INITIALIZE DE AND DO THE SEARCH.
1599 ; "FNDLNP" WILL START WITH DE AND SEARCH FOR THE LINE #.
1599 ; "FNDNXT" WILL BUMP DE BY 2, FIND A CR AND THEN START SEARCH.
1599 ; "FNDSKP" USE DE TO FIND A CR, AND THEN START SEARCH.
1599 ;
1599 CD 0A 10 GETLN: CALL OUTC ;*** GETLN ***
159C 11 37 FC LXI D,BUFFER ;PROMPT AND INIT.
159F CD 41 17 GL1: CALL CHKIO ;CHECK KEYBOARD
15A2 CA 9F 15 JZ GL1 ;NO INPUT, WAIT
15A5 FE 7F CPI 7FH ;DELETE LAST CHARACTER?
15A7 CA C6 15 JZ GL3 ;YES
15AA CD 0A 10 CALL OUTC ;INPUT, ECHO BACK
15AD FE 0A CPI 0AH ;IGNORE LF
15AF CA 9F 15 JZ GL1
15B2 B7 ORA A ;IGNORE NULL
15B3 CA 9F 15 JZ GL1
15B6 FE 7D CPI 7DH ;DELETE THE WHOLE LINE?
15B8 CA D5 15 JZ GL4 ;YES
15BB 12 STAX D ;ELSE SAVE INPUT
15BC 13 INX D ;AND BUMP POINTER
15BD FE 0D CPI 0DH ;WAS IT CR?
15BF C8 RZ ;YES, END OF LINE
15C0 7B MOV A,E ;ELSE MORE FREE ROOM?
15C1 FE 77 CPI <BUFEND
15C3 C2 9F 15 JNZ GL1 ;YES, GET NEXT INPUT
15C6 7B GL3: MOV A,E ;DELETE LAST CHARACTER
15C7 FE 37 CPI <BUFFER ;BUT DO WE HAVE ANY?
15C9 CA D5 15 JZ GL4 ;NO, REDO WHOLE LINE
15CC 1B DCX D ;YES, BACKUP POINTER
15CD 3E 5C MVI A,5CH ;AND ECHO A BACK-SLASH
15CF CD 0A 10 CALL OUTC
15D2 C3 9F 15 JMP GL1 ;GO GET NEXT INPUT
15D5 CD 08 10 GL4: CALL CRLF ;REDO ENTIRE LINE
15D8 3E 5E MVI A,05EH ;CR, LF AND UP-ARROW
15DA C3 99 15 JMP GETLN
15DD ;
15DD 7C FNDLN: MOV A,H ;*** FNDLN ***
15DE B7 ORA A ;CHECK SIGN OF HL
15DF FA A4 10 JM QHOW ;IT CANNOT BE -
15E2 11 1A 80 LXI D,TXTBGN ;INIT TEXT POINTER
15E5 ;
15E5 FNDLP: ;*** FDLNP ***
15E5 E5 FL1: PUSH H ;SAVE LINE #
15E6 2A 18 80 LHLD TXTUNF ;CHECK IF WE PASSED END
15E9 2B DCX H
15EA CD 1A 10 CALL COMP
15ED E1 POP H ;GET LINE # BACK
15EE D8 RC ;C,NZ PASSED END
15EF 1A LDAX D ;WE DID NOT, GET BYTE 1
15F0 95 SUB L ;IS THIS THE LINE?
15F1 47 MOV B,A ;COMPARE LOW ORDER
15F2 13 INX D
15F3 1A LDAX D ;GET BYTE 2
15F4 9C SBB H ;COMPARE HIGH ORDER
15F5 DA FC 15 JC FL2 ;NO, NOT THERE YET
15F8 1B DCX D ;ELSE WE EITHER FOUND
15F9 B0 ORA B ;IT, OR IT IS NOT THERE
15FA C9 RET ;NC,Z:FOUND, NC,NZ:NO
15FB ;
15FB FNDNXT: ;*** FNDNXT ***
15FB 13 INX D ;FIND NEXT LINE
15FC 13 FL2: INX D ;JUST PASSED BYTE 1 & 2
15FD ;
15FD 1A FNDSKP: LDAX D ;*** FNDSKP ***
15FE FE 0D CPI CR ;TRY TO FIND CR
1600 C2 FC 15 JNZ FL2 ;KEEP LOOKING
1603 13 INX D ;FOUND CR, SKIP OVER
1604 C3 E5 15 JMP FL1 ;CHECK IF END OF TEXT
1607 ;
1607 ;*************************************************************
1607 ;
1607 ; *** PRTSTG *** QTSTG *** PRTNUM *** & PRTLN ***
1607 ;
1607 ; "PRTSTG" PRINTS A STRING POINTED BY DE. IT STOPS PRINTING
1607 ; AND RETURNS TO CALLER WHEN EITHER A CR IS PRINTED OR WHEN
1607 ; THE NEXT BYTE IS THE SAME AS WHAT WAS IN A (GIVEN BY THE
1607 ; CALLER). OLD A IS STORED IN B, OLD B IS LOST.
1607 ;
1607 ; "QTSTG" LOOKS FOR A BACK-ARROW, SINGLE QUOTE, OR DOUBLE
1607 ; QUOTE. IF NONE OF THESE, RETURN TO CALLER. IF BACK-ARROW,
1607 ; OUTPUT A CR WITHOUT A LF. IF SINGLE OR DOUBLE QUOTE, PRINT
1607 ; THE STRING IN THE QUOTE AND DEMANDS A MATCHING UNQUOTE.
1607 ; AFTER THE PRINTING THE NEXT 3 BYTES OF THE CALLER IS SKIPPED
1607 ; OVER (USUALLY A JUMP INSTRUCTION.
1607 ;
1607 ; "PRTNUM" PRINTS THE NUMBER IN HL. LEADING BLANKS ARE ADDED
1607 ; IF NEEDED TO PAD THE NUMBER OF SPACES TO THE NUMBER IN C.
1607 ; HOWEVER, IF THE NUMBER OF DIGITS IS LARGER THAN THE # IN
1607 ; C, ALL DIGITS ARE PRINTED ANYWAY. NEGATIVE SIGN IS ALSO
1607 ; PRINTED AND COUNTED IN, POSITIVE SIGN IS NOT.
1607 ;
1607 ; "PRTLN" PRINTS A SAVED TEXT LINE WITH LINE # AND ALL.
1607 ;
1607 47 PRTSTG: MOV B,A ;*** PRTSTG ***
1608 1A PS1: LDAX D ;GET A CHARACTER
1609 13 INX D ;BUMP POINTER
160A B8 CMP B ;SAME AS OLD A?
160B C8 RZ ;YES, RETURN
160C CD 0A 10 CALL OUTC ;ELSE PRINT IT
160F FE 0D CPI CR ;WAS IT A CR?
1611 C2 08 16 JNZ PS1 ;NO, NEXT
1614 C9 RET ;YES, RETURN
1615 ;
1615 CD 66 10 QTSTG: CALL TSTC ;*** QTSTG ***
1618 22 DB 22h
1619 0F DB QT3-$-1
161A 3E 22 MVI A,22H ;IT IS A "
161C CD 07 16 QT1: CALL PRTSTG ;PRINT UNTIL ANOTHER
161F FE 0D CPI CR ;WAS LAST ONE A CR?
1621 E1 POP H ;RETURN ADDRESS
1622 CA 53 11 JZ RUNNXL ;WAS CR, RUN NEXT LINE
1625 23 QT2: INX H ;SKIP 3 BYTES ON RETURN
1626 23 INX H
1627 23 INX H
1628 E9 PCHL ;RETURN
1629 CD 66 10 QT3: CALL TSTC ;IS IT A '?
162C 27 DB 27H
162D 05 DB QT4-$-1
162E 3E 27 MVI A,27H ;YES, DO THE SAME
1630 C3 1C 16 JMP QT1 ;AS IN "
1633 CD 66 10 QT4: CALL TSTC ;IS IT BACK-ARROW?
1636 5F DB 5FH
1637 0C DB QT5-$-1
1638 3E 8D MVI A,08DH ;YES, CR WITHOUT LF
163A CD 0A 10 CALL OUTC ;DO IT TWICE TO GIVE
163D CD 0A 10 CALL OUTC ;TTY ENOUGH TIME
1640 E1 POP H ;RETURN ADDRESS
1641 C3 25 16 JMP QT2
1644 C9 QT5: RET ;NONE OF ABOVE
1645 ;
1645 06 00 PRTNUM: MVI B,0 ;*** PRTNUM ***
1647 CD 12 15 CALL CHKSGN ;CHECK SIGN
164A F2 50 16 JP PN1 ;NO SIGN
164D 06 2D MVI B,"-" ;B=SIGN
164F 0D DCR C ;"-" TAKES SPACE
1650 D5 PN1: PUSH D ;SAVE
1651 11 0A 00 LXI D,0AH ;DECIMAL
1654 D5 PUSH D ;SAVE AS A FLAG
1655 0D DCR C ;C=SPACES
1656 C5 PUSH B ;SAVE SIGN & SPACE
1657 CD F5 14 PN2: CALL DIVIDE ;DIVIDE HL BY 10
165A 78 MOV A,B ;RESULT 0?
165B B1 ORA C
165C CA 67 16 JZ PN3 ;YES, WE GOT ALL
165F E3 XTHL ;NO, SAVE REMAINDER
1660 2D DCR L ;AND COUNT SPACE
1661 E5 PUSH H ;HL IS OLD BC
1662 60 MOV H,B ;MOVE RESULT TO BC
1663 69 MOV L,C
1664 C3 57 16 JMP PN2 ;AND DIVIDE BY 10
1667 C1 PN3: POP B ;WE GOT ALL DIGITS IN
1668 0D PN4: DCR C ;THE STACK
1669 79 MOV A,C ;LOOK AT SPACE COUNT
166A B7 ORA A
166B FA 76 16 JM PN5 ;NO LEADING BLANKS
166E 3E 20 MVI A,20H ;LEADING BLANKS
1670 CD 0A 10 CALL OUTC
1673 C3 68 16 JMP PN4 ;MORE?
1676 78 PN5: MOV A,B ;PRINT SIGN
1677 B7 ORA A
1678 C4 10 00 CNZ 10H
167B 5D MOV E,L ;LAST REMAINDER IN E
167C 7B PN6: MOV A,E ;CHECK DIGIT IN E
167D FE 0A CPI 0AH ;10 IS FLAG FOR NO MORE
167F D1 POP D
1680 C8 RZ ;IF SO, RETURN
1681 C6 30 ADI 30H ;ELSE CONVERT TO ASCII
1683 CD 0A 10 CALL OUTC ;AND PRINT THE DIGIT
1686 C3 7C 16 JMP PN6 ;GO BACK FOR MORE
1689 ;
1689 1A PRTLN: LDAX D ;*** PRTLN ***
168A 6F MOV L,A ;LOW ORDER LINE #
168B 13 INX D
168C 1A LDAX D ;HIGH ORDER
168D 67 MOV H,A
168E 13 INX D
168F 0E 04 MVI C,4H ;PRINT 4 DIGIT LINE #
1691 CD 45 16 CALL PRTNUM
1694 3E 20 MVI A,20H ;FOLLOWED BY A BLANK
1696 CD 0A 10 CALL OUTC
1699 97 SUB A ;AND THEN THE NEXT
169A CD 07 16 CALL PRTSTG
169D C9 RET
169E ;
169E ;*************************************************************
169E ;
169E ; *** MVUP *** MVDOWN *** POPA *** & PUSHA ***
169E ;
169E ; "MVUP" MOVES A BLOCK UP FROM WHERE DE-> TO WHERE BC-> UNTIL
169E ; DE = HL
169E ;
169E ; "MVDOWN" MOVES A BLOCK DOWN FROM WHERE DE-> TO WHERE HL->
169E ; UNTIL DE = BC
169E ;
169E ; "POPA" RESTORES THE "FOR" LOOP VARIABLE SAVE AREA FROM THE
169E ; STACK
169E ;
169E ; "PUSHA" STACKS THE "FOR" LOOP VARIABLE SAVE AREA INTO THE
169E ; STACK
169E ;
169E CD 1A 10 MVUP: CALL COMP ;*** MVUP ***
16A1 C8 RZ ;DE = HL, RETURN
16A2 1A LDAX D ;GET ONE BYTE
16A3 02 STAX B ;MOVE IT
16A4 13 INX D ;INCREASE BOTH POINTERS
16A5 03 INX B
16A6 C3 9E 16 JMP MVUP ;UNTIL DONE
16A9 ;
16A9 78 MVDOWN: MOV A,B ;*** MVDOWN ***
16AA 92 SUB D ;TEST IF DE = BC
16AB C2 B1 16 JNZ MD1 ;NO, GO MOVE
16AE 79 MOV A,C ;MAYBE, OTHER BYTE?
16AF 93 SUB E
16B0 C8 RZ ;YES, RETURN
16B1 1B MD1: DCX D ;ELSE MOVE A BYTE
16B2 2B DCX H ;BUT FIRST DECREASE
16B3 1A LDAX D ;BOTH POINTERS AND
16B4 77 MOV M,A ;THEN DO IT
16B5 C3 A9 16 JMP MVDOWN ;LOOP BACK
16B8 ;
16B8 C1 POPA: POP B ;BC = RETURN ADDR.
16B9 E1 POP H ;RESTORE LOPVAR, BUT
16BA 22 0C 80 SHLD LOPVAR ;=0 MEANS NO MORE
16BD 7C MOV A,H
16BE B5 ORA L
16BF CA D2 16 JZ PP1 ;YEP, GO RETURN
16C2 E1 POP H ;NOP, RESTORE OTHERS
16C3 22 0E 80 SHLD LOPINC
16C6 E1 POP H
16C7 22 10 80 SHLD LOPLMT
16CA E1 POP H
16CB 22 12 80 SHLD LOPLN
16CE E1 POP H
16CF 22 14 80 SHLD LOPPT
16D2 C5 PP1: PUSH B ;BC = RETURN ADDR.
16D3 C9 RET
16D4 ;
16D4 21 78 FC PUSHA: LXI H,STKLMT ;*** PUSHA ***
16D7 CD 15 15 CALL CHGSGN
16DA C1 POP B ;BC=RETURN ADDRESS
16DB 39 DAD SP ;IS STACK NEAR THE TOP?
16DC D2 92 15 JNC QSORRY ;YES, SORRY FOR THAT
16DF 2A 0C 80 LHLD LOPVAR ;ELSE SAVE LOOP VAR'S
16E2 7C MOV A,H ;BUT IF LOPVAR IS 0
16E3 B5 ORA L ;THAT WILL BE ALL
16E4 CA FA 16 JZ PU1
16E7 2A 14 80 LHLD LOPPT ;ELSE, MORE TO SAVE
16EA E5 PUSH H
16EB 2A 12 80 LHLD LOPLN
16EE E5 PUSH H
16EF 2A 10 80 LHLD LOPLMT
16F2 E5 PUSH H
16F3 2A 0E 80 LHLD LOPINC
16F6 E5 PUSH H
16F7 2A 0C 80 LHLD LOPVAR
16FA E5 PU1: PUSH H
16FB C5 PUSH B ;BC = RETURN ADDR.
16FC C9 RET
16FD ;
16FD ;*************************************************************
16FD ;
16FD ; *** OUTC *** & CHKIO ***
16FD ;
16FD ; THESE ARE THE ONLY I/O ROUTINES IN TBI.
16FD ; "OUTC" IS CONTROLLED BY A SOFTWARE SWITCH "OCSW". IF OCSW=0
16FD ; "OUTC" WILL JUST RETURN TO THE CALLER. IF OCSW IS NOT 0,
16FD ; IT WILL OUTPUT THE BYTE IN A. IF THAT IS A CR, A LF IS ALSO
16FD ; SEND OUT. ONLY THE FLAGS MAY BE CHANGED AT RETURN. ALL REG.
16FD ; ARE RESTORED.
16FD ;
16FD ; "CHKIO" CHECKS THE INPUT. IF NO INPUT, IT WILL RETURN TO
16FD ; THE CALLER WITH THE Z FLAG SET. IF THERE IS INPUT, Z FLAG
16FD ; IS CLEARED AND THE INPUT BYTE IS IN A. HOWEVER, IF THE
16FD ; INPUT IS A CONTROL-O, THE "OCSW" SWITCH IS COMPLIMENTED, AND
16FD ; Z FLAG IS RETURNED. IF A CONTROL-C IS READ, "CHKIO" WILL
16FD ; RESTART TBI AND DO NOT RETURN TO THE CALLER.
16FD ;
16FD ;OUTC: PUSH PSW ;THIS IS AT LOC. 10
16FD ; LDA OCSW ;CHECK SOFTWARE SWITCH
16FD ; ORA A
16FD ;
16FD ACIA_C: EQU 0DEh
16FD ACIA_D: EQU 0DFh
16FD ;
16FD 32 03 80 INIT: STA OCSW
1700 3E 03 MVI A,3 ;RESET ACIA
1702 D3 DE OUT ACIA_C
1704 3E 15 MVI A,15H ;15H FOR 8N1, 11H FOR 8N2
1706 D3 DE OUT ACIA_C
1708 16 19 MVI D,19H
170A PATLOP:
170A CD 08 10 CALL CRLF
170D 15 DCR D
170E C2 0A 17 JNZ PATLOP
1711 97 SUB A
1712 11 60 17 LXI D,MSG1
1715 CD 07 16 CALL PRTSTG
1718 21 00 10 LXI H,START
171B 22 16 80 SHLD RANPNT
171E 21 1A 80 LXI H,TXTBGN
1721 22 18 80 SHLD TXTUNF
1724 C3 BF 10 JMP RSTART
1727 C2 2C 17 OC2: JNZ OC3 ;IT IS ON
172A F1 POP PSW ;IT IS OFF
172B C9 RET ;RESTORE AF AND RETURN
172C DB DE OC3: IN ACIA_C ;COME HERE TO DO OUTPUT
172E E6 02 ANI 2H ;STATUS BIT
1730 CA 2C 17 JZ OC3 ;NOT READY, WAIT
1733 F1 POP PSW ;READY, GET OLD A BACK
1734 D3 DF OUT ACIA_D ;AND SEND IT OUT
1736 FE 0D CPI CR ;WAS IT CR?
1738 C0 RNZ ;NO, FINISHED
1739 3E 0A MVI A,LF ;YES, WE SEND LF TOO
173B CD 0A 10 CALL OUTC ;THIS IS RECURSIVE
173E 3E 0D MVI A,CR ;GET CR BACK IN A
1740 C9 RET
1741 ;
1741 DB DE CHKIO: IN ACIA_C ;*** CHKIO ***
1743 00 NOP ;STATUS BIT FLIPPED?
1744 E6 01 ANI 01H ;MASK STATUS BIT
1746 C8 RZ ;NOT READY, RETURN "Z"
1747 DB DF IN ACIA_D ;READY, READ DATA
1749 E6 7F ANI 7FH ;MASK BIT 7 OFF
174B FE 0F CPI 0FH ;IS IT CONTROL-O?
174D C2 5A 17 JNZ CI1 ;NO, MORE CHECKING
1750 3A 03 80 LDA OCSW ;CONTROL-O FLIPS OCSW
1753 2F CMA ;ON TO OFF, OFF TO ON
1754 32 03 80 STA OCSW
1757 C3 41 17 JMP CHKIO ;GET ANOTHER INPUT
175A FE 03 CI1: CPI 3H ;IS IT CONTROL-C?
175C C0 RNZ ;NO, RETURN "NZ"
175D C3 BF 10 JMP RSTART ;YES, RESTART TBI
1760 ;
1760 54 49 4E 59 20 MSG1: DB "TINY "
1765 42 41 53 49 43 DB "BASIC"
176A 0D DB CR
176B ;
176B ;*************************************************************
176B ;
176B ; *** TABLES *** DIRECT *** & EXEC ***
176B ;
176B ; THIS SECTION OF THE CODE TESTS A STRING AGAINST A TABLE.
176B ; WHEN A MATCH IS FOUND, CONTROL IS TRANSFERED TO THE SECTION
176B ; OF CODE ACCORDING TO THE TABLE.
176B ;
176B ; AT "EXEC", DE SHOULD POINT TO THE STRING AND HL SHOULD POINT
176B ; TO THE TABLE-1. AT "DIRECT", DE SHOULD POINT TO THE STRING.
176B ; HL WILL BE SET UP TO POINT TO TAB1-1, WHICH IS THE TABLE OF
176B ; ALL DIRECT AND STATEMENT COMMANDS.
176B ;
176B ; A "." IN THE STRING WILL TERMINATE THE TEST AND THE PARTIAL
176B ; MATCH WILL BE CONSIDERED AS A MATCH. E.G., "P.", "PR.",
176B ; "PRI.", "PRIN.", OR "PRINT" WILL ALL MATCH "PRINT".
176B ;
176B ; THE TABLE CONSISTS OF ANY NUMBER OF ITEMS. EACH ITEM
176B ; IS A STRING OF CHARACTERS WITH BIT 7 SET TO 0 AND
176B ; A JUMP ADDRESS STORED HI-LOW WITH BIT 7 OF THE HIGH
176B ; BYTE SET TO 1.
176B ;
176B ; END OF TABLE IS AN ITEM WITH A JUMP ADDRESS ONLY. IF THE
176B ; STRING DOES NOT MATCH ANY OF THE OTHER ITEMS, IT WILL
176B ; MATCH THIS NULL ITEM AS DEFAULT.
176B ;
176B TAB1: ;DIRECT COMMANDS
176B 4C 49 53 54 DB "LIST"
176F ;*Macro unroll: DWA LIST
176F 91 DB >LIST + 128
1770 A0 DB <LIST
1771 52 55 4E DB "RUN"
1774 ;*Macro unroll: DWA RUN
1774 91 DB >RUN + 128
1775 4D DB <RUN
1776 4E 45 57 DB "NEW"
1779 ;*Macro unroll: DWA NEW
1779 91 DB >NEW + 128
177A 3B DB <NEW
177B 42 59 45 DB "BYE"
177E ;*Macro unroll: DWA BYE
177E 91 DB >BYE + 128
177F 4A DB <BYE
1780 ;
1780 TAB2: ;DIRECT/STATEMENT
1780 4E 45 58 54 DB "NEXT"
1784 ;*Macro unroll: DWA NEXT
1784 92 DB >NEXT + 128
1785 A0 DB <NEXT
1786 4C 45 54 DB "LET"
1789 ;*Macro unroll: DWA LET
1789 93 DB >LET + 128
178A 80 DB <LET
178B 49 46 DB "IF"
178D ;*Macro unroll: DWA IFF
178D 93 DB >IFF + 128
178E 05 DB <IFF
178F 47 4F 54 4F DB "GOTO"
1793 ;*Macro unroll: DWA GOTO
1793 91 DB >GOTO + 128
1794 6C DB <GOTO
1795 47 4F 53 55 42 DB "GOSUB"
179A ;*Macro unroll: DWA GOSUB
179A 91 DB >GOSUB + 128
179B FE DB <GOSUB
179C 52 45 54 55 52 4E DB "RETURN"
17A2 ;*Macro unroll: DWA RETURN
17A2 92 DB >RETURN + 128
17A3 20 DB <RETURN
17A4 52 45 4D DB "REM"
17A7 ;*Macro unroll: DWA REM
17A7 93 DB >REM + 128
17A8 01 DB <REM
17A9 46 4F 52 DB "FOR"
17AC ;*Macro unroll: DWA FOR
17AC 92 DB >FOR + 128
17AD 3B DB <FOR
17AE 49 4E 50 55 54 DB "INPUT"
17B3 ;*Macro unroll: DWA INPUT
17B3 93 DB >INPUT + 128
17B4 20 DB <INPUT
17B5 50 52 49 4E 54 DB "PRINT"
17BA ;*Macro unroll: DWA PRINT
17BA 91 DB >PRINT + 128
17BB B8 DB <PRINT
17BC 53 54 4F 50 DB "STOP"
17C0 ;*Macro unroll: DWA STOP
17C0 91 DB >STOP + 128
17C1 44 DB <STOP
17C2 4F 55 54 50 DB "OUTP"
17C6 ;*Macro unroll: DWA OUTP
17C6 91 DB >OUTP + 128
17C7 7D DB <OUTP
17C8 ;*Macro unroll: DWA DEFLT
17C8 93 DB >DEFLT + 128
17C9 7A DB <DEFLT
17CA ;
17CA TAB4: ;FUNCTIONS
17CA 52 4E 44 DB "RND"
17CD ;*Macro unroll: DWA RND
17CD 94 DB >RND + 128
17CE 9A DB <RND
17CF 41 42 53 DB "ABS"
17D2 ;*Macro unroll: DWA ABS
17D2 94 DB >ABS + 128
17D3 C7 DB <ABS
17D4 49 4E 50 DB "INP"
17D7 ;*Macro unroll: DWA INFN
17D7 94 DB >INFN + 128
17D8 D0 DB <INFN
17D9 53 49 5A 45 DB "SIZE"
17DD ;*Macro unroll: DWA SIZE
17DD 94 DB >SIZE + 128
17DE E8 DB <SIZE
17DF ;*Macro unroll: DWA XP40
17DF 94 DB >XP40 + 128
17E0 78 DB <XP40
17E1 ;
17E1 TAB5: ;"TO" IN "FOR"
17E1 54 4F DB "TO"
17E3 ;*Macro unroll: DWA FR1
17E3 92 DB >FR1 + 128
17E4 4B DB <FR1
17E5 ;*Macro unroll: DWA QWHAT
17E5 95 DB >QWHAT + 128
17E6 63 DB <QWHAT
17E7 ;
17E7 TAB6: ;"STEP" IN "FOR"
17E7 53 54 45 50 DB "STEP"
17EB ;*Macro unroll: DWA FR2
17EB 92 DB >FR2 + 128
17EC 57 DB <FR2
17ED ;*Macro unroll: DWA FR3
17ED 92 DB >FR3 + 128
17EE 5D DB <FR3
17EF ;
17EF TAB8: ;RELATION OPERATORS
17EF 3E 3D DB ">="
17F1 ;*Macro unroll: DWA XP11
17F1 93 DB >XP11 + 128
17F2 94 DB <XP11
17F3 23 DB "#"
17F4 ;*Macro unroll: DWA XP12
17F4 93 DB >XP12 + 128
17F5 9A DB <XP12
17F6 3E DB ">"
17F7 ;*Macro unroll: DWA XP13
17F7 93 DB >XP13 + 128
17F8 A0 DB <XP13
17F9 3D DB "="
17FA ;*Macro unroll: DWA XP15
17FA 93 DB >XP15 + 128
17FB AF DB <XP15
17FC 3C 3D DB "<="
17FE ;*Macro unroll: DWA XP14
17FE 93 DB >XP14 + 128
17FF A7 DB <XP14
1800 3C DB "<"
1801 ;*Macro unroll: DWA XP16
1801 93 DB >XP16 + 128
1802 B5 DB <XP16
1803 ;*Macro unroll: DWA XP17
1803 93 DB >XP17 + 128
1804 BB DB <XP17
1805 ;
1805 21 6A 17 DIRECT: LXI H,TAB1-1 ;*** DIRECT ***
1808 ;
1808 EXEC: ;*** EXEC ***
1808 CD 22 10 EX0: CALL IGNBLK ;IGNORE LEADING BLANKS
180B D5 PUSH D ;SAVE POINTER
180C 1A EX1: LDAX D ;IF FOUND "." IN STRING
180D 13 INX D ;BEFORE ANY MISMATCH
180E FE 2E CPI 2EH ;WE DECLARE A MATCH
1810 CA 29 18 JZ EX3
1813 23 INX H ;HL->TABLE
1814 BE CMP M ;IF MATCH, TEST NEXT
1815 CA 0C 18 JZ EX1
1818 3E 7F MVI A,07FH ;ELSE SEE IF BIT 7
181A 1B DCX D ;OF TABLE IS SET, WHICH
181B BE CMP M ;IS THE JUMP ADDR. (HI)
181C DA 30 18 JC EX5 ;C:YES, MATCHED
181F 23 EX2: INX H ;NC:NO, FIND JUMP ADDR.
1820 BE CMP M
1821 D2 1F 18 JNC EX2
1824 23 INX H ;BUMP TO NEXT TAB. ITEM
1825 D1 POP D ;RESTORE STRING POINTER
1826 C3 08 18 JMP EX0 ;TEST AGAINST NEXT ITEM
1829 3E 7F EX3: MVI A,07FH ;PARTIAL MATCH, FIND
182B 23 EX4: INX H ;JUMP ADDR., WHICH IS
182C BE CMP M ;FLAGGED BY BIT 7
182D D2 2B 18 JNC EX4
1830 7E EX5: MOV A,M ;LOAD HL WITH THE JUMP
1831 23 INX H ;ADDRESS FROM THE TABLE
1832 6E MOV L,M
1833 E6 7F ANI 7FH ;MASK OFF BIT 7
1835 67 MOV H,A
1836 F1 POP PSW ;CLEAN UP THE GABAGE
1837 E9 PCHL ;AND WE GO DO IT
1838 ;
1838 LSTROM: ;ALL ABOVE CAN BE ROM
8000 .ORG 8000H ;HERE DOWN MUST BE RAM
8000 ; ORG 0800H
8000 INRAM: DS 3 ; space for IN x;ret;
8003 OCSW: DS 1 ;SWITCH FOR OUTPUT
8004 CURRNT: DS 2 ;POINTS TO CURRENT LINE
8006 STKGOS: DS 2 ;SAVES SP IN "GOSUB"
8008 VARNXT: DS 2 ;TEMP STORAGE
800A STKINP: DS 2 ;SAVES SP IN "INPUT"
800C LOPVAR: DS 2 ;"FOR" LOOP SAVE AREA
800E LOPINC: DS 2 ;INCREMENT
8010 LOPLMT: DS 2 ;LIMIT
8012 LOPLN: DS 2 ;LINE NUMBER
8014 LOPPT: DS 2 ;TEXT POINTER
8016 RANPNT: DS 2 ;RANDOM NUMBER POINTER
8018 TXTUNF: DS 2 ;->UNFILLED TEXT AREA
801A TXTBGN: DS 2 ;TEXT SAVE AREA BEGINS
FC00 .ORG 0fc00H
FC00 ; ORG 1F00H
FC00 TXTEND: DS 0 ;TEXT SAVE AREA ENDS
FC00 VARBGN: DS 55 ;VARIABLE @(0)
FC37 BUFFER: DS 64 ;INPUT BUFFER
FC77 BUFEND: DS 1 ;BUFFER ENDS
FC78 STKLMT: DS 1 ;TOP LIMIT FOR STACK
FFFF .ORG 0ffffH
FFFF ; ORG 2000H
FFFF STACK: DS 0 ;STACK STARTS HERE
FFFF ;
FFFF CR: EQU 0DH
FFFF LF: EQU 0AH
FFFF ;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment