basic: out of order loops, convert editor to uppercase when dialect says so, OPTION CPUSPEED

This commit is contained in:
Steven Hugg 2020-08-09 22:19:27 -05:00
parent 52a1107114
commit cf39cd4f58
9 changed files with 449 additions and 12 deletions

42
presets/basic/23match.bas Normal file
View File

@ -0,0 +1,42 @@
100 REM***23 MATCHES
110 LET M=23
115 PRINT
120 PRINT "WE START WITH 23 MATCHES. WHEN IT IS YOUR"
130 PRINT "TURN, YOU MAY TAKE 1, 2, OR 3 MATCHES. THE"
140 PRINT "ONE WHO MUST TAKE THE LAST MATCH LOSES."
150 PRINT
200 REM***THE HUMAN MOVES
205 PRINT
210 PRINT "THERE ARE NOW";M;"MATCHES."
215 PRINT
220 PRINT "HOW MANY MATCHES DO YOU TAKE";
230 INPUT H
240 IF H>M THEN 260
250 IF H=INT(H) THEN 252
251 GOTO 260
252 IF H>0 THEN 254
253 GOTO 260
254 IF H<4 THEN 280
260 PRINT "YOU CHEATED! I'LL GIVE YOU ANOTHER CHANCE."
270 GOTO 215
280 LET M=M-H
290 IF M=0 THEN 410
300 REM***THE COMPUTER MOVES
310 LET R=M-4*INT(M/4)
320 IF R<>1 THEN 350
330 LET C=INT(3*RND(0))+1
340 GOTO 360
350 LET C=(R+3)-4*INT((R+3)/4)
360 LET M=M-C
370 IF M=0 THEN 440
375 PRINT
380 PRINT "I TOOK";C;"MATCHES."
390 GOTO 200
400 REM***SOMEBODY ONE(SEE LINES 290 AND 370)
410 PRINT
420 PRINT "I WON!!! BETTER LUCK NEXT TIME."
430 GOTO 100
440 PRINT
450 PRINT "O.K. SO YOU WON. LET'S PLAY AGAIN."
460 GOTO 100
999 END

121
presets/basic/hamurabi.bas Normal file
View File

