basic: help, dialect info, fixed advance() issue, slice = bug, GOTO ref fix, RESTORE fix

This commit is contained in:
Steven Hugg 2020-08-14 09:26:43 -05:00
parent b2cb2ec27f
commit 2cac077735
4 changed files with 64 additions and 15 deletions

View File

@ -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,

View File

@ -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<BASICOptions>();
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<args.length; i++) {
runtime.trace = true;
else if (args[i] == '-d')
parser.opts = DIALECTS[args[++i]] || Error('no such dialect');
else if (args[i] == '--dialects')
dumpDialectInfo();
else
filename = args[i];
}

View File

@ -121,9 +121,9 @@ export class BASICRuntime {
});
// parse DATA literals
this.allstmts.filter((stmt) => 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});`;
}
}

View File

@ -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)