1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-06-26 21:29:33 +00:00

basic: dialect stuff, error checking (44, 45, 68)

This commit is contained in:
Steven Hugg 2020-08-08 20:25:58 -05:00
parent bbae87269f
commit a1efa8eebd
2 changed files with 36 additions and 17 deletions

View File

@ -400,10 +400,7 @@ export class BASICParser {
if (stmt) stmt.$loc = { line: cmdtok.$loc.line, start: cmdtok.$loc.start, end: this.peekToken().$loc.start }; if (stmt) stmt.$loc = { line: cmdtok.$loc.line, start: cmdtok.$loc.start, end: this.peekToken().$loc.start };
return stmt; return stmt;
} }
parseVarOrIndexedOrFunc(): IndOp { parseVarSubscriptOrFunc(): IndOp {
return this.parseVarOrIndexed();
}
parseVarOrIndexed(): IndOp {
var tok = this.consumeToken(); var tok = this.consumeToken();
switch (tok.type) { switch (tok.type) {
case TokenType.Ident: case TokenType.Ident:
@ -412,27 +409,34 @@ export class BASICParser {
if (this.peekToken().str == '(') { if (this.peekToken().str == '(') {
this.expectToken('('); this.expectToken('(');
args = this.parseExprList(); args = this.parseExprList();
if (args && args.length > this.opts.maxArguments)
this.compileError(`There can be no more than ${this.opts.maxArguments} arguments to a function or subscript.`);
this.expectToken(')'); this.expectToken(')');
} }
return { name: tok.str, args: args, $loc: tok.$loc }; return { name: tok.str, args: args, $loc: tok.$loc };
default: default:
this.compileError("Expected variable or array index"); this.compileError(`There should be a variable name here.`);
break; break;
} }
} }
parseLexpr(): IndOp {
var lexpr = this.parseVarSubscriptOrFunc();
this.validateVarName(lexpr);
return lexpr;
}
parseList<T>(parseFunc:()=>T, delim:string): T[] { parseList<T>(parseFunc:()=>T, delim:string): T[] {
var sep; var sep;
var list = []; var list = [];
do { do {
var el = parseFunc.bind(this)() var el = parseFunc.bind(this)(); // call parse function
if (el != null) list.push(el); if (el != null) list.push(el); // add parsed element to list
sep = this.consumeToken(); sep = this.consumeToken(); // consume seperator token
} while (sep.str == delim); } while (sep.str == delim);
this.pushbackToken(sep); this.pushbackToken(sep);
return list; return list;
} }
parseLexprList(): IndOp[] { parseLexprList(): IndOp[] {
var list = this.parseList(this.parseVarOrIndexed, ','); var list = this.parseList(this.parseLexpr, ',');
list.forEach((lexpr) => this.decls[lexpr.name] = this.lasttoken.$loc); list.forEach((lexpr) => this.decls[lexpr.name] = this.lasttoken.$loc);
return list; return list;
} }
@ -469,7 +473,7 @@ export class BASICParser {
return { op: 'lnot', expr: expr }; return { op: 'lnot', expr: expr };
} else { } else {
this.pushbackToken(tok); this.pushbackToken(tok);
return this.parseVarOrIndexedOrFunc(); return this.parseVarSubscriptOrFunc();
} }
case TokenType.Operator: case TokenType.Operator:
if (tok.str == '(') { if (tok.str == '(') {
@ -515,11 +519,19 @@ export class BASICParser {
parseExpr(): Expr { parseExpr(): Expr {
return this.parseExpr1(this.parsePrimary(), 0); return this.parseExpr1(this.parsePrimary(), 0);
} }
validateVarName(lexpr: IndOp) {
if (this.opts.strictVarNames) {
if (lexpr.args == null && !/^[A-Z][0-9]?[$]?$/.test(lexpr.name))
this.dialectError(`variable names other than a letter followed by an optional digit`);
if (lexpr.args != null && !/^[A-Z]?[$]?$/.test(lexpr.name))
this.dialectError(`array names other than a single letter`);
}
}
//// STATEMENTS //// STATEMENTS
stmt__LET(): LET_Statement { stmt__LET(): LET_Statement {
var lexpr = this.parseVarOrIndexed(); var lexpr = this.parseLexpr();
this.expectToken("="); this.expectToken("=");
this.decls[lexpr.name] = this.lasttoken.$loc; this.decls[lexpr.name] = this.lasttoken.$loc;
var right = this.parseExpr(); var right = this.parseExpr();
@ -569,7 +581,7 @@ export class BASICParser {
return { command: "IF", cond: cond }; return { command: "IF", cond: cond };
} }
stmt__FOR() : FOR_Statement { stmt__FOR() : FOR_Statement {
var lexpr = this.parseVarOrIndexed(); // TODO: parseNumVar() var lexpr = this.parseLexpr(); // TODO: parseNumVar()
this.expectToken('='); this.expectToken('=');
var init = this.parseExpr(); var init = this.parseExpr();
this.expectToken('TO'); this.expectToken('TO');
@ -588,7 +600,14 @@ export class BASICParser {
return { command:'NEXT', lexpr:lexpr }; return { command:'NEXT', lexpr:lexpr };
} }
stmt__DIM() : DIM_Statement { stmt__DIM() : DIM_Statement {
return { command:'DIM', args:this.parseLexprList() }; var lexprs = this.parseLexprList();
lexprs.forEach((arr) => {
if (arr.args == null || arr.args.length == 0)
this.compileError(`An array defined by DIM must have at least one dimension.`)
else if (arr.args.length > this.opts.maxDimensions)
this.dialectError(`more than ${this.opts.maxDimensions} dimensional arrays`);
});
return { command:'DIM', args:lexprs };
} }
stmt__INPUT() : INPUT_Statement { stmt__INPUT() : INPUT_Statement {
var prompt = this.consumeToken(); var prompt = this.consumeToken();
@ -627,7 +646,7 @@ export class BASICParser {
return { command:'ONGOTO', expr:expr, labels:labels }; return { command:'ONGOTO', expr:expr, labels:labels };
} }
stmt__DEF() : DEF_Statement { stmt__DEF() : DEF_Statement {
var lexpr = this.parseVarOrIndexed(); var lexpr = this.parseVarSubscriptOrFunc();
if (!lexpr.name.startsWith('FN')) this.compileError(`Functions defined with DEF must begin with the letters "FN".`) if (!lexpr.name.startsWith('FN')) this.compileError(`Functions defined with DEF must begin with the letters "FN".`)
this.expectToken("="); this.expectToken("=");
this.decls[lexpr.name] = this.lasttoken.$loc; this.decls[lexpr.name] = this.lasttoken.$loc;

View File

@ -358,11 +358,11 @@ export class BASICRuntime {
getArray(name: string, order: number) : [] { getArray(name: string, order: number) : [] {
if (!this.arrays[name]) { if (!this.arrays[name]) {
if (order == 1) if (order == 1)
this.dimArray(name, 11); this.dimArray(name, this.program.opts.defaultArraySize);
else if (order == 2) else if (order == 2)
this.dimArray(name, 11, 11); this.dimArray(name, this.program.opts.defaultArraySize, this.program.opts.defaultArraySize);
else else
this.runtimeError(`I only support arrays of one or two dimensions.`) this.runtimeError(`I only support arrays of one or two dimensions.`); // TODO
} }
return this.arrays[name]; return this.arrays[name];
} }