mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-08 22:34:03 +09:00
unary plus/minus has seemingly correct precedence | POW op breaks parser
This commit is contained in:
@@ -286,7 +286,8 @@ basicFunctions._isSeparator = function(code) {
|
|||||||
};
|
};
|
||||||
basicFunctions._operatorPrecedence = {
|
basicFunctions._operatorPrecedence = {
|
||||||
// function call in itself has highest precedence
|
// function call in itself has highest precedence
|
||||||
"^":1,
|
"^":0,
|
||||||
|
// precedence of 1 are unary plus/minus which are pre-parenthesized
|
||||||
"*":2,"/":2,
|
"*":2,"/":2,
|
||||||
"MOD":3,
|
"MOD":3,
|
||||||
"+":4,"-":4,
|
"+":4,"-":4,
|
||||||
@@ -756,7 +757,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 = false;
|
var _debugSyntaxAnalysis = true;
|
||||||
|
|
||||||
if (_debugSyntaxAnalysis) println("@@ SYNTAX ANALYSIS @@");
|
if (_debugSyntaxAnalysis) println("@@ SYNTAX ANALYSIS @@");
|
||||||
|
|
||||||
@@ -883,7 +884,7 @@ for input "DEFUN sinc(x) = sin(x) / x"
|
|||||||
|
|
||||||
// if there is no paren or paren does NOT start index 1
|
// if there is no paren or paren does NOT start index 1
|
||||||
// e.g. negative three should NOT require to be written as "-(3)"
|
// e.g. negative three should NOT require to be written as "-(3)"
|
||||||
if ((parenStart > 1 || parenStart == -1) && (operatorPos != 1 && operatorPos != 0)) {
|
if ((parenStart > 1 || parenStart == -1) && (operatorPos != 1 && operatorPos != 0) && states[0] != "operator") {
|
||||||
// make a paren!
|
// make a paren!
|
||||||
tokens = [].concat(tokens[0], "(", tokens.slice(1, tokens.length), ")");
|
tokens = [].concat(tokens[0], "(", tokens.slice(1, tokens.length), ")");
|
||||||
states = [].concat(states[0], "paren", states.slice(1, states.length), "paren");
|
states = [].concat(states[0], "paren", states.slice(1, states.length), "paren");
|
||||||
@@ -925,23 +926,34 @@ for input "DEFUN sinc(x) = sin(x) / x"
|
|||||||
if (topmostOp !== undefined) {
|
if (topmostOp !== undefined) {
|
||||||
if (_debugSyntaxAnalysis) println("operator: "+topmostOp+", pos: "+operatorPos);
|
if (_debugSyntaxAnalysis) println("operator: "+topmostOp+", pos: "+operatorPos);
|
||||||
|
|
||||||
var subtknL = tokens.slice(0, operatorPos);
|
|
||||||
var subtknR = tokens.slice(operatorPos + 1, tokens.length);
|
|
||||||
var substaL = states.slice(0, operatorPos);
|
|
||||||
var substaR = states.slice(operatorPos + 1, tokens.length);
|
|
||||||
|
|
||||||
// BINARY_OP?
|
// BINARY_OP?
|
||||||
if (operatorPos > 0) {
|
if (operatorPos > 0) {
|
||||||
|
var subtknL = tokens.slice(0, operatorPos);
|
||||||
|
var subtknR = tokens.slice(operatorPos + 1, tokens.length);
|
||||||
|
var substaL = states.slice(0, operatorPos);
|
||||||
|
var substaR = states.slice(operatorPos + 1, tokens.length);
|
||||||
|
|
||||||
treeHead.value = topmostOp;
|
treeHead.value = topmostOp;
|
||||||
treeHead.type = "operator";
|
treeHead.type = "operator";
|
||||||
treeHead.leaves[0] = basicFunctions._parseTokens(lnum, subtknL, substaL, recDepth + 1);
|
treeHead.leaves[0] = basicFunctions._parseTokens(lnum, subtknL, substaL, recDepth + 1);
|
||||||
treeHead.leaves[1] = basicFunctions._parseTokens(lnum, subtknR, substaR, recDepth + 1);
|
treeHead.leaves[1] = basicFunctions._parseTokens(lnum, subtknR, substaR, recDepth + 1);
|
||||||
}
|
}
|
||||||
else { // TODO do I ever reach this branch?
|
else {
|
||||||
// this also takes care of nested unary ops (e.g. "- NOT 43")
|
if (_debugSyntaxAnalysis) println("re-parenthesising unary op");
|
||||||
treeHead.value = (topmostOp == "+") ? "UNARYPLUS" : (topmostOp == "-") ? "UNARYMINUS" : topmostOp;
|
|
||||||
treeHead.type = "operator";
|
// parenthesize the unary op
|
||||||
treeHead.leaves[0] = basicFunctions._parseTokens(lnum, subtknR, substaR, recDepth + 1);
|
var unaryParenEnd = 1;
|
||||||
|
while (unaryParenEnd < tokens.length) {
|
||||||
|
if (states[unaryParenEnd] == "operator" && basicFunctions._operatorPrecedence[tokens[unaryParenEnd]] > 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
unaryParenEnd += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var newTokens = [].concat("(", tokens.slice(0, unaryParenEnd), ")", tokens.slice(unaryParenEnd, tokens.length));
|
||||||
|
var newStates = [].concat("paren", states.slice(0, unaryParenEnd), "paren", states.slice(unaryParenEnd, tokens.length));
|
||||||
|
|
||||||
|
return basicFunctions._parseTokens(lnum, newTokens, newStates, recDepth + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// FUNCTION CALL
|
// FUNCTION CALL
|
||||||
@@ -954,36 +966,16 @@ for input "DEFUN sinc(x) = sin(x) / x"
|
|||||||
|
|
||||||
var leaves = [];
|
var leaves = [];
|
||||||
|
|
||||||
// if there is no paren or paren does NOT start index 1
|
// if there is no paren (this part deals with unary ops ONLY!)
|
||||||
// e.g. negative three should NOT require to be written as "-(3)"
|
if (parenStart == -1 && parenEnd == -1) {
|
||||||
/*if (parenStart > 1 || parenStart == -1) {
|
var subtkn = tokens.slice(1, tokens.length);
|
||||||
// make a paren!
|
var substa = states.slice(1, tokens.length);
|
||||||
tokens = [].concat(tokens[0], "(", tokens.slice(1, tokens.length), ")");
|
|
||||||
states = [].concat(states[0], "paren", states.slice(1, states.length), "paren");
|
|
||||||
parenStart = 1;
|
|
||||||
parenEnd = states.length - 1;
|
|
||||||
|
|
||||||
// get the position of parens and separators AGAIN
|
if (_debugSyntaxAnalysis) println("subtokenA: "+subtkn.join("/"));
|
||||||
for (k = 0; k < tokens.length; k++) {
|
|
||||||
if (tokens[k] == "(") {
|
|
||||||
parenDepth += 1;
|
|
||||||
if (parenDepth == 1) parenStart = k;
|
|
||||||
}
|
|
||||||
else if (tokens[k] == ")") {
|
|
||||||
if (parenDepth == 1) parenEnd = k;
|
|
||||||
parenDepth -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parenDepth == 1 && states[k] == "sep") {
|
leaves.push(basicFunctions._parseTokens(lnum, subtkn, substa, recDepth + 1))
|
||||||
separators.push(k);
|
}
|
||||||
}
|
else if (parenEnd > parenStart) {
|
||||||
}
|
|
||||||
|
|
||||||
if (_debugSyntaxAnalysis) println("inserting paren at right place");
|
|
||||||
if (_debugSyntaxAnalysis) println(tokens.join(","));
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if (parenEnd > parenStart) {
|
|
||||||
separators = [parenStart].concat(separators, [parenEnd]);
|
separators = [parenStart].concat(separators, [parenEnd]);
|
||||||
if (_debugSyntaxAnalysis) println("separators: "+separators.join(","));
|
if (_debugSyntaxAnalysis) println("separators: "+separators.join(","));
|
||||||
// recursively parse comma-separated arguments
|
// recursively parse comma-separated arguments
|
||||||
@@ -1049,6 +1041,9 @@ basicFunctions._executeSyntaxTree = function(lnum, syntaxTree, recDepth) {
|
|||||||
if (_debugExec) serial.println(recWedge+"string|operator");
|
if (_debugExec) serial.println(recWedge+"string|operator");
|
||||||
return { type:syntaxTree.type, value:syntaxTree.value };
|
return { type:syntaxTree.type, value:syntaxTree.value };
|
||||||
}
|
}
|
||||||
|
else if (syntaxTree.type == "null") {
|
||||||
|
return basicFunctions._executeSyntaxTree(lnum, syntaxTree.leaves[0], recDepth + 1);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
serial.println(recWedge+"Parse error in "+lnum);
|
serial.println(recWedge+"Parse error in "+lnum);
|
||||||
serial.println(recWedge+syntaxTree.toString());
|
serial.println(recWedge+syntaxTree.toString());
|
||||||
@@ -1057,31 +1052,24 @@ basicFunctions._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
|
||||||
basicFunctions._interpretLine = function(lnum, cmd) {
|
basicFunctions._interpretLine = function(lnum, cmd) {
|
||||||
var _debugprintHighestLevel = false;
|
var _debugprintHighestLevel = true;
|
||||||
|
|
||||||
// TOKENISE
|
// TOKENISE
|
||||||
var tokenisedObject = basicFunctions._tokenise(lnum, cmd);
|
var tokenisedObject = basicFunctions._tokenise(lnum, cmd);
|
||||||
var tokens = tokenisedObject.tokens;
|
var tokens = tokenisedObject.tokens;
|
||||||
var states = tokenisedObject.states;
|
var states = tokenisedObject.states;
|
||||||
|
|
||||||
if (_debugprintHighestLevel) println(tokens.join("~"));
|
|
||||||
if (_debugprintHighestLevel) println(states.join(" "));
|
|
||||||
|
|
||||||
|
|
||||||
// ELABORATION : distinguish numbers and operators from literals
|
// ELABORATION : distinguish numbers and operators from literals
|
||||||
basicFunctions._parserElaboration(lnum, tokens, states);
|
basicFunctions._parserElaboration(lnum, tokens, states);
|
||||||
|
|
||||||
|
|
||||||
if (_debugprintHighestLevel) println(tokens.join("~"));
|
|
||||||
if (_debugprintHighestLevel) println(states.join(" "));
|
|
||||||
|
|
||||||
|
|
||||||
// PARSING (SYNTAX ANALYSIS)
|
// PARSING (SYNTAX ANALYSIS)
|
||||||
var syntaxTree = basicFunctions._parseTokens(lnum, tokens, states, 0);
|
var syntaxTree = basicFunctions._parseTokens(lnum, tokens, states, 0);
|
||||||
|
if (_debugprintHighestLevel) serial.println("Final syntax tree:");
|
||||||
|
if (_debugprintHighestLevel) serial.println(syntaxTree.toString());
|
||||||
|
|
||||||
basicFunctions._executeSyntaxTree(lnum, syntaxTree, 0);
|
basicFunctions._executeSyntaxTree(lnum, syntaxTree, 0);
|
||||||
|
|
||||||
serial.println(syntaxTree.toString());
|
|
||||||
|
|
||||||
|
|
||||||
// EXECUTE
|
// EXECUTE
|
||||||
|
|||||||
Reference in New Issue
Block a user