mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-13 16:04:05 +09:00
basic: more debuggable property names and broke PRINT statement
This commit is contained in:
@@ -44,7 +44,7 @@ lang.refError = function(line, obj) {
|
|||||||
};
|
};
|
||||||
lang.nowhereToReturn = function(line) { return "RETURN without GOSUB in " + line; };
|
lang.nowhereToReturn = function(line) { return "RETURN without GOSUB in " + line; };
|
||||||
lang.errorinline = function(line, stmt, errobj) {
|
lang.errorinline = function(line, stmt, errobj) {
|
||||||
return "Error on statement \""+stmt+"\": " + errobj;
|
return 'Error'+((line !== undefined) ? (" in "+line) : "")+' on statement "'+stmt+'": '+errobj;
|
||||||
};
|
};
|
||||||
lang.parserError = function(line, errorobj) {
|
lang.parserError = function(line, errorobj) {
|
||||||
return "Parser error in " + line + ": " + errorobj;
|
return "Parser error in " + line + ": " + errorobj;
|
||||||
@@ -109,7 +109,20 @@ fs.write = function(string) {
|
|||||||
Object.freeze(fs);
|
Object.freeze(fs);
|
||||||
|
|
||||||
let getUsedMemSize = function() {
|
let getUsedMemSize = function() {
|
||||||
return cmdbufMemFootPrint; // + array's dimsize * 8 + variables' sizeof literal + functions' expression length
|
let varsMemSize = 0;
|
||||||
|
|
||||||
|
Object.entries(bStatus.vars).forEach(function(pair,i) {
|
||||||
|
let object = pair[1];
|
||||||
|
|
||||||
|
if (Array.isArray(object)) {
|
||||||
|
// TODO test 1-D array
|
||||||
|
varsMemSize += object.length * 8;
|
||||||
|
}
|
||||||
|
else if (!isNaN(object)) varsMemSize += 8;
|
||||||
|
else if (typeof object === "string" || object instanceof String) varsMemSize += object.length;
|
||||||
|
else varsMemSize += 1;
|
||||||
|
});
|
||||||
|
return varsMemSize + cmdbufMemFootPrint; // + array's dimsize * 8 + variables' sizeof literal + functions' expression length
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -121,7 +134,7 @@ let reLineNum = /^[0-9]+ /;
|
|||||||
|
|
||||||
// must match partial
|
// must match partial
|
||||||
let reNumber = /([0-9]*[.][0-9]+[eE]*[\-+0-9]*[fF]*|[0-9]+[.eEfF][0-9+\-]*[fF]?)|([0-9_]+)|(0[Xx][0-9A-Fa-f_]+)|(0[Bb][01_]+)/;
|
let reNumber = /([0-9]*[.][0-9]+[eE]*[\-+0-9]*[fF]*|[0-9]+[.eEfF][0-9+\-]*[fF]?)|([0-9_]+)|(0[Xx][0-9A-Fa-f_]+)|(0[Bb][01_]+)/;
|
||||||
let reOps = /\^|;|\*|\/|\+|\-|[<>=]{1,2}/;
|
//let reOps = /\^|;|\*|\/|\+|\-|[<>=]{1,2}/;
|
||||||
|
|
||||||
let reNum = /[0-9]+/;
|
let reNum = /[0-9]+/;
|
||||||
let tbasexit = false;
|
let tbasexit = false;
|
||||||
@@ -130,9 +143,14 @@ println("Terran BASIC 1.0 "+vmemsize+" bytes free");
|
|||||||
println(prompt);
|
println(prompt);
|
||||||
|
|
||||||
// variable object constructor
|
// variable object constructor
|
||||||
|
/** variable object constructor
|
||||||
|
* @param literal Javascript object or primitive
|
||||||
|
* @type derived from parseSigil or JStoBASICtype
|
||||||
|
* @see bStatus.builtin["="]
|
||||||
|
*/
|
||||||
let BasicVar = function(literal, type) {
|
let BasicVar = function(literal, type) {
|
||||||
this.literal = literal;
|
this.bvLiteral = literal;
|
||||||
this.type = type;
|
this.bvType = type;
|
||||||
}
|
}
|
||||||
// DEFUN (GW-BASIC equiv. of DEF FN) constructor
|
// DEFUN (GW-BASIC equiv. of DEF FN) constructor
|
||||||
let BasicFun = function(params, expression) {
|
let BasicFun = function(params, expression) {
|
||||||
@@ -140,7 +158,7 @@ let BasicFun = function(params, expression) {
|
|||||||
this.expression = expression;
|
this.expression = expression;
|
||||||
}
|
}
|
||||||
// DIM (array) constructor
|
// DIM (array) constructor
|
||||||
let BasicArr = function() {
|
/*let BasicArr = function() {
|
||||||
var args = Array.from(arguments);
|
var args = Array.from(arguments);
|
||||||
if (args.length == 1)
|
if (args.length == 1)
|
||||||
throw lang.syntaxfehler(args[0]);
|
throw lang.syntaxfehler(args[0]);
|
||||||
@@ -161,29 +179,29 @@ let BasicArr = function() {
|
|||||||
this.array = a;
|
this.array = a;
|
||||||
this.dimsize = dimsize;
|
this.dimsize = dimsize;
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
// Abstract Syntax Tree
|
// Abstract Syntax Tree
|
||||||
// creates empty tree node
|
// creates empty tree node
|
||||||
let BasicAST = function() {
|
let BasicAST = function() {
|
||||||
this.lnum = 0;
|
this.astLnum = 0;
|
||||||
this.depth = 0;
|
this.astDepth = 0;
|
||||||
this.leaves = [];
|
this.astLeaves = [];
|
||||||
this.seps = [];
|
this.astSeps = [];
|
||||||
this.value = undefined;
|
this.astValue = undefined;
|
||||||
this.type = "null"; // literal, operator, string, number, array, function, null
|
this.astType = "null"; // literal, operator, string, number, array, function, null
|
||||||
|
|
||||||
this.toString = function() {
|
this.toString = function() {
|
||||||
var sb = "";
|
var sb = "";
|
||||||
var marker = ("literal" == this.type) ? "i" : ("operator" == this.type) ? "+" : "f";
|
var marker = ("literal" == this.astTpe) ? "i" : ("operator" == this.astType) ? "+" : "f";
|
||||||
sb += "| ".repeat(this.depth) + marker+" Line "+this.lnum+" ("+this.type+")\n";
|
sb += "| ".repeat(this.astDepth) + marker+" Line "+this.astLnum+" ("+this.astType+")\n";
|
||||||
sb += "| ".repeat(this.depth+1) + "leaves: "+(this.leaves.length)+"\n";
|
sb += "| ".repeat(this.astDepth+1) + "leaves: "+(this.astLeaves.length)+"\n";
|
||||||
sb += "| ".repeat(this.depth+1) + "value: "+this.value+" (type: "+typeof this.value+")\n";
|
sb += "| ".repeat(this.astDepth+1) + "value: "+this.astValue+" (type: "+typeof this.astValue+")\n";
|
||||||
for (var k = 0; k < this.leaves.length; k++) {
|
for (var k = 0; k < this.astLeaves.length; k++) {
|
||||||
if (k > 0)
|
if (k > 0)
|
||||||
sb += "| ".repeat(this.depth+1) + " " + this.seps[k - 1] + "\n";
|
sb += "| ".repeat(this.astDepth+1) + " " + this.astSeps[k - 1] + "\n";
|
||||||
sb += this.leaves[k].toString(); + "\n";
|
sb += this.astLeaves[k].toString(); + "\n";
|
||||||
}
|
}
|
||||||
sb += "| ".repeat(this.depth) + "`-----------------\n";
|
sb += "| ".repeat(this.astDepth) + "`-----------------\n";
|
||||||
return sb;
|
return sb;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -198,23 +216,23 @@ let parseSigil = function(s) {
|
|||||||
|
|
||||||
return {name:(rettype === undefined) ? s.toUpperCase() : s.substring(0, s.length - 1).toUpperCase(), type:rettype};
|
return {name:(rettype === undefined) ? s.toUpperCase() : s.substring(0, s.length - 1).toUpperCase(), type:rettype};
|
||||||
}
|
}
|
||||||
|
let literalTypes = ["string", "number", "bool", "array"];
|
||||||
/*
|
/*
|
||||||
@param variable object in following structure: {type: (String), value: (String}. The type is defined in BasicAST.
|
@param variable SyntaxTreeReturnObj, of which the 'troType' is defined in BasicAST.
|
||||||
@return a value, if the input type if string or number, its literal value will be returned. Otherwise will search the
|
@return a value, if the input type if string or number, its literal value will be returned. Otherwise will search the
|
||||||
BASIC variable table and return the literal value of the BasicVar; undefined will be returned if no such var exists.
|
BASIC variable table and return the literal value of the BasicVar; undefined will be returned if no such var exists.
|
||||||
*/
|
*/
|
||||||
let literalTypes = ["string", "number", "bool", "array"];
|
|
||||||
let resolve = function(variable) {
|
let resolve = function(variable) {
|
||||||
if (literalTypes.includes(variable.type))
|
if (literalTypes.includes(variable.troType))
|
||||||
return variable.value;
|
return variable.troValue;
|
||||||
else if (variable.type == "literal") {
|
else if (variable.troType == "literal") {
|
||||||
var basicvar = bStatus.vars[parseSigil(variable.value).name];
|
var basicVar = bStatus.vars[parseSigil(variable.troValue).name];
|
||||||
return (basicvar !== undefined) ? basicvar.literal : undefined;
|
return (basicVar !== undefined) ? basicVar.bvLiteral : undefined;
|
||||||
}
|
}
|
||||||
else if (variable.type == "null")
|
else if (variable.troType == "null")
|
||||||
return undefined;
|
return undefined;
|
||||||
else
|
else
|
||||||
throw "BasicIntpError: unknown variable with type "+variable.type+", with value "+variable.value
|
throw "BasicIntpError: unknown variable with type "+variable.troType+", with value "+variable.troValue
|
||||||
}
|
}
|
||||||
let oneArg = function(lnum, args, action) {
|
let oneArg = function(lnum, args, action) {
|
||||||
if (args.length != 1) throw lang.syntaxfehler(lnum, args.length + " arguments were given");
|
if (args.length != 1) throw lang.syntaxfehler(lnum, args.length + " arguments were given");
|
||||||
@@ -273,21 +291,28 @@ let threeArgNum = function(lnum, args, action) {
|
|||||||
let bStatus = {};
|
let bStatus = {};
|
||||||
bStatus.gosubStack = [];
|
bStatus.gosubStack = [];
|
||||||
bStatus.forStack = {};
|
bStatus.forStack = {};
|
||||||
bStatus.vars = {};
|
bStatus.vars = {}; // contains instances of BasicVars
|
||||||
bStatus.defuns = {};
|
bStatus.defuns = {};
|
||||||
bStatus.rnd = 0; // stores mantissa (23 bits long) of single precision floating point number
|
bStatus.rnd = 0; // stores mantissa (23 bits long) of single precision floating point number
|
||||||
/*
|
/*
|
||||||
@param lnum line number
|
@param lnum line number
|
||||||
@param args instance of the SyntaxTreeReturnObj
|
@param args instance of the SyntaxTreeReturnObj
|
||||||
*/
|
*/
|
||||||
|
bStatus.getArrayIndexFun = function(lnum, array) {
|
||||||
|
return function(lnum, args) {
|
||||||
|
return "test lol";
|
||||||
|
};
|
||||||
|
};
|
||||||
bStatus.builtin = {
|
bStatus.builtin = {
|
||||||
"REM" : function(lnum, args) {},
|
"REM" : function(lnum, args) {},
|
||||||
"=" : function(lnum, args) {
|
"=" : function(lnum, args) {
|
||||||
if (args.length != 2) throw lang.syntaxfehler(lnum, args.length + " arguments were given");
|
if (args.length != 2) throw lang.syntaxfehler(lnum, args.length + " arguments were given");
|
||||||
var parsed = parseSigil(args[0].value); var rh = resolve(args[1]);
|
var sigil = parseSigil(args[0].troValue);
|
||||||
if (rh === undefined) throw lang.refError(lnum, args[1].value);
|
var rh = resolve(args[1]);
|
||||||
|
if (rh === undefined) throw lang.refError(lnum, args[1].troValue);
|
||||||
|
var type = sigil.type || JStoBASICtype(rh)
|
||||||
|
|
||||||
bStatus.vars[parsed.name] = new BasicVar(rh, (parsed.type === undefined) ? "float" : parsed.type);
|
bStatus.vars[sigil.name] = new BasicVar(rh, type);
|
||||||
},
|
},
|
||||||
"==" : function(lnum, args) {
|
"==" : function(lnum, args) {
|
||||||
return twoArg(lnum, args, function(lh, rh) { return lh == rh; });
|
return twoArg(lnum, args, function(lh, rh) { return lh == rh; });
|
||||||
@@ -368,6 +393,7 @@ bStatus.builtin = {
|
|||||||
a.push(k);
|
a.push(k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return a;
|
return a;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -387,6 +413,8 @@ bStatus.builtin = {
|
|||||||
return a;
|
return a;
|
||||||
},
|
},
|
||||||
"PRINT" : function(lnum, args, seps) {
|
"PRINT" : function(lnum, args, seps) {
|
||||||
|
serial.printerr("PRINT args = "+args);
|
||||||
|
serial.printerr("PRINT seps = "+seps);
|
||||||
//serial.println("BASIC func: PRINT -- args="+(args.map(function(it) { return it.type+" "+it.value; })).join(", "));
|
//serial.println("BASIC func: PRINT -- args="+(args.map(function(it) { return it.type+" "+it.value; })).join(", "));
|
||||||
|
|
||||||
if (args.length == 0)
|
if (args.length == 0)
|
||||||
@@ -478,7 +506,7 @@ bStatus.builtin = {
|
|||||||
return argum[0] || argum[1];
|
return argum[0] || argum[1];
|
||||||
},
|
},
|
||||||
"RND" : function(lnum, args) {
|
"RND" : function(lnum, args) {
|
||||||
if (!(args.length > 0 && args[0].value === 0))
|
if (!(args.length > 0 && args[0].troValue === 0))
|
||||||
bStatus.rnd = (bStatus.rnd * 214013 + 2531011) % 16777216; // GW-BASIC does this
|
bStatus.rnd = (bStatus.rnd * 214013 + 2531011) % 16777216; // GW-BASIC does this
|
||||||
|
|
||||||
|
|
||||||
@@ -957,6 +985,9 @@ bF._parserElaboration = function(lnum, tokens, states) {
|
|||||||
k += 1;
|
k += 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* @returns BasicAST
|
||||||
|
*/
|
||||||
bF._parseTokens = function(lnum, tokens, states, recDepth) {
|
bF._parseTokens = function(lnum, tokens, states, recDepth) {
|
||||||
// DO NOT PERFORM SEMANTIC ANALYSIS HERE
|
// DO NOT PERFORM SEMANTIC ANALYSIS HERE
|
||||||
// at this point you can't (and shouldn't) distinguish whether or not defuns/variables are previously declared
|
// at this point you can't (and shouldn't) distinguish whether or not defuns/variables are previously declared
|
||||||
@@ -1028,7 +1059,7 @@ for input "DEFUN sinc(x) = sin(x) / x"
|
|||||||
"quote" == state || "number" == state || "bool" == state || "literal" == state;
|
"quote" == state || "number" == state || "bool" == state || "literal" == state;
|
||||||
}
|
}
|
||||||
|
|
||||||
var _debugSyntaxAnalysis = true;
|
var _debugSyntaxAnalysis = false;
|
||||||
|
|
||||||
if (_debugSyntaxAnalysis) serial.println("@@ SYNTAX ANALYSIS @@");
|
if (_debugSyntaxAnalysis) serial.println("@@ SYNTAX ANALYSIS @@");
|
||||||
|
|
||||||
@@ -1046,8 +1077,8 @@ for input "DEFUN sinc(x) = sin(x) / x"
|
|||||||
let k;
|
let k;
|
||||||
let headWord = tokens[0].toLowerCase();
|
let headWord = tokens[0].toLowerCase();
|
||||||
let treeHead = new BasicAST();
|
let treeHead = new BasicAST();
|
||||||
treeHead.depth = recDepth;
|
treeHead.astDepth = recDepth;
|
||||||
treeHead.lnum = lnum;
|
treeHead.astLnum = lnum;
|
||||||
|
|
||||||
// TODO ability to parse arbitrary parentheses
|
// TODO ability to parse arbitrary parentheses
|
||||||
// test string: print((minus(plus(3,2),times(8,7))))
|
// test string: print((minus(plus(3,2),times(8,7))))
|
||||||
@@ -1056,8 +1087,8 @@ for input "DEFUN sinc(x) = sin(x) / x"
|
|||||||
// LITERAL
|
// LITERAL
|
||||||
if (tokens.length == 1 && (isSemanticLiteral(tokens[0], states[0]))) {
|
if (tokens.length == 1 && (isSemanticLiteral(tokens[0], states[0]))) {
|
||||||
if (_debugSyntaxAnalysis) serial.println("literal/number: "+tokens[0]);
|
if (_debugSyntaxAnalysis) serial.println("literal/number: "+tokens[0]);
|
||||||
treeHead.value = ("quote" == states[0]) ? tokens[0] : tokens[0].toUpperCase();
|
treeHead.astValue = ("quote" == states[0]) ? tokens[0] : tokens[0].toUpperCase();
|
||||||
treeHead.type = ("quote" == states[0]) ? "string" : ("number" == states[0]) ? "number" : "literal";
|
treeHead.astType = ("quote" == states[0]) ? "string" : ("number" == states[0]) ? "number" : "literal";
|
||||||
}
|
}
|
||||||
else if (tokens[0].toUpperCase() == "IF" && states[0] != "quote") {
|
else if (tokens[0].toUpperCase() == "IF" && states[0] != "quote") {
|
||||||
// find ELSE and THEN
|
// find ELSE and THEN
|
||||||
@@ -1086,30 +1117,30 @@ for input "DEFUN sinc(x) = sin(x) / x"
|
|||||||
// generate tree
|
// generate tree
|
||||||
if (indexThen === undefined) throw lang.syntaxfehler(lnum);
|
if (indexThen === undefined) throw lang.syntaxfehler(lnum);
|
||||||
|
|
||||||
treeHead.value = "if";
|
treeHead.astValue = "if";
|
||||||
treeHead.type = "function";
|
treeHead.astType = "function";
|
||||||
treeHead.leaves[0] = bF._parseTokens(
|
treeHead.astLeaves[0] = bF._parseTokens(
|
||||||
lnum,
|
lnum,
|
||||||
tokens.slice(1, indexThen),
|
tokens.slice(1, indexThen),
|
||||||
states.slice(1, indexThen),
|
states.slice(1, indexThen),
|
||||||
recDepth + 1
|
recDepth + 1
|
||||||
);
|
);
|
||||||
if (!useGoto)
|
if (!useGoto)
|
||||||
treeHead.leaves[1] = bF._parseTokens(
|
treeHead.astLeaves[1] = bF._parseTokens(
|
||||||
lnum,
|
lnum,
|
||||||
tokens.slice(indexThen + 1, (indexElse !== undefined) ? indexElse : tokens.length),
|
tokens.slice(indexThen + 1, (indexElse !== undefined) ? indexElse : tokens.length),
|
||||||
states.slice(indexThen + 1, (indexElse !== undefined) ? indexElse : tokens.length),
|
states.slice(indexThen + 1, (indexElse !== undefined) ? indexElse : tokens.length),
|
||||||
recDepth + 1
|
recDepth + 1
|
||||||
);
|
);
|
||||||
else
|
else
|
||||||
treeHead.leaves[1] = bF._parseTokens(
|
treeHead.astLeaves[1] = bF._parseTokens(
|
||||||
lnum,
|
lnum,
|
||||||
[].concat("goto", tokens.slice(indexThen + 1, (indexElse !== undefined) ? indexElse : tokens.length)),
|
[].concat("goto", tokens.slice(indexThen + 1, (indexElse !== undefined) ? indexElse : tokens.length)),
|
||||||
[].concat("literal", states.slice(indexThen + 1, (indexElse !== undefined) ? indexElse : tokens.length)),
|
[].concat("literal", states.slice(indexThen + 1, (indexElse !== undefined) ? indexElse : tokens.length)),
|
||||||
recDepth + 1
|
recDepth + 1
|
||||||
);
|
);
|
||||||
if (indexElse !== undefined) {
|
if (indexElse !== undefined) {
|
||||||
treeHead.leaves[2] = bF._parseTokens(
|
treeHead.astLeaves[2] = bF._parseTokens(
|
||||||
lnum,
|
lnum,
|
||||||
tokens.slice(indexElse + 1, tokens.length),
|
tokens.slice(indexElse + 1, tokens.length),
|
||||||
states.slice(indexElse + 1, tokens.length),
|
states.slice(indexElse + 1, tokens.length),
|
||||||
@@ -1206,10 +1237,10 @@ for input "DEFUN sinc(x) = sin(x) / x"
|
|||||||
var substaL = states.slice(0, operatorPos);
|
var substaL = states.slice(0, operatorPos);
|
||||||
var substaR = states.slice(operatorPos + 1, tokens.length);
|
var substaR = states.slice(operatorPos + 1, tokens.length);
|
||||||
|
|
||||||
treeHead.value = topmostOp;
|
treeHead.astValue = topmostOp;
|
||||||
treeHead.type = "operator";
|
treeHead.astType = "operator";
|
||||||
treeHead.leaves[0] = bF._parseTokens(lnum, subtknL, substaL, recDepth + 1);
|
treeHead.astLeaves[0] = bF._parseTokens(lnum, subtknL, substaL, recDepth + 1);
|
||||||
treeHead.leaves[1] = bF._parseTokens(lnum, subtknR, substaR, recDepth + 1);
|
treeHead.astLeaves[1] = bF._parseTokens(lnum, subtknR, substaR, recDepth + 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (_debugSyntaxAnalysis) serial.println("re-parenthesising unary op");
|
if (_debugSyntaxAnalysis) serial.println("re-parenthesising unary op");
|
||||||
@@ -1233,9 +1264,9 @@ for input "DEFUN sinc(x) = sin(x) / x"
|
|||||||
else {
|
else {
|
||||||
if (_debugSyntaxAnalysis) serial.println("function call");
|
if (_debugSyntaxAnalysis) serial.println("function call");
|
||||||
var currentFunction = (states[0] == "paren") ? undefined : tokens[0];
|
var currentFunction = (states[0] == "paren") ? undefined : tokens[0];
|
||||||
treeHead.value = ("-" == currentFunction) ? "UNARYMINUS" : ("+" == currentFunction) ? "UNARYPLUS" : currentFunction;
|
treeHead.astValue = ("-" == currentFunction) ? "UNARYMINUS" : ("+" == currentFunction) ? "UNARYPLUS" : currentFunction;
|
||||||
treeHead.type = (currentFunction === undefined) ? "null" : "function";
|
treeHead.astType = (currentFunction === undefined) ? "null" : "function";
|
||||||
if (_debugSyntaxAnalysis) serial.println("function name: "+treeHead.value);
|
if (_debugSyntaxAnalysis) serial.println("function name: "+treeHead.astValue);
|
||||||
|
|
||||||
var leaves = [];
|
var leaves = [];
|
||||||
var seps = [];
|
var seps = [];
|
||||||
@@ -1272,8 +1303,8 @@ for input "DEFUN sinc(x) = sin(x) / x"
|
|||||||
separators.slice(1, separators.length - 1).forEach(function(v) { if (v !== undefined) seps.push(tokens[v]); });
|
separators.slice(1, separators.length - 1).forEach(function(v) { if (v !== undefined) seps.push(tokens[v]); });
|
||||||
}
|
}
|
||||||
else throw lang.syntaxfehler(lnum, lang.badFunctionCallFormat);
|
else throw lang.syntaxfehler(lnum, lang.badFunctionCallFormat);
|
||||||
treeHead.leaves = leaves;//.filter(function(__v) { return __v !== undefined; });
|
treeHead.astLeaves = leaves;//.filter(function(__v) { return __v !== undefined; });
|
||||||
treeHead.seps = seps;
|
treeHead.astSeps = seps;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1291,43 +1322,50 @@ let JStoBASICtype = function(object) {
|
|||||||
else throw "BasicIntpError: un-translatable object with typeof "+(typeof object)+"\n"+object;
|
else throw "BasicIntpError: un-translatable object with typeof "+(typeof object)+"\n"+object;
|
||||||
}
|
}
|
||||||
let SyntaxTreeReturnObj = function(type, value, nextLine) {
|
let SyntaxTreeReturnObj = function(type, value, nextLine) {
|
||||||
this.type = type;
|
this.troType = type;
|
||||||
this.value = value;
|
this.troValue = value;
|
||||||
this.nextLine = nextLine;
|
this.troNextLine = nextLine;
|
||||||
}
|
}
|
||||||
bF._gotoCmds = { GOTO:1, GOSUB:1 }; // put nonzero (truthy) value here
|
bF._gotoCmds = { GOTO:1, GOSUB:1 }; // put nonzero (truthy) value here
|
||||||
|
/**
|
||||||
|
* @param lnum line number of BASIC
|
||||||
|
* @param syntaxTree BasicAST
|
||||||
|
* @param recDepth recursion depth used internally
|
||||||
|
*
|
||||||
|
* @return syntaxTreeReturnObject if recursion is escaped
|
||||||
|
*/
|
||||||
bF._executeSyntaxTree = function(lnum, syntaxTree, recDepth) {
|
bF._executeSyntaxTree = function(lnum, syntaxTree, recDepth) {
|
||||||
var _debugExec = false;
|
var _debugExec = false;
|
||||||
var recWedge = "> ".repeat(recDepth);
|
var recWedge = "> ".repeat(recDepth);
|
||||||
|
|
||||||
if (_debugExec) serial.println(recWedge+"@@ EXECUTE @@");
|
if (_debugExec) serial.println(recWedge+"@@ EXECUTE @@");
|
||||||
|
|
||||||
if (syntaxTree === undefined || (recDepth == 0 && syntaxTree.value.toUpperCase() == "REM"))
|
if (syntaxTree === undefined || (recDepth == 0 && syntaxTree.astValue.toUpperCase() == "REM"))
|
||||||
return new SyntaxTreeReturnObj("null", undefined, lnum + 1);
|
return new SyntaxTreeReturnObj("null", undefined, lnum + 1);
|
||||||
else if (syntaxTree.type == "function" || syntaxTree.type == "operator") {
|
else if (syntaxTree.astType == "function" || syntaxTree.astType == "operator") {
|
||||||
if (_debugExec) serial.println(recWedge+"function|operator");
|
if (_debugExec) serial.println(recWedge+"function|operator");
|
||||||
if (_debugExec) serial.println(recWedge+syntaxTree.toString());
|
if (_debugExec) serial.println(recWedge+syntaxTree.toString());
|
||||||
var funcName = syntaxTree.value.toUpperCase();
|
var funcName = syntaxTree.astValue.toUpperCase();
|
||||||
var func = bStatus.builtin[funcName];
|
var func = bStatus.builtin[funcName];
|
||||||
|
|
||||||
if (funcName == "IF") {
|
if (funcName == "IF") {
|
||||||
if (syntaxTree.leaves.length != 2 && syntaxTree.leaves.length != 3) throw lang.syntaxfehler(lnum);
|
if (syntaxTree.astLeaves.length != 2 && syntaxTree.astLeaves.length != 3) throw lang.syntaxfehler(lnum);
|
||||||
var testedval = bF._executeSyntaxTree(lnum, syntaxTree.leaves[0], recDepth + 1);
|
var testedval = bF._executeSyntaxTree(lnum, syntaxTree.astLeaves[0], recDepth + 1);
|
||||||
|
|
||||||
if (_debugExec) {
|
if (_debugExec) {
|
||||||
serial.println(recWedge+"testedval:");
|
serial.println(recWedge+"testedval:");
|
||||||
serial.println(recWedge+"type="+testedval.type);
|
serial.println(recWedge+"type="+testedval.astType);
|
||||||
serial.println(recWedge+"value="+testedval.value);
|
serial.println(recWedge+"value="+testedval.astValue);
|
||||||
serial.println(recWedge+"nextLine="+testedval.nextLine);
|
serial.println(recWedge+"nextLine="+testedval.astNextLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var iftest = bStatus.builtin["TEST"](lnum, [testedval]);
|
var iftest = bStatus.builtin["TEST"](lnum, [testedval]);
|
||||||
|
|
||||||
if (!iftest && syntaxTree.leaves[2] !== undefined)
|
if (!iftest && syntaxTree.astLeaves[2] !== undefined)
|
||||||
return bF._executeSyntaxTree(lnum, syntaxTree.leaves[2], recDepth + 1);
|
return bF._executeSyntaxTree(lnum, syntaxTree.astLeaves[2], recDepth + 1);
|
||||||
else if (iftest)
|
else if (iftest)
|
||||||
return bF._executeSyntaxTree(lnum, syntaxTree.leaves[1], recDepth + 1);
|
return bF._executeSyntaxTree(lnum, syntaxTree.astLeaves[1], recDepth + 1);
|
||||||
else
|
else
|
||||||
return new SyntaxTreeReturnObj("null", undefined, lnum + 1);
|
return new SyntaxTreeReturnObj("null", undefined, lnum + 1);
|
||||||
}
|
}
|
||||||
@@ -1336,44 +1374,51 @@ bF._executeSyntaxTree = function(lnum, syntaxTree, recDepth) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var args = syntaxTree.leaves.map(function(it) { return bF._executeSyntaxTree(lnum, it, recDepth + 1); });
|
var args = syntaxTree.astLeaves.map(function(it) { return bF._executeSyntaxTree(lnum, it, recDepth + 1); });
|
||||||
|
|
||||||
if (_debugExec) {
|
if (_debugExec) {
|
||||||
serial.println(recWedge+"fn call name: "+funcName);
|
serial.println(recWedge+"fn call name: "+funcName);
|
||||||
serial.println(recWedge+"fn call args: "+(args.map(function(it) { return it.type+" "+it.value; })).join(", "));
|
serial.println(recWedge+"fn call args: "+(args.map(function(it) { return it.astType+" "+it.astValue; })).join(", "));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// func not in builtins (e.g. array access, user-defined function defuns)
|
||||||
if (func === undefined) {
|
if (func === undefined) {
|
||||||
serial.printerr(lang.syntaxfehler(lnum, funcName + " is not defined"));
|
let someVar = bStatus.vars[funcName];
|
||||||
throw lang.syntaxfehler(lnum, funcName + " is not defined");
|
if (someVar.astType != "array") {
|
||||||
}
|
serial.printerr(lang.syntaxfehler(lnum, funcName + " is not defined"));
|
||||||
else {
|
throw lang.syntaxfehler(lnum, funcName + " is not defined");
|
||||||
try {
|
}
|
||||||
var funcCallResult = func(lnum, args, syntaxTree.seps);
|
|
||||||
|
|
||||||
return new SyntaxTreeReturnObj(
|
// TODO calling from bStatus.defuns
|
||||||
JStoBASICtype(funcCallResult),
|
|
||||||
funcCallResult,
|
func = bStatus.getArrayIndexFun(lnum, someVar);
|
||||||
(bF._gotoCmds[funcName] !== undefined) ? funcCallResult : lnum + 1,
|
}
|
||||||
syntaxTree.seps
|
// call whatever the 'func' has whether it's builtin or we just made shit up right above
|
||||||
);
|
try {
|
||||||
}
|
var funcCallResult = func(lnum, args, syntaxTree.astSeps);
|
||||||
catch (eeeee) {
|
|
||||||
throw lang.errorinline(lnum, funcName, eeeee);
|
return new SyntaxTreeReturnObj(
|
||||||
}
|
JStoBASICtype(funcCallResult),
|
||||||
|
funcCallResult,
|
||||||
|
(bF._gotoCmds[funcName] !== undefined) ? funcCallResult : lnum + 1,
|
||||||
|
syntaxTree.astSeps
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch (eeeee) {
|
||||||
|
throw lang.errorinline(lnum, funcName, eeeee);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (syntaxTree.type == "number") {
|
else if (syntaxTree.astType == "number") {
|
||||||
if (_debugExec) serial.println(recWedge+"number");
|
if (_debugExec) serial.println(recWedge+"number");
|
||||||
return new SyntaxTreeReturnObj(syntaxTree.type, +(syntaxTree.value), lnum + 1);
|
return new SyntaxTreeReturnObj(syntaxTree.astType, +(syntaxTree.astValue), lnum + 1);
|
||||||
}
|
}
|
||||||
else if (syntaxTree.type == "string" || syntaxTree.type == "literal" || syntaxTree.type == "bool") {
|
else if (syntaxTree.astType == "string" || syntaxTree.astType == "literal" || syntaxTree.astType == "bool") {
|
||||||
if (_debugExec) serial.println(recWedge+"string|literal|bool");
|
if (_debugExec) serial.println(recWedge+"string|literal|bool");
|
||||||
return new SyntaxTreeReturnObj(syntaxTree.type, syntaxTree.value, lnum + 1);
|
return new SyntaxTreeReturnObj(syntaxTree.astType, syntaxTree.astValue, lnum + 1);
|
||||||
}
|
}
|
||||||
else if (syntaxTree.type == "null") {
|
else if (syntaxTree.astType == "null") {
|
||||||
return new bF._executeSyntaxTree(lnum, syntaxTree.leaves[0], recDepth + 1);
|
return new bF._executeSyntaxTree(lnum, syntaxTree.astLeaves[0], recDepth + 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
serial.println(recWedge+"Parse error in "+lnum);
|
serial.println(recWedge+"Parse error in "+lnum);
|
||||||
@@ -1383,7 +1428,7 @@ bF._executeSyntaxTree = function(lnum, syntaxTree, recDepth) {
|
|||||||
};
|
};
|
||||||
// @returns: line number for the next command, normally (lnum + 1); if GOTO or GOSUB was met, returns its line number
|
// @returns: line number for the next command, normally (lnum + 1); if GOTO or GOSUB was met, returns its line number
|
||||||
bF._interpretLine = function(lnum, cmd) {
|
bF._interpretLine = function(lnum, cmd) {
|
||||||
var _debugprintHighestLevel = true;
|
var _debugprintHighestLevel = false;
|
||||||
|
|
||||||
// TOKENISE
|
// TOKENISE
|
||||||
var tokenisedObject = bF._tokenise(lnum, cmd);
|
var tokenisedObject = bF._tokenise(lnum, cmd);
|
||||||
@@ -1402,7 +1447,7 @@ bF._interpretLine = function(lnum, cmd) {
|
|||||||
// EXECUTE
|
// EXECUTE
|
||||||
//try {
|
//try {
|
||||||
var execResult = bF._executeSyntaxTree(lnum, syntaxTree, 0);
|
var execResult = bF._executeSyntaxTree(lnum, syntaxTree, 0);
|
||||||
return execResult.nextLine;
|
return execResult.troNextLine;
|
||||||
//}
|
//}
|
||||||
//catch (e) {
|
//catch (e) {
|
||||||
// throw lang.parserError(lnum, e);
|
// throw lang.parserError(lnum, e);
|
||||||
|
|||||||
Reference in New Issue
Block a user