basic: ON..GOSUB, CLEAR, rearranged platform menu

This commit is contained in:
Steven Hugg 2020-08-10 08:07:09 -05:00
parent cf39cd4f58
commit 946037a1c9
4 changed files with 86 additions and 44 deletions

View File

@ -191,6 +191,7 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
<li><a class="dropdown-item" href="?platform=msx-libcv">MSX (libCV)</a></li> <li><a class="dropdown-item" href="?platform=msx-libcv">MSX (libCV)</a></li>
<li><a class="dropdown-item" href="?platform=apple2">Apple ][+</a></li> <li><a class="dropdown-item" href="?platform=apple2">Apple ][+</a></li>
<li><a class="dropdown-item" href="?platform=zx">ZX Spectrum</a></li> <li><a class="dropdown-item" href="?platform=zx">ZX Spectrum</a></li>
<li><a class="dropdown-item" href="?platform=x86">x86 (FreeDOS)</a></li>
</ul> </ul>
</li> </li>
<li class="dropdown dropdown-submenu"> <li class="dropdown dropdown-submenu">
@ -200,6 +201,7 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
<li><a class="dropdown-item" href="?platform=mw8080bw">Midway 8080</a></li> <li><a class="dropdown-item" href="?platform=mw8080bw">Midway 8080</a></li>
<li><a class="dropdown-item" href="?platform=galaxian-scramble">Galaxian/Scramble</a></li> <li><a class="dropdown-item" href="?platform=galaxian-scramble">Galaxian/Scramble</a></li>
<li><a class="dropdown-item" href="?platform=vector-z80color">Atari Color Vector (Z80)</a></li> <li><a class="dropdown-item" href="?platform=vector-z80color">Atari Color Vector (Z80)</a></li>
<li><a class="dropdown-item" href="?platform=vector-ataricolor">Atari Color Vector (6502)</a></li>
<li><a class="dropdown-item" href="?platform=williams-z80">Williams (Z80)</a></li> <li><a class="dropdown-item" href="?platform=williams-z80">Williams (Z80)</a></li>
<li><a class="dropdown-item" href="?platform=sound_williams-z80">Williams Sound (Z80)</a></li> <li><a class="dropdown-item" href="?platform=sound_williams-z80">Williams Sound (Z80)</a></li>
</ul> </ul>
@ -211,26 +213,25 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
<li><a class="dropdown-item" href="?platform=verilog-vga">Verilog (VGA @ 25 Mhz)</a></li> <li><a class="dropdown-item" href="?platform=verilog-vga">Verilog (VGA @ 25 Mhz)</a></li>
</ul> </ul>
</li> </li>
<li class="dropdown dropdown-submenu">
<a tabindex="-1" href="#">MAME Emulators</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="?platform=atari8-800xl.mame">Atari 800XL (MAME)</a></li>
<li><a class="dropdown-item" href="?platform=atari8-5200.mame">Atari 5200 (MAME)</a></li>
<hr>
<li><a class="dropdown-item" href="?platform=vcs.mame">Atari 2600 (MAME)</a></li>
<li><a class="dropdown-item" href="?platform=coleco.mame">ColecoVision (MAME)</a></li>
<li><a class="dropdown-item" href="?platform=nes.mame">NES (MAME)</a></li>
</ul>
</li>
<li class="dropdown dropdown-submenu"> <li class="dropdown dropdown-submenu">
<a tabindex="-1" href="#">Other</a> <a tabindex="-1" href="#">Text-Based</a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a class="dropdown-item" href="?platform=vector-ataricolor">Atari Color Vector (6502)</a></li> <li><a class="dropdown-item" href="?platform=basic">BASIC</a></li>
<li><a class="dropdown-item" href="?platform=x86">x86 (FreeDOS)</a></li> <li><a class="dropdown-item" href="?platform=zmachine">Z-Machine</a></li>
<li><a class="dropdown-item" href="?platform=zmachine">Z-Machine</a></li> <li><a class="dropdown-item" href="?platform=markdown">Markdown Text Editor</a></li>
<li><a class="dropdown-item" href="?platform=markdown">Markdown Text Editor</a></li> </ul>
</ul> </li>
</li> <li class="dropdown dropdown-submenu">
<a tabindex="-1" href="#">MAME Emulators</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="?platform=atari8-800xl.mame">Atari 800XL (MAME)</a></li>
<li><a class="dropdown-item" href="?platform=atari8-5200.mame">Atari 5200 (MAME)</a></li>
<hr>
<li><a class="dropdown-item" href="?platform=vcs.mame">Atari 2600 (MAME)</a></li>
<li><a class="dropdown-item" href="?platform=coleco.mame">ColecoVision (MAME)</a></li>
<li><a class="dropdown-item" href="?platform=nes.mame">NES (MAME)</a></li>
</ul>
</li>
</ul> </ul>
</span> </span>

View File

@ -88,7 +88,7 @@ export interface RETURN_Statement {
} }
export interface ONGOTO_Statement { export interface ONGOTO_Statement {
command: "ONGOTO"; command: "ONGOTO" | "ONGOSUB";
expr: Expr; expr: Expr;
labels: Expr[]; labels: Expr[];
} }
@ -706,9 +706,11 @@ export class BASICParser {
} }
stmt__ON() : ONGOTO_Statement { stmt__ON() : ONGOTO_Statement {
var expr = this.parseExpr(); 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(); var labels = this.parseLabelList();
return { command:'ONGOTO', expr:expr, labels:labels }; return { command:cmd, expr:expr, labels:labels };
} }
stmt__DEF() : DEF_Statement { stmt__DEF() : DEF_Statement {
var lexpr = this.parseVarSubscriptOrFunc(); var lexpr = this.parseVarSubscriptOrFunc();
@ -728,6 +730,9 @@ export class BASICParser {
this.decls[lexpr.name] = this.lasttoken.$loc; this.decls[lexpr.name] = this.lasttoken.$loc;
return { command:'GET', lexpr:lexpr }; 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) // TODO: CHANGE A TO A$ (4th edition, A(0) is len and A(1..) are chars)
stmt__OPTION() : OPTION_Statement { stmt__OPTION() : OPTION_Statement {
var tokname = this.consumeToken(); var tokname = this.consumeToken();
@ -826,7 +831,7 @@ export const ECMA55_MINIMAL : BASICOptions = {
validKeywords : ['BASE','DATA','DEF','DIM','END', validKeywords : ['BASE','DATA','DEF','DIM','END',
'FOR','GO','GOSUB','GOTO','IF','INPUT','LET','NEXT','ON','OPTION','PRINT', 'FOR','GO','GOSUB','GOTO','IF','INPUT','LET','NEXT','ON','OPTION','PRINT',
'RANDOMIZE','READ','REM','RESTORE','RETURN','STEP','STOP','SUB','THEN','TO' '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'], validFunctions : ['ABS','ATN','COS','EXP','INT','LOG','RND','SGN','SIN','SQR','TAB','TAN'],
validOperators : ['=', '<>', '<', '>', '<=', '>=', '+', '-', '*', '/', '^'], validOperators : ['=', '<>', '<', '>', '<=', '>=', '+', '-', '*', '/', '^'],
printZoneLength : 15, printZoneLength : 15,
@ -857,7 +862,7 @@ export const ALTAIR_BASIC40 : BASICOptions = {
tickComments : false, tickComments : false,
validKeywords : null, // all validKeywords : null, // all
validFunctions : null, // all validFunctions : null, // all
validOperators : null, // all ['\\','MOD','NOT','AND','OR','XOR','EQV','IMP'], validOperators : null, // all
printZoneLength : 15, printZoneLength : 15,
numericPadding : true, numericPadding : true,
checkOverflow : true, checkOverflow : true,
@ -884,10 +889,19 @@ export const APPLESOFT_BASIC : BASICOptions = {
maxStringLength : 255, maxStringLength : 255,
sparseArrays : false, sparseArrays : false,
tickComments : false, tickComments : false,
validKeywords : null, // all validKeywords : [
validFunctions : ['ABS','ATN','COS','EXP','INT','LOG','RND','SGN','SIN','SQR','TAN', 'CLEAR','LET','DIM','DEF','FN','GOTO','GOSUB','RETURN','ON','POP',
'LEN','LEFT$','MID$','RIGHT$','STR$','VAL','CHR$','ASC', 'FOR','TO','NEXT','IF','THEN','END','STOP','ONERR','RESUME',
'FRE','SCRN','PDL','PEEK'], // TODO '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'], validOperators : ['=', '<>', '<', '>', '<=', '>=', '+', '-', '*', '/', '^', 'AND', 'NOT', 'OR'],
printZoneLength : 16, printZoneLength : 16,
numericPadding : false, numericPadding : false,

View File

@ -90,16 +90,19 @@ export class BASICRuntime {
reset() { reset() {
this.curpc = 0; this.curpc = 0;
this.dataptr = 0; this.dataptr = 0;
this.vars = {}; this.clearVars();
this.arrays = {};
this.defs = {};
this.forLoops = []; this.forLoops = [];
this.returnStack = []; this.returnStack = [];
this.column = 0; this.column = 0;
this.running = true; this.running = true;
this.exited = false; this.exited = false;
} }
clearVars() {
this.vars = {};
this.arrays = {};
this.defs = {}; // TODO? only in interpreters
}
getBuiltinFunctions() { getBuiltinFunctions() {
var fnames = this.program && this.opts.validFunctions; var fnames = this.program && this.opts.validFunctions;
// if no valid function list, look for ABC...() functions in prototype // if no valid function list, look for ABC...() functions in prototype
@ -119,18 +122,13 @@ export class BASICRuntime {
} }
getLineForPC(pc:number) { getLineForPC(pc:number) {
var line; var stmt = this.allstmts[pc];
do { return stmt && stmt.$loc && stmt.$loc.line;
line = this.pc2line.get(pc);
if (line != null) break;
} while (--pc >= 0);
return line;
} }
getLabelForPC(pc:number) { getLabelForPC(pc:number) {
var lineno = this.getLineForPC(pc); var stmt = this.allstmts[pc];
var pgmline = this.program.lines[lineno]; return stmt && stmt.$loc && stmt.$loc.label;
return pgmline ? pgmline.label : '?';
} }
getCurrentSourceLocation() : SourceLocation { getCurrentSourceLocation() : SourceLocation {
@ -138,6 +136,11 @@ export class BASICRuntime {
return stmt && stmt.$loc; return stmt && stmt.$loc;
} }
getCurrentLabel() : string {
var loc = this.getCurrentSourceLocation();
return loc && loc.label;
}
getStatement() { getStatement() {
return this.allstmts[this.curpc]; 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.runtimeError("I tried to POP, but there wasn't a corresponding GOSUB.");
this.returnStack.pop(); this.returnStack.pop();
} }
valueToString(obj) : string { valueToString(obj) : string {
var str; var str;
if (typeof obj === 'number') { if (typeof obj === 'number') {
@ -439,6 +442,13 @@ export class BASICRuntime {
if (value < 1 || value > labels.length) if (value < 1 || value > labels.length)
this.runtimeError(`I needed a number between 1 and ${labels.length}, but I got ${value}.`); this.runtimeError(`I needed a number between 1 and ${labels.length}, but I got ${value}.`);
this.gotoLabel(labels[value-1]); 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 { nextDatum() : basic.Value {
@ -550,7 +560,10 @@ export class BASICRuntime {
do__ONGOTO(stmt : basic.ONGOTO_Statement) { do__ONGOTO(stmt : basic.ONGOTO_Statement) {
var expr = this.expr2js(stmt.expr); var expr = this.expr2js(stmt.expr);
var labels = stmt.labels.map((arg) => this.expr2js(arg, {isconst:true})).join(', '); 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() { do__DATA() {
@ -596,6 +609,10 @@ export class BASICRuntime {
})`; })`;
} }
do__CLEAR() {
return 'this.clearVars()';
}
// TODO: ONERR, ON ERROR GOTO // TODO: ONERR, ON ERROR GOTO
// TODO: "SUBSCRIPT ERROR" (range check) // TODO: "SUBSCRIPT ERROR" (range check)
// TODO: gosubs nested too deeply // TODO: gosubs nested too deeply

View File

@ -173,7 +173,17 @@ class BASICPlatform implements Platform {
$.extend(true, this.runtime, state); $.extend(true, this.runtime, state);
} }
getDebugTree() { 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) { inspect(sym: string) {
var o = this.runtime.vars[sym]; var o = this.runtime.vars[sym];