@ -0,0 +1,121 @@
10 REM *** CONVERTED FROM THE ORIGINAL FOCAL PROGRAM AND MODIFIED
20 REM *** FOR EDUSYSTEM 70 BY DAVID AHL, DIGITAL
30 REM *** MODIFIED FOR 8K MICROSOFT BASIC BY PETER TURNBULL
80 PRINT "TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA"
85 PRINT "SUCCESSFULLY FOR A 10-YR TERM OF OFFICE.":PRINT
90 REM RANDOMIZE REMOVED
95 D1=0:P1=0
110 Z=0:P=95:S=2800:H=3000:E=H-S
120 Y=3:A=H/Y:I=5:Q=1
210 D=0
215 PRINT:PRINT:PRINT "HAMURABI: I BEG TO REPORT TO YOU,":Z=Z+1
217 PRINT "IN YEAR"Z","D"PEOPLE STARVED,"I"CAME TO THE CITY."
218 P=P+I
227 IF Q>0 THEN 230
228 P=INT(P/2)
229 PRINT "A HORRIBLE PLAGUE STRUCK! HALF THE PEOPLE DIED."
230 PRINT "POPULATION IS NOW"P
232 PRINT "THE CITY NOW OWNS"A"ACRES."
235 PRINT "YOU HARVESTED"Y"BUSHELS PER ACRE."
250 PRINT "RATS ATE"E"BUSHELS."
260 PRINT "YOU NOW HAVE"S"BUSHELS IN STORE.":PRINT
270 IF Z=11 THEN 860
310 C=INT(10*RND(1)):Y=C+17
312 PRINT "LAND IS TRADING AT"Y"BUSHELS PER ACRE."
320 PRINT "HOW MANY ACRES DO YOU WISH TO BUY";
321 INPUT Q:IF Q<0 THEN 850
322 IF Y*Q<=S THEN 330
323 GOSUB 710
324 GOTO 320
330 IF Q=0 THEN 340
331 A=A+Q:S=S-Y*Q:C=0
334 GOTO 400
340 PRINT "HOW MANY ACRES DO YOU WISH TO SELL";
341 INPUT Q:IF Q<0 THEN 850
342 IF Q<A THEN 350
343 GOSUB 720
344 GOTO 340
350 A=A-Q:S=S+Y*Q:C=0
400 PRINT
410 PRINT "HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE";
411 INPUT Q
412 IF Q<0 THEN 850
418 REM *** TRYING TO USE MORE GRAIN THAN IN THE SILOS?
420 IF Q<=S THEN 430
421 GOSUB 710
422 GOTO 410
430 S=S-Q:C=1:PRINT
440 PRINT "HOW MANY ACRES DO YOU WISH TO PLANT WITH SEED";
441 INPUT D:IF D=0 THEN 511
442 IF D<0 THEN 850
444 REM *** TRYING TO PLANT MORE ACRES THAN YOU OWN?
445 IF D<=A THEN 450
446 GOSUB 720
447 GOTO 440
449 REM *** ENOUGH GRAIN FOR SEED?
450 IF INT(D/2)<S THEN 455
452 GOSUB 710
453 GOTO 440
454 REM *** ENOUGH PEOPLE TO TEND THE CROPS?
455 IF D<10*P THEN 510
460 PRINT "BUT YOU HAVE ONLY"P"PEOPLE TO TEND THE FIELDS. NOW THEN,"
470 GOTO 440
510 S=S-INT(D/2)
511 GOSUB 800
512 REM *** A BOUNTYFULL HARVEST!!
515 Y=C:H=D*Y:E=0
521 GOSUB 800
522 IF INT(C/2)<>C/2 THEN 530
523 REM *** THE RATS ARE RUNNING WILD!!
525 E=INT(S/C)
530 S=S-E+H
531 GOSUB 800
532 REM *** LET'S HAVE SOME BABIES
533 I=INT(C*(20*A+S)/P/100+1)
539 REM *** HOW MANY PEOPLE HAD FULL TUMMIES?
540 C=INT(Q/20)
541 REM *** HORRORS, A 15% CHANCE OF PLAGUE
542 Q=INT(10*(2*RND(1)-.3))
550 IF P<C THEN 210
551 REM *** STARVE ENOUGH FOR IMPEACHMENT?
552 D=P-C:IF D>.45*P THEN 560
553 P1=((Z-1)*P1+D*100/P)/Z
555 P=C:D1=D1+D:GOTO 215
560 PRINT:PRINT "YOU STARVED"D"PEOPLE IN ONE YEAR!!!"
565 PRINT "DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY"
566 PRINT "BEEN IMPEACHED AND THROWN OUT OF OFFICE BUT YOU HAVE"
567 PRINT "ALSO BEEN DECLARED 'NATIONAL FINK' !!":GOTO 990
710 PRINT "HAMURABI: THINK AGAIN. YOU HAVE ONLY"
711 PRINT S"BUSHELS OF GRAIN. NOW THEN,"
712 RETURN
720 PRINT "HAMURABI: THINK AGAIN. YOU OWN ONLY"A"ACRES. NOW THEN,"
730 RETURN
800 C=INT(RND(1)*5)+1
801 RETURN
850 PRINT:PRINT "HAMURABI: I CANNOT DO WHAT YOU WISH."
855 PRINT "GET YOURSELF ANOTHER STEWARD!!!!!"
857 GOTO 990
860 PRINT "IN YOUR 10-YEAR TERM OF OFFICE,"P1"PERCENT OF THE"
862 PRINT "POPULATION STARVED PER YEAR ON AVERAGE, I.E., A TOTAL OF"
865 PRINT D1"PEOPLE DIED!!":L=A/P
870 PRINT "YOU STARTED WITH 10 ACRES PER PERSON AND ENDED WITH"
875 PRINT L"ACRES PER PERSON.":PRINT
880 IF P1>33 THEN 565
885 IF L<7 THEN 565
890 IF P1>10 THEN 940
892 IF L<9 THEN 940
895 IF P1>3 THEN 960
896 IF L<10 THEN 960
900 PRINT "A FANTASTIC PERFORMANCE!!! CHARLEMANGE, DISRAELI, AND"
905 PRINT "JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!":GOTO 990
940 PRINT "YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVAN IV."
945 PRINT "THE PEOPLE (REMAINING) FIND YOU AN UNPLEASANT RULER, AND,"
950 PRINT "FRANKLY, HATE YOUR GUTS!":GOTO 990
960 PRINT "YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT"
965 PRINT "REALLY WASN'T TOO BAD AT ALL. ";
966 PRINT INT(P*.8*RND(1));"PEOPLE WOULD"
970 PRINT "DEARLY LIKE TO SEE YOU ASSASSINATED BUT WE ALL HAVE OUR"
975 PRINT "TRIVIAL PROBLEMS."
990 PRINT:FOR N=1 TO 10:PRINT CHR$(7);:NEXT N
995 PRINT "SO LONG FOR NOW.":PRINT
999 END

