From 2cac07773546f664a69696a6d1e1cfca6715fb61 Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Fri, 14 Aug 2020 09:26:43 -0500 Subject: [PATCH] basic: help, dialect info, fixed advance() issue, slice = bug, GOTO ref fix, RESTORE fix --- src/common/basic/compiler.ts | 24 +++++++++++++++++------- src/common/basic/run.ts | 31 ++++++++++++++++++++++++++++++- src/common/basic/runtime.ts | 16 +++++++++++----- src/platform/basic.ts | 8 ++++++-- 4 files changed, 64 insertions(+), 15 deletions(-) diff --git a/src/common/basic/compiler.ts b/src/common/basic/compiler.ts index 400dcfbd..0d63cb20 100644 --- a/src/common/basic/compiler.ts +++ b/src/common/basic/compiler.ts @@ -321,9 +321,12 @@ export class BASICParser { this.listings = {}; this.refs = {}; } - compileError(msg: string, loc?: SourceLocation) { + addError(msg: string, loc?: SourceLocation) { if (!loc) loc = this.peekToken().$loc; this.errors.push({path:loc.path, line:loc.line, label:this.curlabel, start:loc.start, end:loc.end, msg:msg}); + } + compileError(msg: string, loc?: SourceLocation) { + this.addError(msg, loc); throw new CompileError(msg, loc); } dialectError(what: string, loc?: SourceLocation) { @@ -576,8 +579,14 @@ export class BASICParser { } parseLabel() : Expr { // parse full expr? - if (this.opts.computedGoto) - return this.parseExpr(); + if (this.opts.computedGoto) { + // parse expression, but still add to list of label targets if constant + var expr = this.parseExpr(); + if ((expr as Literal).value != null) { + this.targets[(expr as Literal).value] = this.lasttoken.$loc; + } + return expr; + } // parse a single number or ident label var tok = this.consumeToken(); switch (tok.type) { @@ -991,7 +1000,7 @@ export class BASICParser { checkLabels() { for (let targ in this.targets) { if (this.labels[targ] == null) { - this.compileError(`There isn't a line number ${targ}.`, this.targets[targ]); + this.addError(`There isn't a line number ${targ}.`, this.targets[targ]); } } } @@ -1081,7 +1090,7 @@ export const TINY_BASIC : BASICOptions = { multipleNextVars : false, bitwiseLogic : false, checkOnGotoIndex : false, - computedGoto : true, + computedGoto : true, // TODO: is it really though? restoreWithLabel : false, squareBrackets : false, arraysContainChars : false, @@ -1090,7 +1099,7 @@ export const TINY_BASIC : BASICOptions = { export const HP_TIMESHARED_BASIC : BASICOptions = { - dialectName: "HPTSB", + dialectName: "HP2000", asciiOnly : true, uppercaseOnly : false, optionalLabels : false, @@ -1400,8 +1409,9 @@ export const DIALECTS = { "ALTAIR41": ALTAIR_BASIC41, "ECMA55": ECMA55_MINIMAL, "MINIMAL": ECMA55_MINIMAL, - "HPTSB": HP_TIMESHARED_BASIC, + "HP": HP_TIMESHARED_BASIC, "HPB": HP_TIMESHARED_BASIC, + "HPTSB": HP_TIMESHARED_BASIC, "HP2000": HP_TIMESHARED_BASIC, "HPBASIC": HP_TIMESHARED_BASIC, "HPACCESS": HP_TIMESHARED_BASIC, diff --git a/src/common/basic/run.ts b/src/common/basic/run.ts index 91ae1a00..44344929 100644 --- a/src/common/basic/run.ts +++ b/src/common/basic/run.ts @@ -1,6 +1,33 @@ -import { BASICParser, DIALECTS } from "./compiler"; +import { BASICParser, DIALECTS, BASICOptions } from "./compiler"; import { BASICRuntime } from "./runtime"; +import { lpad, rpad } from "../util"; + +function dumpDialectInfo() { + var dialects = new Set(); + var array = {}; + var SELECTED_DIALECTS = ['TINY','ECMA55','HP','ALTAIR41','BASIC80','MODERN']; + SELECTED_DIALECTS.forEach((dkey) => { + dialects.add(DIALECTS[dkey]); + }); + dialects.forEach((dialect) => { + Object.entries(dialect).forEach(([key, value]) => { + if (value === null) value = "all"; + else if (value === true) value = "Y"; + else if (value === false) value = "-"; + else if (Array.isArray(value)) + value = value.length; + if (!array[key]) array[key] = []; + array[key].push(value); + }); + }); + Object.entries(array).forEach(([key, arr]) => { + var s = rpad(key, 30) + "|"; + s += (arr as []).map((val) => rpad(val, 9)).join('|'); + console.log(s); + }); + process.exit(0); +} var readline = require('readline'); var rl = readline.createInterface({ @@ -28,6 +55,8 @@ for (var i=0; i stmt.command == 'DATA').forEach((datastmt) => { + this.label2dataptr[datastmt.$loc.label] = this.datums.length; (datastmt as basic.DATA_Statement).datums.forEach(datum => { this.curpc = datastmt.$loc.offset; // for error reporting - this.label2dataptr[datastmt.$loc.label] = this.datums.length; this.datums.push(datum); }); }); @@ -409,6 +409,7 @@ export class BASICRuntime { this.checkFuncArgs(expr, this.builtins[expr.name]); s += `this.builtins.${expr.name}(${jsargs})`; } else if (expr.args) { + // get array slice (HP BASIC) if (this.opts.arraysContainChars && expr.name.endsWith('$')) s += `this.MID$(this.vars.${expr.name}, ${jsargs})`; else @@ -436,9 +437,14 @@ export class BASICRuntime { if (expr.name.startsWith("FN") || this.builtins[expr.name]) this.runtimeError(`I can't call a function here.`); // is it a subscript? if (expr.args) { - s += this.expr2js(expr, {novalid:true}); // check array bounds - s += `;this.getArray(${qname}, ${expr.args.length})`; - s += expr.args.map((arg) => '[this.ROUND('+this.expr2js(arg, opts)+')]').join(''); + // set array slice (HP BASIC) + if (this.opts.arraysContainChars && expr.name.endsWith('$')) { + this.runtimeError(`I can't set array slices via this command yet.`); + } else { + s += this.expr2js(expr, {novalid:true}); // check array bounds + s += `;this.getArray(${qname}, ${expr.args.length})`; + s += expr.args.map((arg) => '[this.ROUND('+this.expr2js(arg, opts)+')]').join(''); + } } else { // just a variable s = `this.vars.${expr.name}`; } @@ -664,7 +670,6 @@ export class BASICRuntime { } do__LET(stmt : basic.LET_Statement) { - var lexpr = this.assign2js(stmt.lexpr); var right = this.expr2js(stmt.right); // HP BASIC string-slice syntax? if (this.opts.arraysContainChars && stmt.lexpr.args && stmt.lexpr.name.endsWith('$')) { @@ -674,6 +679,7 @@ export class BASICRuntime { console.log(s); return s; } else { + var lexpr = this.assign2js(stmt.lexpr); return `${lexpr} = this.assign(${JSON.stringify(stmt.lexpr.name)}, ${right});`; } } diff --git a/src/platform/basic.ts b/src/platform/basic.ts index 61cc8d3d..b3cce101 100644 --- a/src/platform/basic.ts +++ b/src/platform/basic.ts @@ -83,8 +83,9 @@ class BASICPlatform implements Platform { if (this.tty.isBusy()) return; var ips = this.program.opts.commandsPerSec || 1000; this.animcount += ips / 60; - while (!this.runtime.exited && this.animcount-- > 0) { - this.advance(); + while (this.runtime.running && this.animcount-- > 0) { + if (!this.advance()) + break; } } @@ -194,6 +195,9 @@ class BASICPlatform implements Platform { return o.toString(); } } + showHelp(tool:string, ident:string) { + window.open("https://8bitworkshop.com/blog/platforms/basic/", "_help"); + } // TODO: debugging (get running state, etc)