diff --git a/index.html b/index.html index e6d8ef67..302be48e 100644 --- a/index.html +++ b/index.html @@ -191,6 +191,7 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
  • MSX (libCV)
  • Apple ][+
  • ZX Spectrum
  • +
  • x86 (FreeDOS)
  • Midway 8080
  • Galaxian/Scramble
  • Atari Color Vector (Z80)
  • +
  • Atari Color Vector (6502)
  • Williams (Z80)
  • Williams Sound (Z80)
  • @@ -211,26 +213,25 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
  • Verilog (VGA @ 25 Mhz)
  • - + Text-Based + + + diff --git a/src/common/basic/compiler.ts b/src/common/basic/compiler.ts index 9caf2d76..6f90beb3 100644 --- a/src/common/basic/compiler.ts +++ b/src/common/basic/compiler.ts @@ -88,7 +88,7 @@ export interface RETURN_Statement { } export interface ONGOTO_Statement { - command: "ONGOTO"; + command: "ONGOTO" | "ONGOSUB"; expr: Expr; labels: Expr[]; } @@ -706,9 +706,11 @@ export class BASICParser { } stmt__ON() : ONGOTO_Statement { var expr = this.parseExpr(); - this.expectToken('GOTO'); + var gotok = this.consumeToken(); + var cmd = {GOTO:'ONGOTO', GOSUB:'ONGOSUB'}[gotok.str]; + if (!cmd) this.compileError(`There should be a GOTO or GOSUB here.`); var labels = this.parseLabelList(); - return { command:'ONGOTO', expr:expr, labels:labels }; + return { command:cmd, expr:expr, labels:labels }; } stmt__DEF() : DEF_Statement { var lexpr = this.parseVarSubscriptOrFunc(); @@ -728,6 +730,9 @@ export class BASICParser { this.decls[lexpr.name] = this.lasttoken.$loc; return { command:'GET', lexpr:lexpr }; } + stmt__CLEAR() : NoArgStatement { + return { command:'CLEAR' }; + } // TODO: CHANGE A TO A$ (4th edition, A(0) is len and A(1..) are chars) stmt__OPTION() : OPTION_Statement { var tokname = this.consumeToken(); @@ -826,7 +831,7 @@ export const ECMA55_MINIMAL : BASICOptions = { validKeywords : ['BASE','DATA','DEF','DIM','END', 'FOR','GO','GOSUB','GOTO','IF','INPUT','LET','NEXT','ON','OPTION','PRINT', 'RANDOMIZE','READ','REM','RESTORE','RETURN','STEP','STOP','SUB','THEN','TO' - ], + ], // TODO: no ON...GOSUB validFunctions : ['ABS','ATN','COS','EXP','INT','LOG','RND','SGN','SIN','SQR','TAB','TAN'], validOperators : ['=', '<>', '<', '>', '<=', '>=', '+', '-', '*', '/', '^'], printZoneLength : 15, @@ -857,7 +862,7 @@ export const ALTAIR_BASIC40 : BASICOptions = { tickComments : false, validKeywords : null, // all validFunctions : null, // all - validOperators : null, // all ['\\','MOD','NOT','AND','OR','XOR','EQV','IMP'], + validOperators : null, // all printZoneLength : 15, numericPadding : true, checkOverflow : true, @@ -884,10 +889,19 @@ export const APPLESOFT_BASIC : BASICOptions = { maxStringLength : 255, sparseArrays : false, tickComments : false, - validKeywords : null, // all - validFunctions : ['ABS','ATN','COS','EXP','INT','LOG','RND','SGN','SIN','SQR','TAN', - 'LEN','LEFT$','MID$','RIGHT$','STR$','VAL','CHR$','ASC', - 'FRE','SCRN','PDL','PEEK'], // TODO + validKeywords : [ + 'CLEAR','LET','DIM','DEF','FN','GOTO','GOSUB','RETURN','ON','POP', + 'FOR','TO','NEXT','IF','THEN','END','STOP','ONERR','RESUME', + 'PRINT','INPUT','GET','HOME','HTAB','VTAB', + 'INVERSE','FLASH','NORMAL','TEXT', + 'GR','COLOR','PLOT','HLIN','VLIN', + 'HGR','HGR2','HPLOT','HCOLOR','AT', + 'DATA','READ','RESTORE', + 'REM','TRACE','NOTRACE'], + validFunctions : [ + 'ABS','ATN','COS','EXP','INT','LOG','RND','SGN','SIN','SQR','TAN', + 'LEN','LEFT$','MID$','RIGHT$','STR$','VAL','CHR$','ASC', + 'FRE','SCRN','PDL','PEEK','POS'], validOperators : ['=', '<>', '<', '>', '<=', '>=', '+', '-', '*', '/', '^', 'AND', 'NOT', 'OR'], printZoneLength : 16, numericPadding : false, diff --git a/src/common/basic/runtime.ts b/src/common/basic/runtime.ts index 759c512d..883d49f6 100644 --- a/src/common/basic/runtime.ts +++ b/src/common/basic/runtime.ts @@ -90,16 +90,19 @@ export class BASICRuntime { reset() { this.curpc = 0; this.dataptr = 0; - this.vars = {}; - this.arrays = {}; - this.defs = {}; + this.clearVars(); this.forLoops = []; this.returnStack = []; this.column = 0; this.running = true; this.exited = false; } - + clearVars() { + this.vars = {}; + this.arrays = {}; + this.defs = {}; // TODO? only in interpreters + } + getBuiltinFunctions() { var fnames = this.program && this.opts.validFunctions; // if no valid function list, look for ABC...() functions in prototype @@ -119,18 +122,13 @@ export class BASICRuntime { } getLineForPC(pc:number) { - var line; - do { - line = this.pc2line.get(pc); - if (line != null) break; - } while (--pc >= 0); - return line; + var stmt = this.allstmts[pc]; + return stmt && stmt.$loc && stmt.$loc.line; } getLabelForPC(pc:number) { - var lineno = this.getLineForPC(pc); - var pgmline = this.program.lines[lineno]; - return pgmline ? pgmline.label : '?'; + var stmt = this.allstmts[pc]; + return stmt && stmt.$loc && stmt.$loc.label; } getCurrentSourceLocation() : SourceLocation { @@ -138,6 +136,11 @@ export class BASICRuntime { return stmt && stmt.$loc; } + getCurrentLabel() : string { + var loc = this.getCurrentSourceLocation(); + return loc && loc.label; + } + getStatement() { return this.allstmts[this.curpc]; } @@ -228,7 +231,7 @@ export class BASICRuntime { this.runtimeError("I tried to POP, but there wasn't a corresponding GOSUB."); this.returnStack.pop(); } - + valueToString(obj) : string { var str; if (typeof obj === 'number') { @@ -439,6 +442,13 @@ export class BASICRuntime { if (value < 1 || value > labels.length) this.runtimeError(`I needed a number between 1 and ${labels.length}, but I got ${value}.`); this.gotoLabel(labels[value-1]); + + } + onGosubLabel(value: number, ...labels: string[]) { + value = this.ROUND(value); + if (value < 1 || value > labels.length) + this.runtimeError(`I needed a number between 1 and ${labels.length}, but I got ${value}.`); + this.gosubLabel(labels[value-1]); } nextDatum() : basic.Value { @@ -550,7 +560,10 @@ export class BASICRuntime { do__ONGOTO(stmt : basic.ONGOTO_Statement) { var expr = this.expr2js(stmt.expr); var labels = stmt.labels.map((arg) => this.expr2js(arg, {isconst:true})).join(', '); - return `this.onGotoLabel(${expr}, ${labels})`; + if (stmt.command == 'ONGOTO') + return `this.onGotoLabel(${expr}, ${labels})`; + else + return `this.onGosubLabel(${expr}, ${labels})`; } do__DATA() { @@ -596,6 +609,10 @@ export class BASICRuntime { })`; } + do__CLEAR() { + return 'this.clearVars()'; + } + // TODO: ONERR, ON ERROR GOTO // TODO: "SUBSCRIPT ERROR" (range check) // TODO: gosubs nested too deeply diff --git a/src/platform/basic.ts b/src/platform/basic.ts index 36b748a3..20363b2c 100644 --- a/src/platform/basic.ts +++ b/src/platform/basic.ts @@ -173,7 +173,17 @@ class BASICPlatform implements Platform { $.extend(true, this.runtime, state); } getDebugTree() { - return this.runtime; + return { + Variables: this.runtime.vars, + Arrays: this.runtime.arrays, + Functions: this.runtime.defs, + ForLoops: this.runtime.forLoops, + ReturnStack: this.runtime.returnStack, + CurrentLine: this.runtime.getCurrentLabel(), + NextDatum: this.runtime.datums[this.runtime.dataptr], + Dialect: this.runtime.opts, + Internals: this.runtime, + } } inspect(sym: string) { var o = this.runtime.vars[sym];