16
presets/basic/sieve.bas Normal file
View File

@ -0,0 +1,16 @@
005 OPTION CPUSPEED MAX
010 REM***A PRIME NUMBER SIEVE BENCHMARK
020 T = TIMER
025 N = 8191
030 DIM F(N+3)
040 FOR I = 0 TO N : F(I) = 1 : NEXT I
050 S = N
060 FOR I = 0 TO S
070 IF F(I) = 0 THEN GOTO 110
080 P = I+I+3
090 FOR K = I+P TO S STEP P : F(K) = 0 : NEXT K
100 C = C+1
110 NEXT I
120 T = TIMER-T
130 PRINT C;" PRIMES FOUND IN ";T;" SECONDS"
150 END

221
presets/basic/wumpus.bas Normal file
View File

@ -0,0 +1,221 @@
5 REM *** HUNT THE WUMPUS ***
10 DIM P(5)
15 PRINT "INSTRUCTIONS (Y-N)";
20 INPUT I$
25 IF (I$ = "N") OR (I$ = "N") THEN 35
30 GOSUB 375
35 GOTO 80
80 REM *** SET UP CAVE (DODECAHEDRAL NODE LIST) ***
85 DIM S(20,3)
90 FOR J = 1 TO 20
95 FOR K = 1 TO 3
100 READ S(J,K)
105 NEXT K
110 NEXT J
115 DATA 2,5,8,1,3,10,2,4,12,3,5,14,1,4,6
120 DATA 5,7,15,6,8,17,1,7,9,8,10,18,2,9,11
125 DATA 10,12,19,3,11,13,12,14,20,4,13,15,6,14,16
130 DATA 15,17,20,7,16,18,9,17,19,11,18,20,13,16,19
135 DEF FNA(X)=INT(20*RND(1))+1
140 DEF FNB(X)=INT(3*RND(1))+1
145 DEF FNC(X)=INT(4*RND(1))+1
150 REM *** LOCATE L ARRAY ITEMS ***
155 REM *** 1-YOU, 2-WUMPUS, 3&4-PITS, 5&6-BATS ***
160 DIM L(6)
165 DIM M(6)
170 FOR J = 1 TO 6
175 L(J) = FNA(0)
180 M(J) = L(J)
185 NEXT J
190 REM *** CHECK FOR CROSSOVERS (IE L(1)=L(2), ETC) ***
195 FOR J = 1 TO 6
200 FOR K = 1 TO 6
205 IF J = K THEN 215
210 IF L(J) = L(K) THEN 170
215 NEXT K
220 NEXT J
225 REM *** SET NO. OF ARROWS ***
230 A = 5
235 L = L(1)
240 REM *** RUN THE GAME ***
245 PRINT "HUNT THE WUMPUS"
250 REM *** HAZARD WARNING AND LOCATION ***
255 GOSUB 585
260 REM *** MOVE OR SHOOT ***
265 GOSUB 670
270 ON O GOTO 280,300
275 REM *** SHOOT ***
280 GOSUB 715
285 IF F = 0 THEN 255
290 GOTO 310
295 REM *** MOVE ***
300 GOSUB 975
305 IF F = 0 THEN 255
310 IF F > 0 THEN 335
315 REM *** LOSE ***
320 PRINT "HA HA HA - YOU LOSE!"
325 GOTO 340
330 REM *** WIN ***
335 PRINT "HEE HEE HEE - THE WUMPUS'LL GET YOU NEXT TIME!!"
340 FOR J = 1 TO 6
345 L(J) = M(J)
350 NEXT J
355 PRINT "SAME SETUP (Y-N)";
360 INPUT I$
365 IF (I$ <> "Y") AND (I$ <> "Y") THEN 170
370 GOTO 230
375 REM *** INSTRUCTIONS ***
380 PRINT "WELCOME TO 'HUNT THE WUMPUS'"
385 PRINT " THE WUMPUS LIVES IN A CAVE OF 20 ROOMS. EACH ROOM"
390 PRINT "HAS 3 TUNNELS LEADING TO OTHER ROOMS. (LOOK AT A"
395 PRINT "DODECAHEDRON TO SEE HOW THIS WORKS-IF YOU DON'T KNOW"
400 PRINT "WHAT A DODECAHEDRON IS, ASK SOMEONE)"
405 PRINT
410 PRINT " HAZARDS:"
415 PRINT " BOTTOMLESS PITS - TWO ROOMS HAVE BOTTOMLESS PITS IN THEM"
420 PRINT " IF YOU GO THERE, YOU FALL INTO THE PIT (& LOSE!)"
425 PRINT " SUPER BATS - TWO OTHER ROOMS HAVE SUPER BATS. IF YOU"
430 PRINT " GO THERE, A BAT GRABS YOU AND TAKES YOU TO SOME OTHER"
435 PRINT " ROOM AT RANDOM. (WHICH MAY BE TROUBLESOME)"
440 INPUT "HIT RETURN TO CONTINUE";A$
445 PRINT " WUMPUS:"
450 PRINT " THE WUMPUS IS NOT BOTHERED BY HAZARDS (HE HAS SUCKER"
455 PRINT " FEET AND IS TOO BIG FOR A BAT TO LIFT). USUALLY"
460 PRINT " HE IS ASLEEP. TWO THINGS WAKE HIM UP: YOU SHOOTING AN"
465 PRINT "ARROW OR YOU ENTERING HIS ROOM."
470 PRINT " IF THE WUMPUS WAKES HE MOVES (P=.75) ONE ROOM"
475 PRINT " OR STAYS STILL (P=.25). AFTER THAT, IF HE IS WHERE YOU"
480 PRINT " ARE, HE EATS YOU UP AND YOU LOSE!"
485 PRINT
490 PRINT " YOU:"
495 PRINT " EACH TURN YOU MAY MOVE OR SHOOT A CROOKED ARROW"
500 PRINT " MOVING: YOU CAN MOVE ONE ROOM (THRU ONE TUNNEL)"
505 PRINT " ARROWS: YOU HAVE 5 ARROWS. YOU LOSE WHEN YOU RUN OUT"
510 PRINT " EACH ARROW CAN GO FROM 1 TO 5 ROOMS. YOU AIM BY TELLING"
515 PRINT " THE COMPUTER THE ROOM#S YOU WANT THE ARROW TO GO TO."
520 PRINT " IF THE ARROW CAN'T GO THAT WAY (IF NO TUNNEL) IT MOVES"
525 PRINT " AT RANDOM TO THE NEXT ROOM."
530 PRINT " IF THE ARROW HITS THE WUMPUS, YOU WIN."
535 PRINT " IF THE ARROW HITS YOU, YOU LOSE."
540 INPUT "HIT RETURN TO CONTINUE";A$
545 PRINT " WARNINGS:"
550 PRINT " WHEN YOU ARE ONE ROOM AWAY FROM A WUMPUS OR HAZARD,"
555 PRINT " THE COMPUTER SAYS:"
560 PRINT " WUMPUS: 'I SMELL A WUMPUS'"
565 PRINT " BAT : 'BATS NEARBY'"
570 PRINT " PIT : 'I FEEL A DRAFT'"
575 PRINT
580 RETURN
585 REM *** PRINT LOCATION & HAZARD WARNINGS ***
590 PRINT
595 FOR J = 2 TO 6
600 FOR K = 1 TO 3
605 IF S(L(1),K) <> L(J) THEN 640
610 ON J-1 GOTO 615,625,625,635,635
615 PRINT "I SMELL A WUMPUS!"
620 GOTO 640
625 PRINT "I FEEL A DRAFT"
630 GOTO 640
635 PRINT "BATS NEARBY!"
640 NEXT K
645 NEXT J
650 PRINT "YOU ARE IN ROOM ";L(1)
655 PRINT "TUNNELS LEAD TO ";S(L,1);" ";S(L,2);" ";S(L,3)
660 PRINT
665 RETURN
670 REM *** CHOOSE OPTION ***
675 PRINT "SHOOT OR MOVE (S-M)";
680 INPUT I$
685 IF (I$ <> "S") AND (I$ <> "S") THEN 700
690 O = 1
695 RETURN
700 IF (I$ <> "M") AND (I$ <> "M") THEN 675
705 O = 2
710 RETURN
715 REM *** ARROW ROUTINE ***
720 F = 0
725 REM *** PATH OF ARROW ***
735 PRINT "NO. OF ROOMS (1-5)";
740 INPUT J9
745 IF J9 < 1 THEN 735
750 IF J9 > 5 THEN 735
755 FOR K = 1 TO J9
760 PRINT "ROOM #";
765 INPUT P(K)
770 IF K <= 2 THEN 790
775 IF P(K) <> P(K-2) THEN 790
780 PRINT "ARROWS AREN'T THAT CROOKED - TRY ANOTHER ROOM"
785 GOTO 760
790 NEXT K
795 REM *** SHOOT ARROW ***
800 L = L(1)
805 FOR K = 1 TO J9
810 FOR K1 = 1 TO 3
815 IF S(L,K1) = P(K) THEN 895
820 NEXT K1
825 REM *** NO TUNNEL FOR ARROW ***
830 L = S(L,FNB(1))
835 GOTO 900
840 NEXT K
845 PRINT "MISSED"
850 L = L(1)
855 REM *** MOVE WUMPUS ***
860 GOSUB 935
865 REM *** AMMO CHECK ***
870 A = A-1
875 IF A > 0 THEN 885
880 F = -1
885 RETURN
890 REM *** SEE IF ARROW IS AT L(1) OR AT L(2)
895 L = P(K)
900 IF L <> L(2) THEN 920
905 PRINT "AHA! YOU GOT THE WUMPUS!"
910 F = 1
915 RETURN
920 IF L <> L(1) THEN 840
925 PRINT "OUCH! ARROW GOT YOU!"
930 GOTO 880
935 REM *** MOVE WUMPUS ROUTINE ***
940 K = FNC(0)
945 IF K = 4 THEN 955
950 L(2) = S(L(2),K)
955 IF L(2) <> L THEN 970
960 PRINT "TSK TSK TSK - WUMPUS GOT YOU!"
965 F = -1
970 RETURN
975 REM *** MOVE ROUTINE ***
980 F = 0
985 PRINT "WHERE TO";
990 INPUT L
995 IF L < 1 THEN 985
1000 IF L > 20 THEN 985
1005 FOR K = 1 TO 3
1010 REM *** CHECK IF LEGAL MOVE ***
1015 IF S(L(1),K) = L THEN 1045
1020 NEXT K
1025 IF L = L(1) THEN 1045
1030 PRINT "NOT POSSIBLE -";
1035 GOTO 985
1040 REM *** CHECK FOR HAZARDS ***
1045 L(1) = L
1050 REM *** WUMPUS ***
1055 IF L <> L(2) THEN 1090
1060 PRINT "... OOPS! BUMPED A WUMPUS!"
1065 REM *** MOVE WUMPUS ***
1070 GOSUB 940
1075 IF F = 0 THEN 1090
1080 RETURN
1085 REM *** PIT ***
1090 IF L = L(3) THEN 1100
1095 IF L <> L(4) THEN 1120
1100 PRINT "YYYYIIIIEEEE . . . FELL IN PIT"
1105 F = -1
1110 RETURN
1115 REM *** BATS ***
1120 IF L = L(5) THEN 1130
1125 IF L <> L(6) THEN 1145
1130 PRINT "ZAP--SUPER BAT SNATCH! ELSEWHEREVILLE FOR YOU!"
1135 L = FNA(1)
1140 GOTO 1045
1145 RETURN
1150 END

