mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2025-02-07 04:30:46 +00:00
basic: help, dialect info, fixed advance() issue, slice = bug, GOTO ref fix, RESTORE fix
This commit is contained in:
parent
b2cb2ec27f
commit
2cac077735
@ -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,
|
||||
|
@ -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];
|
||||
}
|
||||
|
@ -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});`;
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user