mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2025-04-06 17:39:40 +00:00
basic: OPTION DIALECT must come 1st, hot restart for FOR loops, chainAssignments, more games, CONVERT, DEC+
This commit is contained in:
parent
7f372b0b52
commit
295f1ef9de
230
presets/basic/craps.bas
Normal file
230
presets/basic/craps.bas
Normal file
@ -0,0 +1,230 @@
|
||||
0 REM http://www.bitsavers.org/bits/HP/paperTapes/JeffM/CRAPS.BAS
|
||||
1 OPTION DIALECT HP2000
|
||||
10 REM THIS IS A SPECIAL VERSION OF CRAPS
|
||||
20 REM 1) MAXIMUM BANK IS $1000
|
||||
30 REM 2) THE PLAYER GETS 10 CHANCES TO PLACE A BET
|
||||
40 REM 3) COMMENTS HAVE BEEN ADJUSTED FOR FAMILIES
|
||||
50 PRINT TAB(18)"G T E S Y L V A N I A"
|
||||
60 PRINT
|
||||
70 PRINT TAB(27)"1 9 7 4"
|
||||
80 PRINT
|
||||
90 PRINT TAB(20)"F A M I L Y D A Y"
|
||||
100 PRINT
|
||||
110 PRINT
|
||||
120 PRINT TAB(16)"COMPUTERIZED CRAP GAME RULES"
|
||||
130 PRINT
|
||||
140 PRINT
|
||||
150 PRINT
|
||||
160 PRINT "2, 3, OR 12 ON THE FIRST THROW IS A LOSER."
|
||||
170 PRINT "7 OR 11 ON THE FIRST THROW WINS."
|
||||
180 PRINT
|
||||
190 PRINT "IF FIRST THROW IS NOT A WINNER OR A LOSER IT BECOMES";
|
||||
200 PRINT " YOUR POINT."
|
||||
210 PRINT "CONTINUE TO ROLL UNTIL EITHER 7 OR YOUR POINT OCCURS."
|
||||
220 PRINT "ROLL 7 AND YOU LOSE. MAKE YOUR POINT AND YOU WIN."
|
||||
230 PRINT
|
||||
240 PRINT "YOU MAY END THE GAME BY ENTERING A ZERO BET."
|
||||
250 PRINT
|
||||
260 PRINT "I RESERVE THE RIGHT TO END THE GAME AT ANY TIME."
|
||||
270 PRINT
|
||||
280 LET F6=0
|
||||
290 PRINT "NO PROFANITY!"
|
||||
300 PRINT
|
||||
310 PRINT "WHAT TIME IS IT";
|
||||
320 INPUT T
|
||||
330 IF T<2401 THEN 390
|
||||
340 IF F6<1 THEN 360
|
||||
350 PRINT "DUMMY! ";
|
||||
360 PRINT "WHAT TIME";
|
||||
370 LET F6=F6+1
|
||||
380 GOTO 320
|
||||
390 LET T=T*19
|
||||
400 IF T<1900 THEN 430
|
||||
410 LET T=T-1900
|
||||
420 GOTO 400
|
||||
430 PRINT "THANK YOU - ON WITH THE GAME."
|
||||
440 FOR D=1 TO T
|
||||
450 LET R1=RND(0)
|
||||
460 NEXT D
|
||||
470 LET F2=0
|
||||
480 LET F3=0
|
||||
490 LET F4=0
|
||||
500 LET F5=0
|
||||
510 LET X=0
|
||||
520 LET Y=0
|
||||
530 PRINT " ENTER YOUR BANKROLL ";
|
||||
540 INPUT F7
|
||||
550 IF F7<1001 THEN 620
|
||||
560 LET F5=F5+1
|
||||
570 IF F5>1 THEN 600
|
||||
580 PRINT "YOU'RE TOO RICH FOR MY ELECTRONS!"
|
||||
590 GOTO 530
|
||||
600 PRINT "BE REASONABLE! THIS IS NOT LOS VEGAS."
|
||||
610 GOTO 530
|
||||
620 LET F8=F7
|
||||
630 PRINT "YOU NOW HAVE TEN TRYS TO BEAT THE BANK."
|
||||
640 LET Q=10
|
||||
650 GOTO 750
|
||||
660 PRINT
|
||||
670 IF F8>F7 THEN 710
|
||||
680 IF F7>F8 THEN 730
|
||||
690 PRINT "EVEN WITH THE BOARD - HMPH!"
|
||||
700 GOTO 2050
|
||||
710 PRINT "YOU HAVE WON "F8-F7" DOLLARS. TRY AND GET IT."
|
||||
720 GOTO 2050
|
||||
730 PRINT "YOU HAVE LOST "F7-F8" DOLLARS. SORRY ABOUT THAT."
|
||||
740 GOTO 2050
|
||||
750 IF Q=0 THEN 660
|
||||
760 LET Q=Q-1
|
||||
770 PRINT " PLACE YOUR BET ";
|
||||
780 INPUT B
|
||||
790 IF B=0 THEN 660
|
||||
800 IF B<1 THEN 1830
|
||||
810 IF B>F8 THEN 1890
|
||||
820 LET B=INT(B)
|
||||
830 GOSUB 2240
|
||||
840 PRINT " FIRST THROW";V;W;
|
||||
850 IF A=2 THEN 930
|
||||
860 IF A=3 THEN 950
|
||||
870 IF A=7 THEN 970
|
||||
880 IF A=11 THEN 990
|
||||
890 IF A=12 THEN 910
|
||||
900 GOTO 1010
|
||||
910 PRINT " BOX CARS ";
|
||||
920 GOTO 1430
|
||||
930 PRINT " SNAKE EYES ";
|
||||
940 GOTO 1430
|
||||
950 PRINT " CRAPS ";
|
||||
960 GOTO 1430
|
||||
970 PRINT " BIG SEVEN - A WINNER";
|
||||
980 GOTO 1090
|
||||
990 PRINT " BIG ELEVEN - A WINNER";
|
||||
1000 GOTO 1090
|
||||
1010 LET C=A
|
||||
1020 PRINT " YOUR POINT ";A
|
||||
1030 GOSUB 2240
|
||||
1040 PRINT " NEXT THROW ";V;W
|
||||
1050 IF A=7 THEN 1410
|
||||
1060 IF A#C THEN 1030
|
||||
1070 PRINT " MADE YOUR POINT";
|
||||
1080 REM WIN COUNTER
|
||||
1090 LET X=X+1
|
||||
1100 IF X>1 THEN 1150
|
||||
1110 IF X=3 THEN 1170
|
||||
1120 IF X=4 THEN 1190
|
||||
1130 IF X>4 THEN 1210
|
||||
1140 GOTO 1220
|
||||
1150 PRINT " AGAIN";
|
||||
1160 GOTO 1110
|
||||
1170 PRINT ". DARNIT!";
|
||||
1180 GOTO 1220
|
||||
1190 PRINT ". STOP THAT!";
|
||||
1200 GOTO 1220
|
||||
1210 PRINT ". -DISGUSTING-";
|
||||
1220 IF Y=2 THEN 1280
|
||||
1230 IF Y=3 THEN 1300
|
||||
1240 IF Y=4 THEN 1320
|
||||
1250 IF Y=5 THEN 1340
|
||||
1260 IF Y>5 THEN 1360
|
||||
1270 GOTO 1370
|
||||
1280 PRINT " FOR A CHANGE - DON'T GET COCKY.";
|
||||
1290 GOTO 1370
|
||||
1300 PRINT " IN SPITE OF ME.";
|
||||
1310 GOTO 1370
|
||||
1320 PRINT " SPOIL SPORT";
|
||||
1330 GOTO 1370
|
||||
1340 PRINT " FEEL BETTER?";
|
||||
1350 GOTO 1370
|
||||
1360 PRINT " - - RELAX";
|
||||
1370 LET Y=0
|
||||
1380 PRINT
|
||||
1390 LET F8=F8+B
|
||||
1400 GOTO 1800
|
||||
1410 PRINT " SEVEN - - -";
|
||||
1420 REM LOSS COUNTER
|
||||
1430 LET Y=Y+1
|
||||
1440 PRINT " YOU LOSE";
|
||||
1450 IF Y>1 THEN 1550
|
||||
1460 IF Y=3 THEN 1570
|
||||
1470 IF Y=4 THEN 1590
|
||||
1480 IF Y=5 THEN 1610
|
||||
1490 IF Y>5 THEN 1630
|
||||
1500 IF X=2 THEN 1650
|
||||
1510 IF X=3 THEN 1680
|
||||
1520 IF X=4 THEN 1710
|
||||
1530 IF X>4 THEN 1740
|
||||
1540 GOTO 1760
|
||||
1550 PRINT " AGAIN. ";
|
||||
1560 GOTO 1460
|
||||
1570 PRINT " KEEP UP THE GOOD WORK!";
|
||||
1580 GOTO 1500
|
||||
1590 PRINT " EAT YOUR HEART OUT!";
|
||||
1600 GOTO 1500
|
||||
1610 PRINT " IT'S NOT YOUR DAY, IS IT, SUCKER?";
|
||||
1620 GOTO 1500
|
||||
1630 PRINT " YOU'RE JUST TOO GOOD TO BE TRUE.";
|
||||
1640 GOTO 1500
|
||||
1650 PRINT ".";
|
||||
1660 PRINT " BUT KEEP TRYING.";
|
||||
1670 GOTO 1760
|
||||
1680 PRINT ".";
|
||||
1690 PRINT " THAT ENDS YOUR LITTLE STREAK.";
|
||||
1700 GOTO 1760
|
||||
1710 PRINT ".";
|
||||
1720 PRINT " GOTCHA!";
|
||||
1730 GOTO 1760
|
||||
1740 PRINT ".";
|
||||
1750 PRINT " AT LAST I FIXED YOUR WAGON.";
|
||||
1760 PRINT ""
|
||||
1770 LET X=0
|
||||
1780 LET F8=F8-B
|
||||
1790 IF F8<1 THEN 2220
|
||||
1800 PRINT
|
||||
1810 PRINT "YOU NOW HAVE "F8"DOLLARS IN THE BANK."
|
||||
1820 GOTO 750
|
||||
1830 PRINT "NO BETS LESS THAN A BUCK.";
|
||||
1840 LET F2=F2+1
|
||||
1850 IF F2=2 THEN 1950
|
||||
1860 IF F2>2 THEN 1970
|
||||
1870 PRINT
|
||||
1880 GOTO 750
|
||||
1890 PRINT "NO CREDIT AT THIS CASINO.";
|
||||
1900 LET F3=F3+1
|
||||
1910 IF F3=2 THEN 1950
|
||||
1920 IF F3>2 THEN 1970
|
||||
1930 PRINT
|
||||
1940 GOTO 750
|
||||
1950 PRINT " (SECOND WARNING)"
|
||||
1960 GOTO 750
|
||||
1970 PRINT " G O T O # @ & % "
|
||||
1980 LET F4=F4+1
|
||||
1990 IF F4=2 THEN 2020
|
||||
2000 IF F4>2 THEN 2040
|
||||
2010 GOTO 750
|
||||
2020 PRINT " DO THAT AGAIN AND I'LL QUIT"
|
||||
2030 GOTO 750
|
||||
2040 PRINT " I WARNED YOU - SMART GUY - I QUIT"
|
||||
2050 PRINT
|
||||
2060 PRINT
|
||||
2070 PRINT
|
||||
2080 PRINT
|
||||
2090 PRINT "NEXT PLAYER. . . PLEASE ENTER YOUR LUCKY NUMBER."
|
||||
2100 PRINT
|
||||
2110 PRINT
|
||||
2120 PRINT
|
||||
2130 PRINT
|
||||
2140 PRINT
|
||||
2150 PRINT
|
||||
2160 INPUT F6
|
||||
2170 PRINT
|
||||
2180 PRINT
|
||||
2190 PRINT
|
||||
2200 PRINT
|
||||
2210 GOTO 50
|
||||
2220 PRINT " B U S T"
|
||||
2230 GOTO 2050
|
||||
2240 LET V=INT(6*RND(0)+1)
|
||||
2250 LET W=INT(6*RND(0)+1)
|
||||
2260 LET A=V+W
|
||||
2270 RETURN
|
||||
2280 END
|
1445
presets/basic/haunted.bas
Normal file
1445
presets/basic/haunted.bas
Normal file
File diff suppressed because it is too large
Load Diff
196
presets/basic/lander.bas
Normal file
196
presets/basic/lander.bas
Normal file
@ -0,0 +1,196 @@
|
||||
0 OPTION DIALECT HP
|
||||
1 REM **** HP BASIC PROGRAM LIBRARY **************************
|
||||
2 REM
|
||||
3 REM LANDER: ROCKET LANDING VEHICLE
|
||||
4 REM
|
||||
5 REM 36684 REV A -- 10/73
|
||||
6 REM REV A-1 -- 3/75 BYARD
|
||||
7 REM **** CONTRIBUTED PROGRAM *******************************
|
||||
100 REM PROGRAM LANDER
|
||||
110 REM
|
||||
130 REM
|
||||
200 PRINT "WELCOME TO THE PUC SCHOOL FOR BUDDING ASTRONAUTS!"
|
||||
210 PRINT
|
||||
220 PRINT " DO YOU WANT INSTRUCTIONS? 1=YES ";
|
||||
230 INPUT C
|
||||
240 PRINT
|
||||
250 IF C#1 THEN 1000
|
||||
300 PRINT "YOU ARE AT THE CONTROLS OF A ROCKET LANDING VEHICLE."
|
||||
310 PRINT
|
||||
320 PRINT "INITIALLY YOU ARE A GIVEN DISTANCE ABOVE THE SURFACE ";
|
||||
330 PRINT "MOVING"
|
||||
335 PRINT "DOWNWARD (VELOCITY IS NEGATIVE)."
|
||||
350 PRINT "YOU CHOOSE THE AMOUNT OF FUEL TO BE BURNED DURING";
|
||||
360 PRINT " THE NEXT ONE SECOND."
|
||||
370 PRINT "OF TIME."
|
||||
400 PRINT
|
||||
410 PRINT " IF YOU BURN ZERO, THEN YOU WILL FALL FASTER BECAUSE OF ";
|
||||
420 PRINT "GRAVITY."
|
||||
430 PRINT " IF YOU BURN EXACTLY THAT REQUIRED TO OVERCOME GRAVITY, ";
|
||||
440 PRINT "THEN"
|
||||
445 PRINT "YOUR VELOCITY WILL BE CONSTANT."
|
||||
450 PRINT " IF YOU BURN MORE, THEN YOU WILL SLOW DOWN OR EVEN";
|
||||
460 PRINT " START TO MOVE"
|
||||
470 PRINT "UPWARD (VELOCITY IS POSITIVE)!"
|
||||
475 PRINT
|
||||
480 PRINT "THE IDEA IS TO GET THE LANDER DOWN TO THE SURFACE,";
|
||||
490 PRINT " LANDING WITH AS"
|
||||
495 PRINT "LITTLE VELOCITY AS POSSIBLE."
|
||||
500 PRINT "THERE IS MORE THAN ENOUGH FUEL, BUT BE CAREFUL NOT";
|
||||
510 PRINT " TO WASTE IT!"
|
||||
600 PRINT
|
||||
700 PRINT "LANDING ON THE MOON IS EASIER, TRY THAT FIRST."
|
||||
720 PRINT
|
||||
730 PRINT
|
||||
1000 PRINT "GOOD LUCK AND HAPPY LANDINGS!"
|
||||
1005 REM
|
||||
1006 LET X0=V0=0
|
||||
1007 PRINT
|
||||
1010 PRINT
|
||||
1030 PRINT "LOCATION: MOON(1) OR EARTH(2) ";
|
||||
1040 INPUT C
|
||||
1042 PRINT
|
||||
1043 LET K=0
|
||||
1045 IF C=1 THEN 1060
|
||||
1047 LET K=1
|
||||
1048 IF C=2 THEN 1060
|
||||
1050 PRINT "THAT LOCATION IS NOT RECOGNIZED."
|
||||
1055 GOTO 1030
|
||||
1060 LET G=5+27*K
|
||||
1070 LET M=30+60*K
|
||||
1075 IF X0>0 THEN 1100
|
||||
1080 LET X=X0=500+1500*K
|
||||
1090 LET V=V0=-50-100*K
|
||||
1100 PRINT "INITIAL CONDITIONS: STANDARD(1), OLD(2), OR NEW(3) ";
|
||||
1110 INPUT D
|
||||
1120 IF D=1 THEN 1150
|
||||
1130 LET X=500+1500*K
|
||||
1140 LET V=-50-100*K
|
||||
1145 GOTO 1200
|
||||
1150 IF D=2 THEN 1170
|
||||
1155 LET X=X0
|
||||
1160 LET V=V0
|
||||
1165 GOTO 1200
|
||||
1170 LET X=INT(RND(0)*(100+K*100))*10+100
|
||||
1180 LET V=-INT(RND(0)*(10+K*10))*5
|
||||
1190 IF V*V>2*(M-G)*X THEN 1180
|
||||
1200 LET X0=X
|
||||
1210 LET V0=V
|
||||
1290 LET F=INT((M*(V^2+2*G*X)/(M-G))^.5*.13+.5)*10
|
||||
1300 PRINT
|
||||
1302 PRINT "INITIAL HEIGHT: ";X;"FEET"
|
||||
1303 PRINT "INITIAL VELOCITY: ";V;"FEET/SEC"
|
||||
1305 PRINT "TOTAL FUEL SUPPLY: ";F;"UNITS"
|
||||
1307 PRINT "MAXIMUM BURN: ";M;"UNITS/SEC"
|
||||
1308 PRINT "AMOUNT OF BURN TO CANCEL GRAVITY: ";G;"UNITS/SEC"
|
||||
1320 PRINT
|
||||
1330 PRINT
|
||||
1340 PRINT "TIME","HEIGHT","VELOCITY","FUEL","BURN"
|
||||
1350 PRINT
|
||||
2000 LET T=-1
|
||||
2010 LET T=T+1
|
||||
2020 PRINT T,X,V,F," ";
|
||||
2030 INPUT B
|
||||
2040 LET B1=ABS(B)
|
||||
2050 IF B1 <= M THEN 2080
|
||||
2060 PRINT " ","MAX BURN IS ";M;"BURN ";
|
||||
2070 GOTO 2030
|
||||
2080 LET T9=T8=2
|
||||
2090 IF B1=0 THEN 2110
|
||||
2100 LET T9=F/B1
|
||||
2110 LET A=B-G
|
||||
2120 LET R=V*V-2*A*X
|
||||
2140 IF R<0 THEN 2200
|
||||
2150 IF A=0 THEN 2180
|
||||
2160 LET T8=-(V+R^.5)/A
|
||||
2170 GOTO 2200
|
||||
2180 IF V >= 0 THEN 2200
|
||||
2190 LET T8=-X/V
|
||||
2200 IF (T8>0 AND T8 <= 1) OR T9 <= 1 THEN 2300
|
||||
2210 LET X=X+V+A/2
|
||||
2220 LET V=V+A
|
||||
2230 LET F=F-B1
|
||||
2235 IF X>1.00000E-04 THEN 2010
|
||||
2240 LET T=T+1
|
||||
2245 GOTO 2630
|
||||
2300 IF T8>0 AND T8 <= T9 THEN 2600
|
||||
2310 PRINT T+T9,"OUT OF FUEL"
|
||||
2320 LET F=B1=0
|
||||
2330 LET X=X+V*T9+A*T9^2/2
|
||||
2340 LET V=V+A*T9
|
||||
2350 LET A=-G
|
||||
2360 LET T8=(V+(V*V-2*A*X)^.5)/G
|
||||
2370 IF T8<1-T9 THEN 2500
|
||||
2380 LET X=X+V*(1-T9)+A*(1-T9)^2/2
|
||||
2390 LET V=V+A*(1-T9)
|
||||
2400 LET T=T+1
|
||||
2410 PRINT T,X,V
|
||||
2420 LET T8=(V+(V^2-2*A*X)^.5)/G
|
||||
2430 IF T8 <= 1 THEN 2600
|
||||
2440 LET X=X+V+A/2
|
||||
2450 LET V=V+A
|
||||
2460 GOTO 2400
|
||||
2500 LET T=T+T9
|
||||
2600 LET F=F-B1*T8
|
||||
2610 LET T=T+T8
|
||||
2620 LET V=V+A*T8
|
||||
2630 PRINT T,0,V,F
|
||||
2640 PRINT
|
||||
2650 PRINT
|
||||
2700 IF V<-1 THEN 2800
|
||||
2710 LET D=INT(RND(0)*5+1)
|
||||
2711 IF D=2 THEN 2730
|
||||
2712 IF D=3 THEN 2745
|
||||
2713 IF D=4 THEN 2750
|
||||
2714 IF D=5 THEN 2760
|
||||
2720 PRINT "YOU ARE NOW A QUALIFIED ASTRONAUT."
|
||||
2725 GOTO 1007
|
||||
2730 PRINT "AS GENTLE AS A KITTEN'S PURR!!"
|
||||
2735 GOTO 1007
|
||||
2740 PRINT "A BUTTERFLY COULDN'T HAVE DONE BETTER!"
|
||||
2745 GOTO 1007
|
||||
2750 PRINT "AS SOFT AS A SNOWFLAKE!"
|
||||
2755 GOTO 1007
|
||||
2760 PRINT "MR. SPOCK WOULD BE PROUD OF YOU!!!"
|
||||
2765 GOTO 1007
|
||||
2800 IF V<-5 THEN 2900
|
||||
2810 LET D=INT(RND(0)*4+1)
|
||||
2811 IF D=2 THEN 2830
|
||||
2812 IF D=3 THEN 2840
|
||||
2813 IF D=4 THEN 2850
|
||||
2820 PRINT "A BIT ROUGH, BUT YOU ARE STILL IN ONE PIECE!"
|
||||
2825 GOTO 1007
|
||||
2830 PRINT "IF YOU HAD BEEN DRIVING A 1970 LTD, THAT WOULD HAVE COST";
|
||||
2831 PRINT " YOU $500!"
|
||||
2835 GOTO 1007
|
||||
2840 PRINT "ANY FASTER AND YOU WOULD HAVE BOUNCED!"
|
||||
2845 GOTO 1007
|
||||
2850 PRINT "YOU HAD BETTER CHECK YOU LANDING GEAR!!"
|
||||
2855 GOTO 1007
|
||||
2900 IF V<-10 THEN 3000
|
||||
2910 LET D=INT(RND(0)*5+1)
|
||||
2911 IF D=2 THEN 2930
|
||||
2912 IF D=3 THEN 2940
|
||||
2913 IF D=4 THEN 2950
|
||||
2914 IF D=5 THEN 2960
|
||||
2920 PRINT "IS YOUR MEDICAL INSURANCE PAID UP??"
|
||||
2925 GOTO 1007
|
||||
2930 PRINT "YOU GOT DOWN, BUT YOU WILL NEVER BE AN ASTRONAUT!"
|
||||
2935 GOTO 1007
|
||||
2940 PRINT "NEIL ARMSTRONG DID IT THE FIRST TIME!!"
|
||||
2945 GOTO 1007
|
||||
2950 PRINT "THE BEST LAID SCHEMES OF MICE AND MEN,"
|
||||
2951 PRINT " OFT' GO ASTRAY."
|
||||
2955 GOTO 1007
|
||||
2960 PRINT "HAVE YOU EVER THOUGHT OF A DIFFERENT LINE OF WORK??"
|
||||
2965 GOTO 1007
|
||||
3000 LET D=INT(RND(0)*3+1)
|
||||
3001 IF D=2 THEN 3020
|
||||
3002 IF D=3 THEN 3030
|
||||
3010 PRINT "YOUR NEXT OF KIN WILL BE NOTIFIED."
|
||||
3015 GOTO 1007
|
||||
3020 PRINT "YOU JUST CREAMED A 29 MEGABUCK LANDER!"
|
||||
3025 GOTO 1007
|
||||
3030 PRINT "AREN'T YOU GLAD THIS IS ONLY A COMPUTER SIMULATION!!"
|
||||
3035 GOTO 1007
|
||||
9999 END
|
96
presets/basic/mortgage.bas
Normal file
96
presets/basic/mortgage.bas
Normal file
@ -0,0 +1,96 @@
|
||||
1 OPTION DIALECT HP
|
||||
10 PRINT "DANIEL O'ROURKE FEB. 23, 1977"
|
||||
20 PRINT "MINI-COMPUTOR 102"
|
||||
30 PRINT "SUBJECT: MORTGAGE PAYMENT"
|
||||
40 FOR A=1 TO 3
|
||||
50 PRINT
|
||||
60 NEXT A
|
||||
70 PRINT "HI, I AM A COMPUTOR. YOU HAVE COME TO ME "
|
||||
80 PRINT "SO I CAN HELP YOU SOLVE YOUR MORTGAGE"
|
||||
90 PRINT "PROBLEMS, BECAUSE I CAN MAKE CALCULATIONS"
|
||||
100 PRINT "MUCH FASTER AND MORE ACCURATELY THAN YOU"
|
||||
110 PRINT "CAN. IF YOU DON'T KNOW HOW TO USE ME,AND"
|
||||
120 PRINT "YOU WOULD LIKE INSTRUCTIONS, PLEASE TYPE"
|
||||
125 PRINT "A 1 (ONE). FOLLOW IT WITH A CARRIAGE RETURN."
|
||||
130 PRINT "IF NOT TYPE A 0 (ZERO) FOLLOWED BY A CARRI-"
|
||||
140 PRINT "AGE RETURN. DO IT NOW, PLEASE."
|
||||
142 PRINT
|
||||
144 PRINT
|
||||
150 INPUT B
|
||||
152 IF B=1 THEN 160
|
||||
155 IF B=0 THEN 285
|
||||
157 IF B#1 THEN 142
|
||||
160 PRINT
|
||||
165 PRINT
|
||||
170 PRINT "THANK YOU, HERE ARE YOUR INSTRUCTIONS."
|
||||
180 PRINT
|
||||
190 PRINT
|
||||
200 GOTO 250
|
||||
250 PRINT "TYPE IN THE AMOUNT YOU WISH TO BORROW."
|
||||
260 PRINT "FOLLOW IT WITH A COMMA (,) THEN TYPE IN"
|
||||
270 PRINT "THE NUMBER OF YEARS YOU WOULD LIKE TO TAKE"
|
||||
280 PRINT "TO REPAY THAT LOAN. FOLLOW THAT WITH"
|
||||
282 PRINT "A CARRIAGE RETURN. DO IT NOW."
|
||||
285 PRINT
|
||||
286 PRINT
|
||||
290 INPUT C,D
|
||||
295 PRINT
|
||||
296 PRINT
|
||||
297 IF B=0 THEN 340
|
||||
300 PRINT "THANK YOU, NOW TYPE IN THE INTEREST RATE."
|
||||
310 PRINT "THIS INFORMATION MUST BE IN DECIMAL FORM."
|
||||
320 PRINT "EXAMPLE: .10=10% INTEREST RATE."
|
||||
325 PRINT "FOLLOW THIS INFORMATION WITH A CARRIAGE RE-"
|
||||
330 PRINT "TURN. DO IT NOW."
|
||||
340 INPUT E
|
||||
342 LET G=C*(((E/12)*(1+E/12)^(D*12))/((1+E/12)^(D*12)-1))
|
||||
344 LET F=(G*D*(12))-C
|
||||
350 PRINT
|
||||
351 PRINT
|
||||
352 PRINT "THANK YOU."
|
||||
354 PRINT "THE TOTAL COST OF YOUR LOAN IS";F
|
||||
355 PRINT
|
||||
356 PRINT "YOUR MONTHLY PAYMENTS (INCLUDING INTEREST) ARE";G
|
||||
358 PRINT
|
||||
359 PRINT
|
||||
360 PRINT "NOW YOU WILL RECEIVE A PAYMENT SCHEDULE"
|
||||
370 PRINT "OF PAYMENTS FOR THE FIRST TWELVE MONTHS OF"
|
||||
380 PRINT "YOUR REPAYMENT PERIOD. THEN I WILL TELL YOU"
|
||||
390 PRINT "HOW MUCH YOU HAVE PAID TOWARDS THE PRINCIPLE,"
|
||||
400 PRINT "THEN I WILL TELL YOU HOW MUCH YOU HAVE PAID"
|
||||
410 PRINT "ON THE INTEREST, AND THEN I WILL TELL YOU HOW"
|
||||
420 PRINT "MUCH YOU STILL HAVE LEFT TO REPAY (BALANCE DUE)."
|
||||
430 PRINT
|
||||
440 PRINT
|
||||
510 PRINT "MONTH","PRINCIPLE","INTEREST","BALANCE DUE"
|
||||
515 LET R=(E/12)*C
|
||||
520 FOR I=1 TO 12
|
||||
530 LET K=(E/12)*C
|
||||
540 LET P=G-K
|
||||
550 LET C=(C)-(P)
|
||||
570 PRINT I,P,K,C
|
||||
600 NEXT I
|
||||
650 PRINT
|
||||
660 PRINT
|
||||
670 PRINT "THE AMOUNT YOU HAVE PAID TOWARDS THE PRINCIPLE IS:"
|
||||
675 LET Q=G-E
|
||||
685 PRINT
|
||||
690 PRINT "$";Q
|
||||
695 PRINT
|
||||
700 PRINT
|
||||
710 PRINT "THE AMOUNT YOU HAVE PAID ON INTEREST IS:"
|
||||
715 PRINT
|
||||
720 PRINT "$";R
|
||||
725 PRINT
|
||||
730 PRINT
|
||||
735 PRINT "YOUR BALANCE DUE IS:"
|
||||
736 PRINT
|
||||
740 PRINT "$";C
|
||||
750 PRINT
|
||||
760 PRINT
|
||||
780 PRINT "THIS COMPLETES THE MORTGAGE PAYMENT PROGRAM."
|
||||
790 PRINT "THANK YOU FOR YOUR COOPERATION."
|
||||
800 FOR T=1 TO 4
|
||||
810 PRINT
|
||||
820 NEXT T
|
||||
999 END
|
@ -1,3 +1,6 @@
|
||||
1 REM***STAR TRADER FROM
|
||||
2 REM***http://www.dunnington.info/public/basicgames/
|
||||
3 REM***2 chain files merged and ported to 8bitworkshop
|
||||
5 OPTION DIALECT HP
|
||||
6 OPTION BASE 0:REM I GUESS HP HAS ZERO BASE???
|
||||
10010 DIM S[12,15],T[12,12],T$[72],B[3,12]
|
||||
|
@ -136,19 +136,15 @@ CodeMirror.defineMode("basic", function(conf, parserConf) {
|
||||
return null;
|
||||
}
|
||||
if (stream.match(doOpening)) {
|
||||
/*
|
||||
indent(stream,state);
|
||||
state.doInCurrentLine = true;
|
||||
*/
|
||||
return 'keyword';
|
||||
}
|
||||
if (stream.match(opening)) {
|
||||
/*
|
||||
if (! state.doInCurrentLine)
|
||||
indent(stream,state);
|
||||
else
|
||||
state.doInCurrentLine = false;
|
||||
*/
|
||||
return 'keyword';
|
||||
}
|
||||
if (stream.match(middle)) {
|
||||
@ -222,7 +218,6 @@ CodeMirror.defineMode("basic", function(conf, parserConf) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var delimiter_index = '[({'.indexOf(current);
|
||||
if (delimiter_index !== -1) {
|
||||
indent(stream, state );
|
||||
@ -271,12 +266,15 @@ CodeMirror.defineMode("basic", function(conf, parserConf) {
|
||||
return style;
|
||||
},
|
||||
|
||||
/* TODO: indentation
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
var trueText = textAfter.replace(/^\s+|\s+$/g, '') ;
|
||||
if (trueText.match(closing) || trueText.match(doubleClosing) || trueText.match(middle)) return conf.indentUnit*(state.currentIndent-1);
|
||||
if(state.currentIndent < 0) return 0;
|
||||
return state.currentIndent * conf.indentUnit;
|
||||
},
|
||||
*/
|
||||
|
||||
lineComment: "'"
|
||||
};
|
||||
|
@ -11,6 +11,7 @@ export interface BASICOptions {
|
||||
squareBrackets : boolean; // "[" and "]" interchangable with "(" and ")"?
|
||||
tickComments : boolean; // support 'comments?
|
||||
hexOctalConsts : boolean; // support &H and &O integer constants?
|
||||
chainAssignments : boolean; // support A = B = value (HP2000)
|
||||
validKeywords : string[]; // valid keywords (or null for accept all)
|
||||
validFunctions : string[]; // valid functions (or null for accept all)
|
||||
validOperators : string[]; // valid operators (or null for accept all)
|
||||
@ -59,7 +60,7 @@ export class CompileError extends Error {
|
||||
|
||||
// Lexer regular expression -- each (capture group) handles a different token type
|
||||
// FLOAT INT HEXOCTAL REMARK IDENT STRING RELOP EXP OPERATORS OTHER WS
|
||||
const re_toks = /([0-9.]+[E][+-]?\d+|\d+[.][E0-9]*|[.][E0-9]+)|[0]*(\d+)|&([OH][0-9A-F]+)|(['].*)|(\w+[$]?)|(".*?")|([<>]?[=<>#])|(\*\*)|([-+*/^,;:()\[\]?\\])|(\S+)|(\s+)/gi;
|
||||
const re_toks = /([0-9.]+[E][+-]?\d+|\d+[.][E0-9]*|[.][E0-9]+)|[0]*(\d+)|&([OH][0-9A-F]+)|(['].*)|(\w+[$]?)|(".*?")|([<>]?[=<>#])|(\*\*)|([-+*/^,;:()\[\]\?\\])|(\S+)|(\s+)/gi;
|
||||
|
||||
export enum TokenType {
|
||||
EOL = 0,
|
||||
@ -112,7 +113,7 @@ export interface PRINT_Statement {
|
||||
|
||||
export interface LET_Statement {
|
||||
command: "LET";
|
||||
lexpr: IndOp;
|
||||
lexprs: IndOp[];
|
||||
right: Expr;
|
||||
}
|
||||
|
||||
@ -210,6 +211,12 @@ export interface GET_Statement { // applesoft only?
|
||||
lexpr: IndOp;
|
||||
}
|
||||
|
||||
export interface CHANGE_Statement {
|
||||
command: "CHANGE";
|
||||
src: Expr;
|
||||
dest: IndOp;
|
||||
}
|
||||
|
||||
export interface NoArgStatement {
|
||||
command: string;
|
||||
}
|
||||
@ -247,10 +254,10 @@ const OPERATORS = {
|
||||
'||': {f:'lor',p:17}, // not used
|
||||
'&&': {f:'land',p:18}, // not used
|
||||
'=': {f:'eq',p:50},
|
||||
//'==': {f:'eq',p:50},
|
||||
'==': {f:'eq',p:50},
|
||||
'<>': {f:'ne',p:50},
|
||||
'><': {f:'ne',p:50},
|
||||
//'!=': {f:'ne',p:50},
|
||||
'!=': {f:'ne',p:50},
|
||||
'#': {f:'ne',p:50},
|
||||
'<': {f:'lt',p:50},
|
||||
'>': {f:'gt',p:50},
|
||||
@ -299,6 +306,7 @@ function stripQuotes(s: string) {
|
||||
|
||||
export class BASICParser {
|
||||
opts : BASICOptions = DIALECTS['DEFAULT'];
|
||||
optionCount : number;
|
||||
errors: WorkerError[];
|
||||
listings: CodeListingMap;
|
||||
labels: { [label: string]: BASICLine };
|
||||
@ -320,6 +328,7 @@ export class BASICParser {
|
||||
this.curlabel = null;
|
||||
this.listings = {};
|
||||
this.refs = {};
|
||||
this.optionCount = 0;
|
||||
}
|
||||
addError(msg: string, loc?: SourceLocation) {
|
||||
if (!loc) loc = this.peekToken().$loc;
|
||||
@ -352,8 +361,8 @@ export class BASICParser {
|
||||
}
|
||||
return tok;
|
||||
}
|
||||
peekToken(): Token {
|
||||
var tok = this.tokens[0];
|
||||
peekToken(lookahead?: number): Token {
|
||||
var tok = this.tokens[lookahead || 0];
|
||||
return tok ? tok : this.eol;
|
||||
}
|
||||
pushbackToken(tok: Token) {
|
||||
@ -385,6 +394,7 @@ export class BASICParser {
|
||||
default:
|
||||
if (this.opts.optionalLabels) this.compileError(`A line must start with a line number, command, or label.`);
|
||||
else this.compileError(`A line must start with a line number.`);
|
||||
case TokenType.Remark:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -487,6 +497,10 @@ export class BASICParser {
|
||||
validKeyword(keyword: string) : string {
|
||||
return (this.opts.validKeywords && this.opts.validKeywords.indexOf(keyword) < 0) ? null : keyword;
|
||||
}
|
||||
supportsKeyword(keyword: string) {
|
||||
if (this['stmt__' + keyword] != null) return true;
|
||||
return false;
|
||||
}
|
||||
parseStatement(): Statement | null {
|
||||
var cmdtok = this.consumeToken();
|
||||
var cmd = cmdtok.str;
|
||||
@ -735,10 +749,15 @@ export class BASICParser {
|
||||
//// STATEMENTS
|
||||
|
||||
stmt__LET(): LET_Statement {
|
||||
var lexpr = this.parseLexpr();
|
||||
var lexprs = [ this.parseLexpr() ];
|
||||
this.expectToken("=");
|
||||
// look for A=B=expr (TODO: doesn't work on arrays)
|
||||
while (this.opts.chainAssignments && this.peekToken().type == TokenType.Ident && this.peekToken(1).str == '=') {
|
||||
lexprs.push(this.parseLexpr());
|
||||
this.expectToken("=");
|
||||
}
|
||||
var right = this.parseExpr();
|
||||
return { command: "LET", lexpr: lexpr, right: right };
|
||||
return { command: "LET", lexprs: lexprs, right: right };
|
||||
}
|
||||
stmt__PRINT(): PRINT_Statement {
|
||||
var sep, lastsep;
|
||||
@ -784,8 +803,9 @@ export class BASICParser {
|
||||
stmt__IF(): IF_Statement {
|
||||
var cond = this.parseExpr();
|
||||
var iftrue: Statement[];
|
||||
// we accept GOTO or THEN if line number provided
|
||||
var thengoto = this.expectTokens(['THEN','GOTO']);
|
||||
// we accept GOTO or THEN if line number provided (DEC accepts GO TO)
|
||||
var thengoto = this.expectTokens(['THEN','GOTO','GO']);
|
||||
if (thengoto.str == 'GO') this.expectToken('TO');
|
||||
var lineno = this.peekToken();
|
||||
// assume GOTO if number given after THEN
|
||||
if (lineno.type == TokenType.Int) {
|
||||
@ -893,7 +913,7 @@ export class BASICParser {
|
||||
stmt__ON() : ONGO_Statement {
|
||||
var expr = this.parseExpr();
|
||||
var gotok = this.consumeToken();
|
||||
var cmd = {GOTO:'ONGOTO', GOSUB:'ONGOSUB'}[gotok.str];
|
||||
var cmd = {GOTO:'ONGOTO', THEN:'ONGOTO', GOSUB:'ONGOSUB'}[gotok.str]; // THEN only for DEC basic?
|
||||
if (!cmd) this.compileError(`There should be a GOTO or GOSUB here.`);
|
||||
var labels = this.parseLabelList();
|
||||
return { command:cmd, expr:expr, labels:labels };
|
||||
@ -920,6 +940,12 @@ export class BASICParser {
|
||||
stmt__RANDOMIZE() : NoArgStatement {
|
||||
return { command:'RANDOMIZE' };
|
||||
}
|
||||
stmt__CHANGE() : CHANGE_Statement {
|
||||
var src = this.parseExpr();
|
||||
this.expectToken('TO');
|
||||
var dest = this.parseLexpr();
|
||||
return { command:'CHANGE', src:src, dest:dest };
|
||||
}
|
||||
// TODO: CHANGE A TO A$ (4th edition, A(0) is len and A(1..) are chars)
|
||||
stmt__OPTION() : OPTION_Statement {
|
||||
var tokname = this.consumeToken();
|
||||
@ -938,18 +964,21 @@ export class BASICParser {
|
||||
}
|
||||
parseOptions(stmt: OPTION_Statement) {
|
||||
var arg = stmt.optargs[0];
|
||||
this.optionCount++;
|
||||
switch (stmt.optname) {
|
||||
case 'BASE':
|
||||
let base = parseInt(arg);
|
||||
if (base == 0 || base == 1) this.opts.defaultArrayBase = base;
|
||||
else this.compileError("OPTION BASE can only be 0 or 1.");
|
||||
break;
|
||||
case 'DIALECT':
|
||||
if (this.optionCount > 1)
|
||||
this.compileError(`OPTION DIALECT must be the first OPTION statement in the file.`);
|
||||
let dname = arg || "";
|
||||
let dialect = DIALECTS[dname.toUpperCase()];
|
||||
if (dialect) this.opts = dialect;
|
||||
else this.compileError(`OPTION DIALECT ${dname} is not supported by this compiler.`);
|
||||
break;
|
||||
case 'BASE':
|
||||
let base = parseInt(arg);
|
||||
if (base == 0 || base == 1) this.opts.defaultArrayBase = base;
|
||||
else this.compileError("OPTION BASE can only be 0 or 1.");
|
||||
break;
|
||||
case 'CPUSPEED':
|
||||
if (!(this.opts.commandsPerSec = Math.min(1e7, arg=='MAX' ? Infinity : parseFloat(arg))))
|
||||
this.compileError(`OPTION CPUSPEED takes a positive number or MAX.`);
|
||||
@ -1051,6 +1080,7 @@ export const ECMA55_MINIMAL : BASICOptions = {
|
||||
squareBrackets : false,
|
||||
arraysContainChars : false,
|
||||
endStmtRequired : true,
|
||||
chainAssignments : false,
|
||||
}
|
||||
|
||||
// TODO: only integers supported
|
||||
@ -1095,13 +1125,14 @@ export const TINY_BASIC : BASICOptions = {
|
||||
squareBrackets : false,
|
||||
arraysContainChars : false,
|
||||
endStmtRequired : false,
|
||||
chainAssignments : false,
|
||||
}
|
||||
|
||||
|
||||
export const HP_TIMESHARED_BASIC : BASICOptions = {
|
||||
dialectName: "HP2000",
|
||||
asciiOnly : true,
|
||||
uppercaseOnly : false,
|
||||
uppercaseOnly : false, // the terminal is usually uppercase
|
||||
optionalLabels : false,
|
||||
optionalWhitespace : false,
|
||||
varNaming : "A1",
|
||||
@ -1145,9 +1176,121 @@ export const HP_TIMESHARED_BASIC : BASICOptions = {
|
||||
squareBrackets : true,
|
||||
arraysContainChars : true,
|
||||
endStmtRequired : true,
|
||||
chainAssignments : true,
|
||||
// TODO: max line number, array index 9999
|
||||
}
|
||||
|
||||
export const DEC_BASIC_11 : BASICOptions = {
|
||||
dialectName: "DEC11",
|
||||
asciiOnly : true,
|
||||
uppercaseOnly : true, // translates all lower to upper
|
||||
optionalLabels : false,
|
||||
optionalWhitespace : false,
|
||||
varNaming : "A1",
|
||||
staticArrays : true,
|
||||
sharedArrayNamespace : false,
|
||||
defaultArrayBase : 0,
|
||||
defaultArraySize : 11,
|
||||
defaultValues : true,
|
||||
stringConcat : true, // can also use &
|
||||
typeConvert : false,
|
||||
maxDimensions : 2,
|
||||
maxDefArgs : 255, // ?
|
||||
maxStringLength : 255,
|
||||
tickComments : false,
|
||||
hexOctalConsts : false,
|
||||
validKeywords : [
|
||||
'OPTION',
|
||||
'DATA','DEF','DIM','END','FOR','STEP','GOSUB','GOTO','GO','TO',
|
||||
'IF','THEN','INPUT','LET','NEXT','ON','PRINT','RANDOMIZE',
|
||||
'READ','REM','RESET','RESTORE','RETURN','STOP',
|
||||
],
|
||||
validFunctions : [
|
||||
'ABS','ATN','COS','EXP','INT','LOG','LOG10','PI','RND','SGN','SIN','SQR','TAB',
|
||||
'ASC','BIN','CHR$','CLK$','DAT$','LEN','OCT','POS','SEG$','STR$','TRM$','VAL',
|
||||
'NFORMAT$', // non-standard, substitute for PRINT USING
|
||||
],
|
||||
validOperators : [
|
||||
'=', '<>', '><', '<', '>', '<=', '>=', '+', '-', '*', '/', '^',
|
||||
],
|
||||
printZoneLength : 14,
|
||||
numericPadding : true,
|
||||
checkOverflow : true, // non-fatal; subst 0 and continue
|
||||
testInitialFor : true,
|
||||
optionalNextVar : false,
|
||||
multipleNextVars : false,
|
||||
bitwiseLogic : false,
|
||||
checkOnGotoIndex : true, // might continue
|
||||
computedGoto : false,
|
||||
restoreWithLabel : false,
|
||||
squareBrackets : false,
|
||||
arraysContainChars : false,
|
||||
endStmtRequired : false,
|
||||
chainAssignments : false,
|
||||
// TODO: max line number 32767
|
||||
// TODO: \ separator, % int vars and constants, 'single' quoted
|
||||
// TODO: can't compare strings and numbers
|
||||
}
|
||||
|
||||
export const DEC_BASIC_PLUS : BASICOptions = {
|
||||
dialectName: "DECPLUS",
|
||||
asciiOnly : true,
|
||||
uppercaseOnly : false,
|
||||
optionalLabels : false,
|
||||
optionalWhitespace : false,
|
||||
varNaming : "A1",
|
||||
staticArrays : true,
|
||||
sharedArrayNamespace : false,
|
||||
defaultArrayBase : 0,
|
||||
defaultArraySize : 11,
|
||||
defaultValues : true,
|
||||
stringConcat : true, // can also use "&"
|
||||
typeConvert : false,
|
||||
maxDimensions : 2,
|
||||
maxDefArgs : 255, // ?
|
||||
maxStringLength : 255,
|
||||
tickComments : true, // actually use "!"
|
||||
hexOctalConsts : false,
|
||||
validKeywords : [
|
||||
'OPTION',
|
||||
'REM','LET','DIM','RANDOM','RANDOMIZE','IF','THEN','ELSE',
|
||||
'FOR','TO','STEP','WHILE','UNTIL','NEXT','DEF','ON','GOTO','GOSUB',
|
||||
'RETURN','CHANGE','READ','DATA','RESTORE','PRINT','USING',
|
||||
'INPUT','LINE','NAME','AS','ERROR','RESUME','CHAIN','STOP','END',
|
||||
'MAT','UNLESS','SLEEP','WAIT',
|
||||
],
|
||||
validFunctions : [
|
||||
'ABS','ATN','COS','EXP','INT','LOG','LOG10','PI','RND','SGN','SIN','SQR','TAB','TAN',
|
||||
'POS','TAB','ASCII','CHR$','CVT%$','CVTF$','CVT$%','CVT$F',
|
||||
'LEFT$','RIGHT$','MID$','LEN','INSTR','SPACE$','NUM$','VAL','XLATE',
|
||||
'DATE$','TIME$','TIME','ERR','ERL','SWAP%','RAD$',
|
||||
'NFORMAT$', // non-standard, substitute for PRINT USING
|
||||
],
|
||||
validOperators : [
|
||||
'=', '<>', '<', '>', '<=', '>=', '+', '-', '*', '/', '^',
|
||||
'**', '==',
|
||||
'NOT', 'AND', 'OR', 'XOR', 'IMP', 'EQV',
|
||||
],
|
||||
printZoneLength : 14,
|
||||
numericPadding : true,
|
||||
checkOverflow : true, // non-fatal; subst 0 and continue
|
||||
testInitialFor : true,
|
||||
optionalNextVar : false,
|
||||
multipleNextVars : false,
|
||||
bitwiseLogic : false,
|
||||
checkOnGotoIndex : true, // might continue
|
||||
computedGoto : false,
|
||||
restoreWithLabel : false,
|
||||
squareBrackets : false,
|
||||
arraysContainChars : false,
|
||||
endStmtRequired : false,
|
||||
chainAssignments : false, // TODO: can chain with "," not "="
|
||||
// TODO: max line number 32767
|
||||
// TODO: \ separator, % int vars and constants, 'single' quoted
|
||||
// TODO: can't compare strings and numbers
|
||||
// TODO: WHILE/UNTIL/FOR extra statements, etc
|
||||
}
|
||||
|
||||
export const BASICODE : BASICOptions = {
|
||||
dialectName: "BASICODE",
|
||||
asciiOnly : true,
|
||||
@ -1193,6 +1336,7 @@ export const BASICODE : BASICOptions = {
|
||||
squareBrackets : false,
|
||||
arraysContainChars : false,
|
||||
endStmtRequired : false,
|
||||
chainAssignments : false,
|
||||
}
|
||||
|
||||
export const ALTAIR_BASIC41 : BASICOptions = {
|
||||
@ -1248,6 +1392,7 @@ export const ALTAIR_BASIC41 : BASICOptions = {
|
||||
squareBrackets : false,
|
||||
arraysContainChars : false,
|
||||
endStmtRequired : false,
|
||||
chainAssignments : false,
|
||||
}
|
||||
|
||||
export const APPLESOFT_BASIC : BASICOptions = {
|
||||
@ -1304,6 +1449,7 @@ export const APPLESOFT_BASIC : BASICOptions = {
|
||||
squareBrackets : false,
|
||||
arraysContainChars : false,
|
||||
endStmtRequired : false,
|
||||
chainAssignments : false,
|
||||
}
|
||||
|
||||
export const BASIC80 : BASICOptions = {
|
||||
@ -1361,6 +1507,7 @@ export const BASIC80 : BASICOptions = {
|
||||
squareBrackets : false,
|
||||
arraysContainChars : false,
|
||||
endStmtRequired : false,
|
||||
chainAssignments : false,
|
||||
}
|
||||
|
||||
export const MODERN_BASIC : BASICOptions = {
|
||||
@ -1398,16 +1545,21 @@ export const MODERN_BASIC : BASICOptions = {
|
||||
squareBrackets : true,
|
||||
arraysContainChars : false,
|
||||
endStmtRequired : false,
|
||||
chainAssignments : false,
|
||||
}
|
||||
|
||||
// TODO: integer vars
|
||||
// TODO: DEFINT/DEFSTR
|
||||
// TODO: superfluous ":" ignored on MS basics only?
|
||||
// TODO: excess INPUT ignored, error msg
|
||||
// TODO: max line len?
|
||||
|
||||
export const DIALECTS = {
|
||||
"DEFAULT": ALTAIR_BASIC41,
|
||||
"ALTAIR": ALTAIR_BASIC41,
|
||||
"ALTAIR4": ALTAIR_BASIC41,
|
||||
"ALTAIR41": ALTAIR_BASIC41,
|
||||
"TINY": TINY_BASIC,
|
||||
"ECMA55": ECMA55_MINIMAL,
|
||||
"MINIMAL": ECMA55_MINIMAL,
|
||||
"HP": HP_TIMESHARED_BASIC,
|
||||
@ -1416,9 +1568,12 @@ export const DIALECTS = {
|
||||
"HP2000": HP_TIMESHARED_BASIC,
|
||||
"HPBASIC": HP_TIMESHARED_BASIC,
|
||||
"HPACCESS": HP_TIMESHARED_BASIC,
|
||||
"DEC11": DEC_BASIC_11,
|
||||
"DEC": DEC_BASIC_PLUS,
|
||||
"DECPLUS": DEC_BASIC_PLUS,
|
||||
"BASICPLUS": DEC_BASIC_PLUS,
|
||||
"BASICODE": BASICODE,
|
||||
"APPLESOFT": APPLESOFT_BASIC,
|
||||
"BASIC80": BASIC80,
|
||||
"MODERN": MODERN_BASIC,
|
||||
"TINY": TINY_BASIC,
|
||||
};
|
||||
|
@ -6,10 +6,11 @@ import { lpad, rpad } from "../util";
|
||||
function dumpDialectInfo() {
|
||||
var dialects = new Set<BASICOptions>();
|
||||
var array = {};
|
||||
var SELECTED_DIALECTS = ['TINY','ECMA55','HP','ALTAIR41','BASIC80','MODERN'];
|
||||
var SELECTED_DIALECTS = ['TINY','ECMA55','HP','DEC','ALTAIR','BASIC80','MODERN'];
|
||||
SELECTED_DIALECTS.forEach((dkey) => {
|
||||
dialects.add(DIALECTS[dkey]);
|
||||
});
|
||||
var ALL_KEYWORDS = new Set<string>();
|
||||
dialects.forEach((dialect) => {
|
||||
Object.entries(dialect).forEach(([key, value]) => {
|
||||
if (value === null) value = "all";
|
||||
@ -19,6 +20,16 @@ function dumpDialectInfo() {
|
||||
value = value.length;
|
||||
if (!array[key]) array[key] = [];
|
||||
array[key].push(value);
|
||||
if (dialect.validKeywords) dialect.validKeywords.map(ALL_KEYWORDS.add.bind(ALL_KEYWORDS));
|
||||
});
|
||||
});
|
||||
dialects.forEach((dialect) => {
|
||||
ALL_KEYWORDS.forEach((keyword) => {
|
||||
if (parser.supportsKeyword(keyword)) {
|
||||
var has = dialect.validKeywords == null || dialect.validKeywords.indexOf(keyword) >= 0;
|
||||
if (!array[keyword]) array[keyword] = [];
|
||||
array[keyword].push(has ? "Y" : "-");
|
||||
}
|
||||
});
|
||||
});
|
||||
Object.entries(array).forEach(([key, arr]) => {
|
||||
|
@ -72,7 +72,7 @@ export class BASICRuntime {
|
||||
allstmts : basic.Statement[];
|
||||
line2pc : number[];
|
||||
pc2line : Map<number,number>;
|
||||
label2lineidx : {[label : string] : number};
|
||||
pc2label : Map<number,string>;
|
||||
label2pc : {[label : string] : number};
|
||||
label2dataptr : {[label : string] : number};
|
||||
datums : basic.Literal[];
|
||||
@ -96,25 +96,39 @@ export class BASICRuntime {
|
||||
exited : boolean = true;
|
||||
trace : boolean = false;
|
||||
|
||||
load(program: basic.BASICProgram) {
|
||||
let prevlabel = this.label2pc && this.getLabelForPC(this.curpc);
|
||||
load(program: basic.BASICProgram) : boolean {
|
||||
// get previous label and offset for hot reload
|
||||
let prevlabel = null;
|
||||
let prevpcofs = 0;
|
||||
if (this.pc2label != null) {
|
||||
var pc = this.curpc;
|
||||
while (pc > 0 && (prevlabel = this.pc2label.get(pc)) == null) {
|
||||
pc--;
|
||||
}
|
||||
prevpcofs = this.curpc - pc;
|
||||
console.log('oldpc=', this.curpc, 'restart @ label', prevlabel, '+', prevpcofs);
|
||||
}
|
||||
// initialize program
|
||||
this.program = program;
|
||||
this.opts = program.opts;
|
||||
this.label2lineidx = {};
|
||||
this.label2pc = {};
|
||||
this.label2dataptr = {};
|
||||
this.allstmts = [];
|
||||
this.line2pc = [];
|
||||
this.pc2line = new Map();
|
||||
this.pc2label = new Map();
|
||||
this.datums = [];
|
||||
this.builtins = this.getBuiltinFunctions();
|
||||
// TODO: detect undeclared vars
|
||||
program.lines.forEach((line, idx) => {
|
||||
// make lookup tables
|
||||
if (line.label != null) this.label2lineidx[line.label] = idx;
|
||||
if (line.label != null) this.label2pc[line.label] = this.allstmts.length;
|
||||
this.line2pc.push(this.allstmts.length);
|
||||
this.pc2line.set(this.allstmts.length, idx);
|
||||
var pc = this.allstmts.length;
|
||||
if (line.label != null) {
|
||||
this.label2pc[line.label] = pc;
|
||||
this.pc2label.set(pc, line.label);
|
||||
}
|
||||
this.line2pc.push(pc);
|
||||
this.pc2line.set(pc, idx);
|
||||
// combine all statements into single list
|
||||
line.stmts.forEach((stmt) => this.allstmts.push(stmt));
|
||||
});
|
||||
@ -132,8 +146,13 @@ export class BASICRuntime {
|
||||
});
|
||||
});
|
||||
// try to resume where we left off after loading
|
||||
this.dataptr = Math.min(this.dataptr, this.datums.length);
|
||||
this.curpc = this.label2pc[prevlabel] || 0;
|
||||
if (this.label2pc[prevlabel] != null) {
|
||||
this.curpc = this.label2pc[prevlabel] + prevpcofs;
|
||||
return true;
|
||||
} else {
|
||||
this.curpc = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
reset() {
|
||||
@ -438,10 +457,9 @@ export class BASICRuntime {
|
||||
}
|
||||
}
|
||||
|
||||
assign2js(expr: basic.IndOp, opts?: ExprOptions) {
|
||||
assign2js(expr: basic.IndOp, opts?: ExprOptions) : string {
|
||||
if (!opts) opts = {};
|
||||
var s = '';
|
||||
var qname = JSON.stringify(expr.name);
|
||||
// is it a function? not allowed
|
||||
if (expr.name.startsWith("FN") || this.builtins[expr.name]) this.runtimeError(`I can't call a function here.`);
|
||||
// is it a subscript?
|
||||
@ -450,9 +468,7 @@ export class BASICRuntime {
|
||||
if (this.opts.arraysContainChars && expr.name.endsWith('$')) {
|
||||
this.runtimeError(`I can't set array slices via this command yet.`);
|
||||
} else {
|
||||
s += this.expr2js(expr, {novalid:true}); // check array bounds
|
||||
s += `;this.getArray(${qname}, ${expr.args.length})`;
|
||||
s += expr.args.map((arg) => '[this.ROUND('+this.expr2js(arg, opts)+')]').join('');
|
||||
s += this.array2js(expr, opts);
|
||||
}
|
||||
} else { // just a variable
|
||||
s = `this.vars.${expr.name}`;
|
||||
@ -460,6 +476,14 @@ export class BASICRuntime {
|
||||
return s;
|
||||
}
|
||||
|
||||
array2js(expr: basic.IndOp, opts?: ExprOptions) : string {
|
||||
var qname = JSON.stringify(expr.name);
|
||||
var args = expr.args || [];
|
||||
return this.expr2js(expr, {novalid:true}) // check array bounds
|
||||
+ `;this.getArray(${qname}, ${args.length})`
|
||||
+ args.map((arg) => '[this.ROUND('+this.expr2js(arg, opts)+')]').join('');
|
||||
}
|
||||
|
||||
checkFuncArgs(expr: basic.IndOp, fn: Function) {
|
||||
// TODO: check types?
|
||||
var nargs = expr.args ? expr.args.length : 0;
|
||||
@ -472,7 +496,9 @@ export class BASICRuntime {
|
||||
}
|
||||
|
||||
startForLoop(forname, init, targ, step) {
|
||||
var pc = this.curpc;
|
||||
// save start PC and label in case of hot reload (only works if FOR is first stmt in line)
|
||||
var looppc = this.curpc - 1;
|
||||
var looplabel = this.pc2label.get(looppc);
|
||||
if (!step) step = 1;
|
||||
this.vars[forname] = init;
|
||||
if (this.trace) console.log(`FOR ${forname} = ${init} TO ${targ} STEP ${step}`);
|
||||
@ -499,7 +525,8 @@ export class BASICRuntime {
|
||||
this.forLoopStack.pop();
|
||||
delete this.forLoops[forname];
|
||||
} else {
|
||||
this.curpc = pc; // go back to FOR location
|
||||
// go back to FOR loop, adjusting for hot reload (fetch pc by label)
|
||||
this.curpc = ((looplabel != null && this.label2pc[looplabel]) || looppc) + 1;
|
||||
}
|
||||
if (this.trace) console.log(`NEXT ${forname}: ${this.vars[forname]} TO ${targ} STEP ${step} DONE=${done}`);
|
||||
}
|
||||
@ -661,6 +688,17 @@ export class BASICRuntime {
|
||||
return s;
|
||||
}
|
||||
|
||||
preInput() {
|
||||
this.running=false;
|
||||
this.curpc--;
|
||||
}
|
||||
|
||||
postInput(valid : boolean) {
|
||||
if (valid) this.curpc++;
|
||||
this.running = true;
|
||||
this.resume();
|
||||
}
|
||||
|
||||
do__INPUT(stmt : basic.INPUT_Statement) {
|
||||
var prompt = this.expr2js(stmt.prompt);
|
||||
var setvals = '';
|
||||
@ -672,29 +710,30 @@ export class BASICRuntime {
|
||||
${lexpr} = value;
|
||||
`
|
||||
});
|
||||
return `this.running=false; this.curpc--;
|
||||
return `this.preInput();
|
||||
this.input(${prompt}, ${stmt.args.length}).then((vals) => {
|
||||
let valid = 1;
|
||||
${setvals}
|
||||
if (valid) this.curpc++;
|
||||
this.running=true;
|
||||
this.resume();
|
||||
this.postInput(valid);
|
||||
this.column = 0; // assume linefeed
|
||||
})`;
|
||||
}
|
||||
|
||||
do__LET(stmt : basic.LET_Statement) {
|
||||
var right = this.expr2js(stmt.right);
|
||||
// HP BASIC string-slice syntax?
|
||||
if (this.opts.arraysContainChars && stmt.lexpr.args && stmt.lexpr.name.endsWith('$')) {
|
||||
var s = `this.vars.${stmt.lexpr.name} = this.modifyStringSlice(this.vars.${stmt.lexpr.name}, ${right}, `
|
||||
s += stmt.lexpr.args.map((arg) => this.expr2js(arg)).join(', ');
|
||||
s += ')';
|
||||
console.log(s);
|
||||
return s;
|
||||
} else {
|
||||
var lexpr = this.assign2js(stmt.lexpr);
|
||||
return `${lexpr} = this.assign(${JSON.stringify(stmt.lexpr.name)}, ${right});`;
|
||||
var s = `let _right = ${right};`;
|
||||
for (var lexpr of stmt.lexprs) {
|
||||
// HP BASIC string-slice syntax?
|
||||
if (this.opts.arraysContainChars && lexpr.args && lexpr.name.endsWith('$')) {
|
||||
s += `this.vars.${lexpr.name} = this.modifyStringSlice(this.vars.${lexpr.name}, _right, `
|
||||
s += lexpr.args.map((arg) => this.expr2js(arg)).join(', ');
|
||||
s += ')';
|
||||
} else {
|
||||
var ljs = this.assign2js(lexpr);
|
||||
s += `${ljs} = this.assign(${JSON.stringify(lexpr.name)}, _right);`;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
do__FOR(stmt : basic.FOR_Statement) {
|
||||
@ -826,11 +865,10 @@ export class BASICRuntime {
|
||||
do__GET(stmt : basic.GET_Statement) {
|
||||
var lexpr = this.assign2js(stmt.lexpr);
|
||||
// TODO: single key input
|
||||
return `this.running=false; this.curpc--;
|
||||
return `this.preInput();
|
||||
this.input().then((vals) => {
|
||||
${lexpr} = this.convert(${JSON.stringify(stmt.lexpr.name)}, vals[0]);
|
||||
this.running=true; this.curpc++;
|
||||
this.resume();
|
||||
this.postInput(true);
|
||||
})`;
|
||||
}
|
||||
|
||||
@ -842,6 +880,33 @@ export class BASICRuntime {
|
||||
return `this.rng.randomize()`;
|
||||
}
|
||||
|
||||
do__CHANGE(stmt : basic.CHANGE_Statement) {
|
||||
var arr2str = stmt.dest.name.endsWith('$');
|
||||
if (arr2str) { // array -> string
|
||||
let arrname = (stmt.src as basic.IndOp).name || this.runtimeError("I can only change to a string from an array.");
|
||||
let dest = this.assign2js(stmt.dest);
|
||||
return `
|
||||
let arrname = ${JSON.stringify(arrname)};
|
||||
let len = this.arrayGet(arrname, 0);
|
||||
let s = '';
|
||||
for (let i=0; i<len; i++) {
|
||||
s += String.fromCharCode(this.arrayGet(arrname, i+1));
|
||||
}
|
||||
${dest} = s;
|
||||
`;
|
||||
} else { // string -> array
|
||||
let src = this.expr2js(stmt.src);
|
||||
let dest = this.array2js(stmt.dest);
|
||||
return `
|
||||
let src = ${src}+"";
|
||||
${dest}[0] = src.length;
|
||||
for (let i=0; i<src.length; i++) {
|
||||
${dest}[i+1] = src.charCodeAt(i);
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: ONERR, ON ERROR GOTO
|
||||
// TODO: gosubs nested too deeply
|
||||
// TODO: memory quota
|
||||
@ -1015,9 +1080,9 @@ export class BASICRuntime {
|
||||
}
|
||||
INSTR(a, b, c) : number {
|
||||
if (c != null) {
|
||||
return this.checkString(c).indexOf(this.checkString(b), a) + 1;
|
||||
return this.checkString(b).indexOf(this.checkString(c), this.checkNum(a) - 1) + 1;
|
||||
} else {
|
||||
return this.checkString(b).indexOf(this.checkString(a)) + 1;
|
||||
return this.checkString(a).indexOf(this.checkString(b)) + 1;
|
||||
}
|
||||
}
|
||||
INT(arg : number) : number {
|
||||
@ -1037,6 +1102,11 @@ export class BASICRuntime {
|
||||
if (arg < 0) this.runtimeError(`I can't take the logarithm of a negative number (${arg}).`)
|
||||
return this.checkNum(Math.log(arg));
|
||||
}
|
||||
LOG10(arg : number) : number {
|
||||
if (arg == 0) this.runtimeError(`I can't take the logarithm of zero (${arg}).`)
|
||||
if (arg < 0) this.runtimeError(`I can't take the logarithm of a negative number (${arg}).`)
|
||||
return this.checkNum(Math.log10(arg));
|
||||
}
|
||||
MID$(arg : string, start : number, count : number) : string {
|
||||
if (start < 1) this.runtimeError(`I can't compute MID$ if the starting index is less than 1.`)
|
||||
if (count == 0) count = arg.length;
|
||||
@ -1045,6 +1115,10 @@ export class BASICRuntime {
|
||||
OCT$(arg : number) : string {
|
||||
return this.ROUND(arg).toString(8);
|
||||
}
|
||||
PI() : number {
|
||||
return Math.PI;
|
||||
}
|
||||
// TODO: POS(haystack, needle, start)
|
||||
POS(arg : number) : number { // arg ignored
|
||||
return this.column + 1;
|
||||
}
|
||||
@ -1130,6 +1204,7 @@ export class BASICRuntime {
|
||||
return arg;
|
||||
}
|
||||
NFORMAT$(arg : number, numlen : number) : string {
|
||||
return this.LPAD$(this.float2str(arg, numlen), numlen);
|
||||
var s = this.float2str(arg, numlen);
|
||||
return (numlen > 0) ? this.LPAD$(s, numlen) : this.RPAD$(s, -numlen);
|
||||
}
|
||||
}
|
||||
|
@ -10,10 +10,14 @@ import { TeleTypeWithKeyboard } from "../common/teletype";
|
||||
const BASIC_PRESETS = [
|
||||
{ id: 'hello.bas', name: 'Hello World' },
|
||||
{ id: 'sieve.bas', name: 'Sieve Benchmark' },
|
||||
{ id: 'mortgage.bas', name: 'Interest Calculator' },
|
||||
{ id: '23match.bas', name: '23 Matches' },
|
||||
{ id: 'wumpus.bas', name: 'Hunt The Wumpus' },
|
||||
{ id: 'craps.bas', name: 'Craps' },
|
||||
{ id: 'lander.bas', name: 'Lander' },
|
||||
{ id: 'hamurabi.bas', name: 'Hammurabi' },
|
||||
{ id: 'wumpus.bas', name: 'Hunt The Wumpus' },
|
||||
{ id: 'startrader.bas', name: 'Star Trader' },
|
||||
{ id: 'haunted.bas', name: 'Haunted House' },
|
||||
];
|
||||
|
||||
class BASICPlatform implements Platform {
|
||||
@ -123,7 +127,10 @@ class BASICPlatform implements Platform {
|
||||
this.program = data;
|
||||
this.runtime.load(data);
|
||||
this.tty.uppercaseOnly = true; // this.program.opts.uppercaseOnly; //TODO?
|
||||
// map editor to uppercase-only if need be
|
||||
views.textMapFunctions.input = this.program.opts.uppercaseOnly ? (s) => s.toUpperCase() : null;
|
||||
// HP 2000 has cute lil small caps (TODO: messes up grid alignment tho)
|
||||
//this.tty.page.style.fontVariant = (this.program.opts.dialectName == 'HP2000') ? 'small-caps' : 'normal';
|
||||
// only reset if we exited, or couldn't restart at label (PC reset to 0)
|
||||
if (!this.hotReload || didExit || this.runtime.curpc == 0)
|
||||
this.reset();
|
||||
|
Loading…
x
Reference in New Issue
Block a user