View File

@ -95,7 +95,7 @@ CodeMirror.defineMode("basic", function(conf, parserConf) {
// Octal
else if (stream.match(/^&O[0-7]+/i)) { intLiteral = true; }
// Decimal
else if (stream.match(/^[1-9]\d*F?/)) {
else if (stream.match(/^\d+F?/)) {
// Decimal literals may be "imaginary"
stream.eat(/J/i);
// TODO - Can you have imaginary longs?

View File

@ -240,6 +240,7 @@ export interface BASICOptions {
sparseArrays : boolean; // true == don't require DIM for arrays (TODO)
printZoneLength : number; // print zone length
numericPadding : boolean; // " " or "-" before and " " after numbers?
outOfOrderNext : boolean; // can we skip a NEXT statement? (can't interleave tho)
multipleNextVars : boolean; // NEXT Y,X (TODO)
ifElse : boolean; // IF...ELSE construct
bitwiseLogic : boolean; // -1 = TRUE, 0 = FALSE, AND/OR/NOT done with bitwise ops
@ -249,6 +250,7 @@ export interface BASICOptions {
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)
commandsPerSec? : number; // how many commands per second?
}
///// BASIC PARSER
@ -743,17 +745,22 @@ export class BASICParser {
return stmt;
}
parseOptions(stmt: OPTION_Statement) {
var arg = stmt.optargs[0];
switch (stmt.optname) {
case 'BASE':
let base = parseInt(stmt.optargs[0]);
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':
let dname = stmt.optargs[0] || "";
let dname = arg || "";
let dialect = DIALECTS[dname.toUpperCase()];
if (dialect) this.opts = dialect;
else this.compileError(`The dialect named "${dname}" is not supported by this compiler.`);
else this.compileError(`OPTION DIALECT ${dname} is not supported by this compiler.`);
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.`);
break;
default:
this.compileError(`OPTION ${stmt.optname} is not supported by this compiler.`);
@ -825,6 +832,7 @@ export const ECMA55_MINIMAL : BASICOptions = {
printZoneLength : 15,
numericPadding : true,
checkOverflow : true,
outOfOrderNext : false,
multipleNextVars : false,
ifElse : false,
bitwiseLogic : false,
@ -853,6 +861,7 @@ export const ALTAIR_BASIC40 : BASICOptions = {
printZoneLength : 15,
numericPadding : true,
checkOverflow : true,
outOfOrderNext : true,
multipleNextVars : true, // TODO: not supported
ifElse : true,
bitwiseLogic : true,
@ -883,6 +892,7 @@ export const APPLESOFT_BASIC : BASICOptions = {
printZoneLength : 16,
numericPadding : false,
checkOverflow : true,
outOfOrderNext : true,
multipleNextVars : false,
ifElse : false,
bitwiseLogic : false,
@ -911,6 +921,7 @@ export const MAX8_BASIC : BASICOptions = {
printZoneLength : 15,
numericPadding : false,
checkOverflow : true,
outOfOrderNext : true,
multipleNextVars : true,
ifElse : true,
bitwiseLogic : true,

View File

@ -42,7 +42,7 @@ export class BASICRuntime {
vars : {};
arrays : {};
defs : {};
forLoops : {next:(name:string) => void}[];
forLoops : {varname:string, next:(name:string) => void}[];
returnStack : number[];
column : number;
@ -79,7 +79,7 @@ export class BASICRuntime {
this.datums.push({value:value});
});
});
// TODO: compile statements?
// compile statements ahead of time
line.stmts.forEach((stmt) => this.compileStatement(stmt));
});
// try to resume where we left off after loading
@ -105,7 +105,7 @@ export class BASICRuntime {
// if no valid function list, look for ABC...() functions in prototype
if (!fnames) fnames = Object.keys(BASICRuntime.prototype).filter((name) => /^[A-Z]{3,}[$]?$/.test(name));
var dict = {};
for (var fn of fnames) dict[fn] = this[fn].bind(this);
for (var fn of fnames) if (this[fn]) dict[fn] = this[fn].bind(this);
return dict;
}
@ -341,6 +341,7 @@ export class BASICRuntime {
this.vars[forname] = init;
if (this.trace) console.log(`FOR ${forname} = ${init} TO ${targ} STEP ${step}`);
this.forLoops.unshift({
varname: forname,
next: (nextname:string) => {
if (nextname && forname != nextname)
this.runtimeError(`I executed NEXT "${nextname}", but the last FOR was for "${forname}".`)
@ -358,8 +359,16 @@ export class BASICRuntime {
nextForLoop(name) {
var fl = this.forLoops[0];
if (fl != null && name != null && fl.varname != name) {
if (!this.opts.outOfOrderNext) this.dialectError(`execute out-of-order NEXT statements`);
while (fl) {
if (fl.varname == name) break;
this.forLoops.shift();
fl = this.forLoops[0];
}
}
if (!fl) this.runtimeError(`I couldn't find a FOR for this NEXT.`)
else fl.next(name);
fl.next(name);
}
// converts a variable to string/number based on var name
@ -557,7 +566,7 @@ export class BASICRuntime {
}
do__RESTORE() {
this.dataptr = 0;
return `this.dataptr = 0`;
}
do__END() {
@ -806,6 +815,9 @@ export class BASICRuntime {
TAN(arg : number) : number {
return this.checkNum(Math.tan(arg));
}
TIMER() : number {
return Date.now() / 1000;
}
VAL(arg : string) : number {
var n = parseFloat(this.checkString(arg));
return isNaN(n) ? 0 : n; // TODO? altair works this way

View File

@ -74,6 +74,10 @@ const MODEDEFS = {
basic: { noLineNumbers: true, noGutters: true }, // TODO: not used?
}
export var textMapFunctions = {
input: null
};
export class SourceEditor implements ProjectView {
constructor(path:string, mode:string) {
this.path = path;
@ -150,6 +154,10 @@ export class SourceEditor implements ProjectView {
});
// set editor mode for highlighting, etc
this.editor.setOption("mode", this.mode);
// change text?
this.editor.on('beforeChange', (cm, chgobj) => {
if (textMapFunctions.input && chgobj.text) chgobj.text = chgobj.text.map(textMapFunctions.input);
});
}

View File

@ -2,12 +2,17 @@
import { Platform, BreakpointCallback } from "../common/baseplatform";
import { PLATFORMS, AnimationTimer, EmuHalt } from "../common/emu";
import { loadScript } from "../ide/ui";
import * as views from "../ide/views";
import { BASICRuntime } from "../common/basic/runtime";
import { BASICProgram } from "../common/basic/compiler";
import { TeleTypeWithKeyboard } from "../common/teletype";
const BASIC_PRESETS = [
{ id: 'hello.bas', name: 'Hello World' }
{ id: 'hello.bas', name: 'Hello World' },
{ id: 'sieve.bas', name: 'Sieve Benchmark' },
{ id: '23match.bas', name: '23 Matches' },
{ id: 'wumpus.bas', name: 'Hunt The Wumpus' },
{ id: 'hamurabi.bas', name: 'Hammurabi' },
];
class BASICPlatform implements Platform {
@ -16,7 +21,6 @@ class BASICPlatform implements Platform {
runtime: BASICRuntime;
timer: AnimationTimer;
tty: TeleTypeWithKeyboard;
ips: number = 1000;
clock: number = 0;
hotReload: boolean = false;
debugstop: boolean = false; // TODO: should be higher-level support
@ -75,7 +79,8 @@ class BASICPlatform implements Platform {
animate() {
if (this.tty.isBusy()) return;
this.clock += this.ips/60;
var ips = this.program.opts.commandsPerSec || 1000;
this.clock += ips / 60;
while (!this.runtime.exited && this.clock-- > 0) {
this.advance();
}
@ -112,6 +117,7 @@ class BASICPlatform implements Platform {
this.program = data;
this.runtime.load(data);
this.tty.uppercaseOnly = this.program.opts.uppercaseOnly;
views.textMapFunctions.input = this.program.opts.uppercaseOnly ? (s) => s.toUpperCase() : null;
// only reset if we exited, otherwise we try to resume
if (!this.hotReload || didExit) this.reset();
}