basic: fixed NEXT, expectTokens()

This commit is contained in:
Steven Hugg 2020-08-12 10:11:10 -05:00
parent e962404c2f
commit 8fdd958859
3 changed files with 20 additions and 7 deletions

View File

@ -31,6 +31,7 @@ export interface BASICOptions {
numericPadding : boolean; // " " or "-" before and " " after numbers?
// CONTROL FLOW
testInitialFor : boolean; // can we skip a NEXT statement? (can't interleave tho)
optionalNextVar : boolean; // can do NEXT without variable
ifElse : boolean; // IF...ELSE construct
// MISC
commandsPerSec? : number; // how many commands per second?
@ -290,7 +291,7 @@ export class BASICParser {
}
compileError(msg: string, loc?: SourceLocation) {
if (!loc) loc = this.peekToken().$loc;
this.errors.push({path:loc.path, line:loc.line, label:loc.label, start:loc.start, end:loc.end, msg:msg});
this.errors.push({path:loc.path, line:loc.line, label:this.curlabel, start:loc.start, end:loc.end, msg:msg});
throw new CompileError(`${msg} (line ${loc.line})`); // TODO: label too?
}
dialectError(what: string, loc?: SourceLocation) {
@ -308,6 +309,14 @@ export class BASICParser {
}
return tok;
}
expectTokens(strlist: string[], msg?: string) : Token {
var tok = this.consumeToken();
var tokstr = tok.str;
if (strlist.indexOf(tokstr) < 0) {
this.compileError(msg || `There should be one of "${strlist}" here.`);
}
return tok;
}
peekToken(): Token {
var tok = this.tokens[0];
return tok ? tok : this.eol;
@ -654,11 +663,10 @@ export class BASICParser {
var cond = this.parseExpr();
var iftrue: Statement[];
// we accept GOTO or THEN if line number provided
if (this.peekToken().str == 'GOTO') this.consumeToken();
else this.expectToken('THEN');
var thengoto = this.expectTokens(['THEN','GOTO']);
var lineno = this.peekToken();
// assume GOTO if number given after THEN
if (lineno.type == TokenType.Int) {
if (lineno.type == TokenType.Int && thengoto.str == 'THEN') {
this.pushbackToken({type:TokenType.Ident, str:'GOTO', $loc:lineno.$loc});
}
// add fake ":"
@ -709,7 +717,7 @@ export class BASICParser {
var prompt = this.consumeToken();
var promptstr;
if (prompt.type == TokenType.String) {
this.expectToken(';');
this.expectTokens([';', ',']);
promptstr = stripQuotes(prompt.str);
} else {
this.pushbackToken(prompt);
@ -884,6 +892,7 @@ export const ECMA55_MINIMAL : BASICOptions = {
numericPadding : true,
checkOverflow : true,
testInitialFor : true,
optionalNextVar : false,
ifElse : false,
bitwiseLogic : false,
}
@ -917,6 +926,7 @@ export const BASICODE : BASICOptions = {
numericPadding : true,
checkOverflow : true,
testInitialFor : true,
optionalNextVar : false,
ifElse : false,
bitwiseLogic : false,
}
@ -952,6 +962,7 @@ export const ALTAIR_BASIC41 : BASICOptions = {
numericPadding : true,
checkOverflow : true,
testInitialFor : false,
optionalNextVar : true,
//multipleNextVars : true, // TODO: not supported
ifElse : true,
bitwiseLogic : true,
@ -994,6 +1005,7 @@ export const APPLESOFT_BASIC : BASICOptions = {
numericPadding : false,
checkOverflow : true,
testInitialFor : false,
optionalNextVar : true,
ifElse : false,
bitwiseLogic : false,
}
@ -1023,6 +1035,7 @@ export const MODERN_BASIC : BASICOptions = {
numericPadding : false,
checkOverflow : true,
testInitialFor : true,
optionalNextVar : true,
ifElse : true,
bitwiseLogic : true,
}

View File

@ -423,7 +423,7 @@ export class BASICRuntime {
}
nextForLoop(name) {
var fl = this.forLoops[name];
var fl = this.forLoops[name || (this.opts.optionalNextVar && this.topForLoopName)];
if (!fl) this.runtimeError(`I couldn't find a FOR for this NEXT.`)
fl.$next(name);
}

View File

@ -179,7 +179,7 @@ class BASICPlatform implements Platform {
ForLoops: this.runtime.forLoops,
ReturnStack: this.runtime.returnStack,
NextDatum: this.runtime.datums[this.runtime.dataptr],
Dialect: this.runtime.opts,
Options: this.runtime.opts,
Internals: this.runtime,
}
}