From 74238b334f8765e9113694329f8a7b71b8af8d2d Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Wed, 19 Aug 2020 12:05:30 -0500 Subject: [PATCH] basic: got rid of BASICLine in favor of list of statements, multipleStmtsPerLine --- presets/basic/hello.bas | 107 ++++++++++++++++++++++--- src/common/basic/compiler.ts | 150 +++++++++++++++++++++-------------- src/common/basic/runtime.ts | 37 ++++----- src/platform/basic.ts | 4 +- 4 files changed, 202 insertions(+), 96 deletions(-) diff --git a/presets/basic/hello.bas b/presets/basic/hello.bas index aed21745..9f7f7c5a 100644 --- a/presets/basic/hello.bas +++ b/presets/basic/hello.bas @@ -1,12 +1,99 @@ OPTION DIALECT DARTMOUTH -10 PRINT "HELLO! LET'S PROGRAM IN BASIC." -15 PRINT -20 INPUT "WOULD YOU MIND TYPING IN YOUR NAME";A$ -25 PRINT -30 PRINT "THANKS, ";A$;"! THIS WILL BE FUN!" -35 PRINT -40 INPUT "NOW TELL ME YOUR FAVORITE NUMBER";N -45 PRINT -50 PRINT "THAT'S A GOOD ONE! I LIKE";N^2;"MYSELF." -60 PRINT "NICE MEETING YOU, ";A$;"." +001 REM THIS IS A PROGRAM WRITTEN IN BASIC. +002 REM YOU CAN WRITE ONE STATEMENT PER LINE. +003 REM EACH STATEMENT MUST HAVE A LINE NUMBER. +004 REM THE "REM" LINES ARE COMMENTS, WHICH ARE IGNORED +005 ' YOU CAN ALSO DO COMMENTS WITH APOSTROPHES +006 ' LET'S START WITH A "PRINT"... +100 PRINT "HELLO! LET'S PROGRAM IN BASIC." +101 PRINT ' <-- THIS PRINTS A BLANK LINE, IT LOOKS NICER +105 ' "INPUT" WAITS FOR USER INPUT FROM THE KEYBOARD +106 ' THE NUMBER ENTERED WILL GO INTO THE VARIABLE "N" +110 INPUT "FIRST, TELL ME YOUR FAVORITE NUMBER";N +111 PRINT +115 ' YOU CAN DO CALCULATIONS WITH THE + - / * OPERATORS +116 ' THE ^ IS AN EXPONENT, SO N^2 IS N-SQUARED +119 ' "LET" ASSIGNS THE RESULT TO A VARIABLE +120 LET Z = N^2 +121 ' THE SEMICOLON ";" SEPARATES THINGS TO BE PRINTED +122 PRINT "THAT'S A GOOD ONE! I LIKE";Z;"MYSELF." +123 PRINT +125 ' IF A VARIABLE ENDS IN "$" IT IS A STRING +126 ' AND CONTAINS CHARACTERS INSTEAD OF A NUMBER +127 ' LET'S READ FROM THE KEYBOARD INTO THE A$ VARIABLE +130 INPUT "WOULD YOU MIND TYPING IN YOUR NAME";A$ +131 PRINT +135 ' WE CAN PRINT MULTIPLE THINGS PER LINE +136 ' IN THIS BASIC DIALECT, NUMBERS ARE PRINTED +137 ' WITH SPACES BEFORE AND AFTER +140 PRINT "GOOD TO MEET YOU, ";A$;" WHO LOVES";N;"!" +141 PRINT +150 INPUT "WOULD YOU LIKE TO SEE ME CALCULATE";B$ +151 PRINT +155 ' "IF" CAN TEST A CONDITION +156 ' AND JUMP TO A DIFFERENT LINE IF IT IS TRUE +160 IF B$ = "Y" THEN 180 +161 IF B$ = "YES" THEN 180 +170 PRINT "TOO BAD, ";A$;"! WE'RE DOING THIS." +180 PRINT +190 PRINT "WATCH ME COUNT..." +195 ' THIS "FOR" STATEMENT STARTS A LOOP WHICH SETS +196 ' VARIABLE I TO 1 AND COUNTS TO 50 +200 FOR I = 1 TO 50 +210 PRINT I, ' USE A COMMA FOR NEAT PRINT ZONES +220 NEXT I ' REPEAT LOOP +225 ' USING THE COMMA (OR SEMICOLON) IN THE PRINT STATEMENT +226 ' KEEPS THE CURSOR ON THE SAME LINE, SO WE PRINT +227 ' A BLANK LINE TO RETURN TO THE LEFT MARGIN +230 PRINT +240 PRINT "I CAN ALSO GRAPH TRIG FUNCTIONS!" +245 ' YOU CAN DEFINE YOUR OWN FUNCTIONS WITH "DEF" +246 ' FUNCTIONS MUST START WITH "FN" +250 DEF FNY(X) = (SIN(X*0.3)+1)*30+2 +260 FOR I = 1 TO 25 +270 PRINT TAB(FNY(I));"*" +280 NEXT I +300 ' YOU CAN DEFINE AN ARRAY WITH "DIM" +301 ' YOU CAN HAVE ARRAYS OF EITHER NUMBERS OR STRINGS +310 DIM T$(15),A$(15),W(15) +315 ' "READ" LOADS FROM "DATA" STATEMENTS +316 ' DATA CAN BE ANYWHERE, OURS IS AT LINE 900 +320 FOR I = 1 TO 15 +330 READ T$(I),A$(I),W(I) +340 NEXT I +350 ' NOW THE ARRAYS ARE FILLED WITH DATA +351 ' SO LET'S PICK A VALUE AT RANDOM +352 ' THE RND FUNCTION RETURNS A RANDOM NUMBER +353 ' FIRST WE USE "RANDOMIZE" TO INITIALIZE THE +354 ' RANDOM NUMBER GENERATOR +360 RANDOMIZE +362 ' "LET" ASSIGNS A VARIABLE FROM AN EXPRESSION +370 LET J = INT(15*RND) +380 PRINT "MY FAVORITE SONG IS '";T$(J);"'" +390 PRINT "BY ";A$(J);", DO YOU KNOW IT?" +400 PRINT "IT SPENT";W(J);"WEEKS ON THE CHARTS." +410 PRINT +890 ' HERE'S THE DATA WE READ EARLIER +891 ' WE CAN USE NUMBERS, QUOTED OR UNQUOTED STRINGS +900 DATA "HELLO, GOODBYE",THE BEATLES,2 +901 DATA "JUDY IN DISGUISE",JOHN FRED AND HIS PLAYBOY BAND,2 +902 DATA "GREEN TAMBOURINE",THE LEMON PIPERS,1 +903 DATA "LOVE IS BLUE",PAUL MAURIAT,5 +904 DATA "(SITTIN' ON) THE DOCK OF THE BAY",OTIS REDDING,4 +905 DATA "HONEY",BOBBY GOLDSBORO,5 +906 DATA "TIGHTEN UP",ARCHIE BELL & THE DRELLS,3 +907 DATA "MRS. ROBINSON",SIMON & GARFUNKEL,3 +908 DATA "THIS GUY'S IN LOVE WITH YOU",HERB ALPERT,4 +909 DATA "GRAZING IN THE GRASS",HUGH MASEKELA,2 +910 DATA "HELLO, I LOVE YOU",THE DOORS,2 +911 DATA "PEOPLE GOT TO BE FREE",THE RASCALS,5 +912 DATA "HARPER VALLEY PTA",JEANNIE C. RILEY,1 +913 DATA "HEY JUDE",THE BEATLES,9 +914 DATA "LOVE CHILD",DIANA ROSS & THE SUPREMES,2 +915 DATA "I HEARD IT THROUGH THE GRAPEVINE",MARVIN GAYE,3 +979 ' WE'RE DONE, SAY GOODBYE TO THE USER +980 PRINT "I APOLOGIZE, BUT I AM FATIGUED FROM ALL OF THIS" +981 PRINT "CALCULATING. I SHALL TAKE MY LEAVE OF YOU NOW." +990 PRINT "NICE MEETING YOU, ";A$;"." +998 ' PROGRAMS MUST END WITH "END" IN THIS DIALECT 999 END diff --git a/src/common/basic/compiler.ts b/src/common/basic/compiler.ts index 8424951e..362ac39f 100644 --- a/src/common/basic/compiler.ts +++ b/src/common/basic/compiler.ts @@ -8,6 +8,7 @@ export interface BASICOptions { uppercaseOnly : boolean; // convert everything to uppercase? optionalLabels : boolean; // can omit line numbers and use labels? optionalWhitespace : boolean; // can "crunch" keywords? also, eat extra ":" delims + multipleStmtsPerLine : boolean; // multiple statements separated by ":" varNaming : 'A'|'A1'|'AA'|'*'; // only allow A0-9 for numerics, single letter for arrays/strings squareBrackets : boolean; // "[" and "]" interchangable with "(" and ")"? tickComments : boolean; // support 'comments? @@ -234,14 +235,10 @@ export type ScopeStartStatement = (IF_Statement | FOR_Statement | WHILE_Statemen export type ScopeEndStatement = NEXT_Statement | WEND_Statement; -export interface BASICLine { - label: string; - stmts: Statement[]; -} - export interface BASICProgram { opts: BASICOptions; - lines: BASICLine[]; + stmts: Statement[]; + labels: { [label: string]: number }; // label -> PC } class Token { @@ -326,9 +323,10 @@ export class BASICParser { opts : BASICOptions = DIALECTS['DEFAULT']; optionCount : number; // how many OPTION stmts so far? maxlinelen : number = 255; // maximum line length + stmts : Statement[]; errors: WorkerError[]; listings: CodeListingMap; - labels: { [label: string]: BASICLine }; + labels: { [label: string]: number }; // label -> PC targets: { [targetlabel: string]: SourceLocation }; varrefs: { [name: string]: SourceLocation }; // references fnrefs: { [name: string]: string[] }; // DEF FN call graph @@ -343,11 +341,12 @@ export class BASICParser { constructor() { this.optionCount = 0; + this.lineno = 0; + this.curlabel = null; + this.stmts = []; this.labels = {}; this.targets = {}; this.errors = []; - this.lineno = 0; - this.curlabel = null; this.listings = {}; this.varrefs = {}; this.fnrefs = {}; @@ -394,7 +393,8 @@ export class BASICParser { pushbackToken(tok: Token) { this.tokens.unshift(tok); } - parseOptLabel(line: BASICLine) { + // this parses either a line number or "label:" -- or adds a default label to a line + parseOptLabel() { let tok = this.consumeToken(); switch (tok.type) { case TokenType.Ident: @@ -410,8 +410,9 @@ export class BASICParser { } else this.dialectError(`Each line must begin with a line number`); case TokenType.Int: - this.setCurrentLabel(line, tok.str); - break; + this.addLabel(tok.str); + return; + // label added, return from function... other cases add default label case TokenType.HexOctalInt: case TokenType.Float: this.compileError(`Line numbers must be positive integers.`); @@ -429,30 +430,41 @@ export class BASICParser { case TokenType.Remark: break; } + // add default label + this.addLabel('#'+this.lineno); } - setCurrentLabel(line: BASICLine, str: string) { - if (this.labels[str] != null) this.compileError(`There's a duplicated label "${str}".`); - this.labels[str] = line; - line.label = str; + getPC() : number { + return this.stmts.length; + } + addStatement(stmt: Statement, cmdtok: Token, endtok?: Token) { + // check IF/THEN WHILE/WEND FOR/NEXT etc + this.modifyScope(stmt); + // set location for statement + if (endtok == null) endtok = this.peekToken(); + stmt.$loc = { path: cmdtok.$loc.path, line: cmdtok.$loc.line, start: cmdtok.$loc.start, end: endtok.$loc.start, label: this.curlabel, offset: null }; + this.stmts.push(stmt); + } + addLabel(str: string) { + if (this.labels[str] != null) this.compileError(`There's a duplicated label named "${str}".`); + this.labels[str] = this.getPC(); this.curlabel = str; this.tokens.forEach((tok) => tok.$loc.label = str); } parseFile(file: string, path: string) : BASICProgram { this.path = path; var txtlines = file.split(/\n|\r\n?/); - var pgmlines = txtlines.map((line) => this.parseLine(line)); - var program = { opts: this.opts, lines: pgmlines }; + txtlines.forEach((line) => this.parseLine(line)); + var program = { opts: this.opts, stmts: this.stmts, labels: this.labels }; this.checkAll(program); this.listings[path] = this.generateListing(file, program); return program; } - parseLine(line: string) : BASICLine { + parseLine(line: string) : void { try { this.tokenize(line); - return this.parse(); + this.parse(); } catch (e) { if (!(e instanceof CompileError)) throw e; // ignore compile errors since errors[] list captures them - return {label:null, stmts:[]}; } } _tokenize(line: string) : void { @@ -517,27 +529,25 @@ export class BASICParser { if (line.length > this.maxlinelen) this.compileError(`A line should be no more than ${this.maxlinelen} characters long.`); this._tokenize(line); } - parse() : BASICLine { - var line = {label: null, stmts: []}; + parse() : void { // not empty line? if (this.tokens.length) { - this.parseOptLabel(line); + this.parseOptLabel(); if (this.tokens.length) { - line.stmts = this.parseCompoundStatement(); + this.parseCompoundStatement(); } + var next = this.peekToken(); + if (!isEOS(next)) this.compileError(`Expected end of line or ':'`, next.$loc); this.curlabel = null; } - return line; } - parseCompoundStatement(): Statement[] { - var list = this.parseList(this.parseStatement, ':'); - var next = this.peekToken(); - if (!isEOS(next)) - this.compileError(`Expected end of line or ':'`, next.$loc); - if (next.str == 'ELSE') - return list.concat(this.parseCompoundStatement()); - else - return list; + parseCompoundStatement() : void { + if (this.opts.multipleStmtsPerLine) { + this.parseList(this.parseStatement, ':'); + } else { + this.parseList(this.parseStatement, '\0'); + if (this.peekToken().str == ':') this.dialectErrorNoSupport(`multiple statements on a line`); + } } validKeyword(keyword: string) : string { return (this.opts.validKeywords && this.opts.validKeywords.indexOf(keyword) < 0) ? null : keyword; @@ -578,7 +588,6 @@ export class BASICParser { if (this.validKeyword(cmd) == null) this.dialectErrorNoSupport(`the ${cmd} statement`); stmt = fn.bind(this)(); - this.modifyScope(stmt); break; } else if (this.peekToken().str == '=' || this.peekToken().str == '(') { if (!this.opts.optionalLet) @@ -596,7 +605,8 @@ export class BASICParser { this.compileError(`There should be a command here.`); return null; } - if (stmt) stmt.$loc = { path: cmdtok.$loc.path, line: cmdtok.$loc.line, start: cmdtok.$loc.start, end: this.peekToken().$loc.start, label: this.curlabel, offset: null }; + // add statement to list + if (stmt != null) this.addStatement(stmt, cmdtok); return stmt; } // check scope stuff (if compiledBlocks is true) @@ -898,30 +908,39 @@ export class BASICParser { return { command: cmd, label: expr }; } } - stmt__IF(): IF_Statement { + stmt__IF(): void { + var cmdtok = this.lasttoken; var cond = this.parseExpr(); - var iftrue: Statement[]; + var ifstmt = { command: "IF", cond: cond }; + this.addStatement(ifstmt, cmdtok); // 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'); + // parse line number or statement clause + this.parseGotoOrStatements(); + // is the next statement an ELSE? + // gotta parse it now because it's an end-of-statement token + if (this.peekToken().str == 'ELSE') { + this.expectToken('ELSE'); + this.stmt__ELSE(); + } + } + stmt__ELSE(): void { + this.addStatement({ command: "ELSE" }, this.lasttoken); + // parse line number or statement clause + this.parseGotoOrStatements(); + } + parseGotoOrStatements() { var lineno = this.peekToken(); // assume GOTO if number given after THEN if (lineno.type == TokenType.Int) { - this.pushbackToken({type:TokenType.Ident, str:'GOTO', $loc:lineno.$loc}); + this.parseLabel(); + var gotostmt : GOTO_Statement = { command:'GOTO', label: {value:lineno.str} } + this.addStatement(gotostmt, lineno); + } else { + // parse rest of IF clause + this.parseCompoundStatement(); } - // add fake ":" - this.pushbackToken({type:TokenType.Operator, str:':', $loc:lineno.$loc}); - return { command: "IF", cond: cond }; - } - stmt__ELSE(): ELSE_Statement { - var lineno = this.peekToken(); - // assume GOTO if number given after ELSE - if (lineno.type == TokenType.Int) { - this.pushbackToken({type:TokenType.Ident, str:'GOTO', $loc:lineno.$loc}); - } - // add fake ":" - this.pushbackToken({type:TokenType.Operator, str:':', $loc:lineno.$loc}); - return { command: "ELSE" }; } stmt__FOR() : FOR_Statement { var lexpr = this.parseForNextLexpr(); @@ -1124,15 +1143,12 @@ export class BASICParser { // for workermain generateListing(file: string, program: BASICProgram) { var srclines = []; - var pc = 0; var laststmt : Statement; - program.lines.forEach((line, idx) => { - line.stmts.forEach((stmt) => { - laststmt = stmt; - var sl = stmt.$loc; - sl.offset = pc++; // TODO: could Statement have offset field? - srclines.push(sl); - }); + program.stmts.forEach((stmt, idx) => { + laststmt = stmt; + var sl = stmt.$loc; + sl.offset = idx; + srclines.push(sl); }); if (this.opts.endStmtRequired && (laststmt == null || laststmt.command != 'END')) this.dialectError(`All programs must have a final END statement`); @@ -1172,6 +1188,7 @@ export const ECMA55_MINIMAL : BASICOptions = { uppercaseOnly : true, optionalLabels : false, optionalWhitespace : false, + multipleStmtsPerLine : false, varNaming : "A1", staticArrays : true, sharedArrayNamespace : true, @@ -1220,6 +1237,7 @@ export const DARTMOUTH_4TH_EDITION : BASICOptions = { uppercaseOnly : true, optionalLabels : false, optionalWhitespace : false, + multipleStmtsPerLine : false, varNaming : "A1", staticArrays : true, sharedArrayNamespace : false, @@ -1271,6 +1289,7 @@ export const TINY_BASIC : BASICOptions = { uppercaseOnly : true, optionalLabels : false, optionalWhitespace : false, + multipleStmtsPerLine : false, varNaming : "A", staticArrays : false, sharedArrayNamespace : true, @@ -1317,6 +1336,7 @@ export const HP_TIMESHARED_BASIC : BASICOptions = { uppercaseOnly : false, // the terminal is usually uppercase optionalLabels : false, optionalWhitespace : false, + multipleStmtsPerLine : true, varNaming : "A1", staticArrays : true, sharedArrayNamespace : false, @@ -1370,6 +1390,7 @@ export const DEC_BASIC_11 : BASICOptions = { uppercaseOnly : true, // translates all lower to upper optionalLabels : false, optionalWhitespace : false, + multipleStmtsPerLine : false, // actually "\" varNaming : "A1", staticArrays : true, sharedArrayNamespace : false, @@ -1424,6 +1445,7 @@ export const DEC_BASIC_PLUS : BASICOptions = { uppercaseOnly : false, optionalLabels : false, optionalWhitespace : false, + multipleStmtsPerLine : true, varNaming : "A1", staticArrays : true, sharedArrayNamespace : false, @@ -1485,6 +1507,7 @@ export const BASICODE : BASICOptions = { uppercaseOnly : false, optionalLabels : false, optionalWhitespace : true, + multipleStmtsPerLine : true, varNaming : "AA", staticArrays : true, sharedArrayNamespace : false, @@ -1535,6 +1558,7 @@ export const ALTAIR_BASIC41 : BASICOptions = { uppercaseOnly : true, optionalLabels : false, optionalWhitespace : true, + multipleStmtsPerLine : true, varNaming : "*", // or AA staticArrays : false, sharedArrayNamespace : true, @@ -1593,6 +1617,7 @@ export const APPLESOFT_BASIC : BASICOptions = { uppercaseOnly : false, optionalLabels : false, optionalWhitespace : true, + multipleStmtsPerLine : true, varNaming : "*", // or AA staticArrays : false, sharedArrayNamespace : false, @@ -1652,6 +1677,7 @@ export const BASIC80 : BASICOptions = { uppercaseOnly : false, optionalLabels : false, optionalWhitespace : true, + multipleStmtsPerLine : true, varNaming : "*", staticArrays : false, sharedArrayNamespace : true, @@ -1712,6 +1738,7 @@ export const MODERN_BASIC : BASICOptions = { uppercaseOnly : false, optionalLabels : true, optionalWhitespace : false, + multipleStmtsPerLine : true, varNaming : "*", staticArrays : false, sharedArrayNamespace : false, @@ -1749,6 +1776,7 @@ export const MODERN_BASIC : BASICOptions = { // TODO: integer vars // TODO: DEFINT/DEFSTR // TODO: excess INPUT ignored, error msg +// TODO: out of order line numbers export const DIALECTS = { "DEFAULT": MODERN_BASIC, diff --git a/src/common/basic/runtime.ts b/src/common/basic/runtime.ts index 1d42846b..8cbf6b7e 100644 --- a/src/common/basic/runtime.ts +++ b/src/common/basic/runtime.ts @@ -72,8 +72,6 @@ export class BASICRuntime { program : basic.BASICProgram; allstmts : basic.Statement[]; - line2pc : number[]; - pc2line : Map; pc2label : Map; label2pc : {[label : string] : number}; label2dataptr : {[label : string] : number}; @@ -103,7 +101,7 @@ export class BASICRuntime { let prevlabel = null; let prevpcofs = 0; if (this.pc2label != null) { - var pc = this.curpc; + let pc = this.curpc; while (pc > 0 && (prevlabel = this.pc2label.get(pc)) == null) { pc--; } @@ -114,27 +112,18 @@ export class BASICRuntime { this.program = program; this.opts = program.opts; if (!this.opts.maxArrayElements) this.opts.maxArrayElements = DEFAULT_MAX_ARRAY_ELEMENTS; - this.label2pc = {}; + this.allstmts = program.stmts; + this.label2pc = program.labels; 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 - 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)); - }); + // build PC -> label lookup + for (var label in program.labels) { + var targetpc = program.labels[label]; + this.pc2label.set(targetpc, label); + } // compile statements ahead of time this.allstmts.forEach((stmt, pc) => { this.curpc = pc + 1; // for error reporting @@ -278,10 +267,11 @@ export class BASICRuntime { stmt.$run(); } + // TODO: this only works because each line has a label skipToEOL() { do { this.curpc++; - } while (this.curpc < this.allstmts.length && !this.pc2line.get(this.curpc)); + } while (this.curpc < this.allstmts.length && !this.pc2label.get(this.curpc)); } skipToElse() { @@ -292,7 +282,7 @@ export class BASICRuntime { if (cmd == 'ELSE') { this.curpc++; break; } else if (cmd == 'IF') return this.skipToEOL(); this.curpc++; - if (this.pc2line.get(this.curpc)) + if (this.pc2label.get(this.curpc)) break; } } @@ -380,9 +370,10 @@ export class BASICRuntime { this.column = 0; str = obj; } else if (obj == '\t') { - var curgroup = Math.floor(this.column / this.opts.printZoneLength); + var l = this.opts.printZoneLength; + var curgroup = Math.floor(this.column / l); var nextcol = (curgroup + 1) * this.opts.printZoneLength; - if (nextcol >= this.margin) { this.column = 0; str = "\n"; } // return to left margin + if (nextcol+l > this.margin) { this.column = 0; str = "\n"; } // return to left margin else str = this.TAB(nextcol); // next column } else { str = `${obj}`; diff --git a/src/platform/basic.ts b/src/platform/basic.ts index 6b5f4b76..ca2e1160 100644 --- a/src/platform/basic.ts +++ b/src/platform/basic.ts @@ -8,7 +8,7 @@ import { BASICProgram } from "../common/basic/compiler"; import { TeleTypeWithKeyboard } from "../common/teletype"; const BASIC_PRESETS = [ - { id: 'hello.bas', name: 'Hello World' }, + { id: 'hello.bas', name: 'Tutorial' }, { id: 'sieve.bas', name: 'Sieve Benchmark' }, { id: 'mortgage.bas', name: 'Interest Calculator' }, { id: '23match.bas', name: '23 Matches' }, @@ -27,7 +27,7 @@ class BASICPlatform implements Platform { clock: number = 0; timer: AnimationTimer; tty: TeleTypeWithKeyboard; - hotReload: boolean = true; + hotReload: boolean = false; animcount: number = 0; constructor(mainElement: HTMLElement) {