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];