basic: actually the parser was correct

This commit is contained in:
minjaesong
2020-12-12 23:48:31 +09:00
parent 2acdb4d0c1
commit 24cd1a030f

View File

@@ -1789,7 +1789,7 @@ bF._parseStmt = function(lnum, tokens, states, recDepth) {
let headTkn = tokens[0].toUpperCase(); let headTkn = tokens[0].toUpperCase();
let headSta = states[0]; let headSta = states[0];
let treeHead = new BasicAST(); let treeHead = new BasicAST();
treeHead.astLnum = lnum; treeHead.astLnum = lnum;
@@ -1818,7 +1818,7 @@ bF._parseStmt = function(lnum, tokens, states, recDepth) {
sepsZero.push(k); sepsZero.push(k);
if (parenDepth == 1 && states[k] == "sep") if (parenDepth == 1 && states[k] == "sep")
sepsOne.push(k); sepsOne.push(k);
if (parenDepth == 0) { if (parenDepth == 0) {
let tok = tokens[k].toUpperCase(); let tok = tokens[k].toUpperCase();
if (-1 == onGoPos && ("GOTO" == tok || "GOSUB" == tok) && "lit" == states[k]) if (-1 == onGoPos && ("GOTO" == tok || "GOSUB" == tok) && "lit" == states[k])
@@ -1842,9 +1842,9 @@ bF._parseStmt = function(lnum, tokens, states, recDepth) {
bF.parserPrintdbgline('$', 'It was NOT!', lnum, recDepth); bF.parserPrintdbgline('$', 'It was NOT!', lnum, recDepth);
if (!(e instanceof ParserError)) throw e; if (!(e instanceof ParserError)) throw e;
} }
/*************************************************************************/ /*************************************************************************/
// ## case for: // ## case for:
// | "DEFUN" , [ident] , "(" , [ident , {" , " , ident}] , ")" , "=" , expr // | "DEFUN" , [ident] , "(" , [ident , {" , " , ident}] , ")" , "=" , expr
if ("DEFUN" == headTkn && "lit" == headSta && if ("DEFUN" == headTkn && "lit" == headSta &&
@@ -1854,7 +1854,7 @@ bF._parseStmt = function(lnum, tokens, states, recDepth) {
treeHead.astValue = "DEFUN"; treeHead.astValue = "DEFUN";
treeHead.astType = "function"; treeHead.astType = "function";
// parse function name // parse function name
if (tokens[1] == "(") { if (tokens[1] == "(") {
// anonymous function // anonymous function
@@ -1865,18 +1865,18 @@ bF._parseStmt = function(lnum, tokens, states, recDepth) {
else { else {
treeHead.astLeaves[0] = bF._parseIdent(lnum, [tokens[1]], [states[1]], recDepth + 1); treeHead.astLeaves[0] = bF._parseIdent(lnum, [tokens[1]], [states[1]], recDepth + 1);
} }
// parse function arguments // parse function arguments
treeHead.astLeaves[0].astLeaves = sepsOne.map(i=>i-1).concat([parenEnd - 1]) treeHead.astLeaves[0].astLeaves = sepsOne.map(i=>i-1).concat([parenEnd - 1])
.map(i=>bF._parseIdent(lnum, [tokens[i]], [states[i]], recDepth + 2)); .map(i=>bF._parseIdent(lnum, [tokens[i]], [states[i]], recDepth + 2));
// parse function body // parse function body
treeHead.astLeaves[1] = bF._parseExpr(lnum, treeHead.astLeaves[1] = bF._parseExpr(lnum,
tokens.slice(parenEnd + 2, tokens.length), tokens.slice(parenEnd + 2, tokens.length),
states.slice(parenEnd + 2, states.length), states.slice(parenEnd + 2, states.length),
recDepth + 1 recDepth + 1
); );
return treeHead; return treeHead;
} }
@@ -1886,12 +1886,12 @@ bF._parseStmt = function(lnum, tokens, states, recDepth) {
// | "ON" , if_equation , ident , if_equation , {"," , if_equation} // | "ON" , if_equation , ident , if_equation , {"," , if_equation}
if ("ON" == headTkn && "lit" == headSta) { if ("ON" == headTkn && "lit" == headSta) {
bF.parserPrintdbgline('$', 'ON Stmt', lnum, recDepth); bF.parserPrintdbgline('$', 'ON Stmt', lnum, recDepth);
if (onGoPos == -1) throw ParserError("Malformed ON Statement"); if (onGoPos == -1) throw ParserError("Malformed ON Statement");
treeHead.astValue = "ON"; treeHead.astValue = "ON";
treeHead.astType = "function"; treeHead.astType = "function";
// parse testvalue // parse testvalue
let testvalue = bF._parseExpr(lnum, let testvalue = bF._parseExpr(lnum,
tokens.slice(1, onGoPos), tokens.slice(1, onGoPos),
@@ -1899,7 +1899,7 @@ bF._parseStmt = function(lnum, tokens, states, recDepth) {
recDepth + 1, recDepth + 1,
true true
); );
// parse functionname // parse functionname
let functionname = bF._parseExpr(lnum, let functionname = bF._parseExpr(lnum,
[tokens[onGoPos]], [tokens[onGoPos]],
@@ -1907,13 +1907,13 @@ bF._parseStmt = function(lnum, tokens, states, recDepth) {
recDepth + 1, recDepth + 1,
true true
); );
// parse arguments // parse arguments
// get list of comma but filter ones appear before GOTO/GOSUB // get list of comma but filter ones appear before GOTO/GOSUB
let onArgSeps = sepsZero.filter(i => (i > onGoPos)); let onArgSeps = sepsZero.filter(i => (i > onGoPos));
let onArgStartPos = [onGoPos + 1].concat(onArgSeps.map(k => k + 1)); let onArgStartPos = [onGoPos + 1].concat(onArgSeps.map(k => k + 1));
let onArgPos = onArgStartPos.map((s,i) => {return{start:s, end: (onArgSeps[i] || tokens.length)}}); // use end of token position as separator position let onArgPos = onArgStartPos.map((s,i) => {return{start:s, end: (onArgSeps[i] || tokens.length)}}); // use end of token position as separator position
// recursively parse expressions // recursively parse expressions
treeHead.astLeaves = [testvalue, functionname].concat(onArgPos.map((x,i) => { treeHead.astLeaves = [testvalue, functionname].concat(onArgPos.map((x,i) => {
bF.parserPrintdbgline('$', 'ON GOTO/GOSUB Arguments #'+(i+1), lnum, recDepth); bF.parserPrintdbgline('$', 'ON GOTO/GOSUB Arguments #'+(i+1), lnum, recDepth);
@@ -1931,7 +1931,7 @@ bF._parseStmt = function(lnum, tokens, states, recDepth) {
return treeHead; return treeHead;
} }
/*************************************************************************/ /*************************************************************************/
// ## case for: // ## case for:
@@ -1944,7 +1944,7 @@ bF._parseStmt = function(lnum, tokens, states, recDepth) {
recDepth + 1 recDepth + 1
); );
} }
/*************************************************************************/ /*************************************************************************/
// ## case for: // ## case for:
@@ -1957,9 +1957,9 @@ bF._parseStmt = function(lnum, tokens, states, recDepth) {
bF.parserPrintdbgline('$', 'Error!', lnum, recDepth); bF.parserPrintdbgline('$', 'Error!', lnum, recDepth);
throw new ParserError("Statement cannot be parsed: "+e.stack); throw new ParserError("Statement cannot be parsed: "+e.stack);
} }
/*************************************************************************/ /*************************************************************************/
throw new ParserError("Statement cannot be parsed"); throw new ParserError("Statement cannot be parsed");
} // END of STMT } // END of STMT
@@ -1972,7 +1972,7 @@ expr = (* this basically blocks some funny attemps such as using DEFUN as anon f
| function_call | function_call
| expr , op , expr | expr , op , expr
| op_uni , expr ; | op_uni , expr ;
* @return: BasicAST * @return: BasicAST
*/ */
bF._parseExpr = function(lnum, tokens, states, recDepth, ifMode) { bF._parseExpr = function(lnum, tokens, states, recDepth, ifMode) {
@@ -1987,9 +1987,9 @@ bF._parseExpr = function(lnum, tokens, states, recDepth, ifMode) {
bF.parserPrintdbgline('E', 'Literal Call', lnum, recDepth); bF.parserPrintdbgline('E', 'Literal Call', lnum, recDepth);
return bF._parseLit(lnum, tokens, states, recDepth + 1); return bF._parseLit(lnum, tokens, states, recDepth + 1);
} }
/*************************************************************************/ /*************************************************************************/
// scan for operators with highest precedence, use rightmost one if multiple were found // scan for operators with highest precedence, use rightmost one if multiple were found
let topmostOp; let topmostOp;
let topmostOpPrc = 0; let topmostOpPrc = 0;
@@ -2032,19 +2032,19 @@ bF._parseExpr = function(lnum, tokens, states, recDepth, ifMode) {
if (parenDepth != 0) throw lang.syntaxfehler(lnum, lang.unmatchedBrackets); if (parenDepth != 0) throw lang.syntaxfehler(lnum, lang.unmatchedBrackets);
/*************************************************************************/ /*************************************************************************/
// ## case for: // ## case for:
// | "(" , expr , ")" // | "(" , expr , ")"
if (parenStart == 0 && parenEnd == tokens.length - 1) { if (parenStart == 0 && parenEnd == tokens.length - 1) {
bF.parserPrintdbgline('E', '( Expr )', lnum, recDepth); bF.parserPrintdbgline('E', '( Expr )', lnum, recDepth);
return bF._parseExpr(lnum, return bF._parseExpr(lnum,
tokens.slice(parenStart + 1, parenEnd), tokens.slice(parenStart + 1, parenEnd),
states.slice(parenStart + 1, parenEnd), states.slice(parenStart + 1, parenEnd),
recDepth + 1 recDepth + 1
); );
} }
/*************************************************************************/ /*************************************************************************/
// ## case for: // ## case for:
@@ -2058,23 +2058,26 @@ bF._parseExpr = function(lnum, tokens, states, recDepth, ifMode) {
bF.parserPrintdbgline('E', 'It was NOT!', lnum, recDepth); bF.parserPrintdbgline('E', 'It was NOT!', lnum, recDepth);
if (!(e instanceof ParserError)) throw e; if (!(e instanceof ParserError)) throw e;
} }
/*************************************************************************/ /*************************************************************************/
// ## case for: // ## case for:
// (* at this point, if OP is found in paren-level 0, skip function_call *)
// | function_call ; // | function_call ;
try { if (topmostOp === undefined) {
bF.parserPrintdbgline('E', "Trying Function Call...", lnum, recDepth); try {
return bF._parseFunctionCall(lnum, tokens, states, recDepth + 1); bF.parserPrintdbgline('E', "Trying Function Call...", lnum, recDepth);
return bF._parseFunctionCall(lnum, tokens, states, recDepth + 1);
}
// if ParserError is raised, continue to apply other rules
catch (e) {
bF.parserPrintdbgline('E', 'It was NOT!', lnum, recDepth);
if (!(e instanceof ParserError)) throw e;
}
} }
// if ParserError is raised, continue to apply other rules
catch (e) {
bF.parserPrintdbgline('E', 'It was NOT!', lnum, recDepth);
if (!(e instanceof ParserError)) throw e;
}
/*************************************************************************/ /*************************************************************************/
// ## case for: // ## case for:
// | expr , op, expr // | expr , op, expr
// | op_uni , expr // | op_uni , expr
@@ -2084,15 +2087,15 @@ bF._parseExpr = function(lnum, tokens, states, recDepth, ifMode) {
if (ifMode && topmostOp == "=") throw lang.syntaxfehler(lnum, "'=' used on IF, did you mean '=='?"); if (ifMode && topmostOp == "=") throw lang.syntaxfehler(lnum, "'=' used on IF, did you mean '=='?");
if (ifMode && topmostOp == ":") throw lang.syntaxfehler(lnum, "':' used on IF"); if (ifMode && topmostOp == ":") throw lang.syntaxfehler(lnum, "':' used on IF");
// this is the AST we're going to build up and return // this is the AST we're going to build up and return
// (other IF clauses don't use this) // (other IF clauses don't use this)
let treeHead = new BasicAST(); let treeHead = new BasicAST();
treeHead.astLnum = lnum; treeHead.astLnum = lnum;
treeHead.astValue = topmostOp; treeHead.astValue = topmostOp;
treeHead.astType = "op"; treeHead.astType = "op";
// BINARY_OP? // BINARY_OP?
if (operatorPos > 0) { if (operatorPos > 0) {
let subtknL = tokens.slice(0, operatorPos); let subtknL = tokens.slice(0, operatorPos);
@@ -2111,12 +2114,12 @@ bF._parseExpr = function(lnum, tokens, states, recDepth, ifMode) {
recDepth + 1 recDepth + 1
); );
} }
return treeHead; return treeHead;
} }
/*************************************************************************/ /*************************************************************************/
throw new ParserError("Expression cannot be parsed"); throw new ParserError("Expression cannot be parsed");
} // END of EXPR } // END of EXPR
@@ -2174,13 +2177,13 @@ bF._parseIfMode = function(lnum, tokens, states, recDepth, exprMode) {
// ## case for: // ## case for:
// "IF" , expr_sans_asgn , "THEN" , stmt , ["ELSE" , stmt] // "IF" , expr_sans_asgn , "THEN" , stmt , ["ELSE" , stmt]
if ("IF" == headTkn && "lit" == headSta) { if ("IF" == headTkn && "lit" == headSta) {
// "THEN" not found, raise error! // "THEN" not found, raise error!
if (thenPos == -1) throw new ParserError("IF without THEN in " + lnum); if (thenPos == -1) throw new ParserError("IF without THEN in " + lnum);
treeHead.astValue = "IF"; treeHead.astValue = "IF";
treeHead.astType = "function"; treeHead.astType = "function";
treeHead.astLeaves[0] = bF._parseExpr(lnum, treeHead.astLeaves[0] = bF._parseExpr(lnum,
tokens.slice(1, thenPos), tokens.slice(1, thenPos),
states.slice(1, thenPos), states.slice(1, thenPos),
@@ -2198,10 +2201,10 @@ bF._parseIfMode = function(lnum, tokens, states, recDepth, exprMode) {
states.slice(elsePos + 1, tokens.length), states.slice(elsePos + 1, tokens.length),
recDepth + 1 recDepth + 1
); );
return treeHead; return treeHead;
} }
throw new ParserError("not an IF "+(exprMode) ? "expression" : "statement"); throw new ParserError("not an IF "+(exprMode) ? "expression" : "statement");
} // END of IF } // END of IF
@@ -2216,13 +2219,13 @@ bF._parseFunctionCall = function(lnum, tokens, states, recDepth) {
bF.parserPrintdbg2(String.fromCharCode(0x192), lnum, tokens, states, recDepth); bF.parserPrintdbg2(String.fromCharCode(0x192), lnum, tokens, states, recDepth);
/*************************************************************************/ /*************************************************************************/
let parenDepth = 0; let parenDepth = 0;
let parenStart = -1; let parenStart = -1;
let parenEnd = -1; let parenEnd = -1;
let _argsepsOnLevelZero = []; // argseps collected when parenDepth == 0 let _argsepsOnLevelZero = []; // argseps collected when parenDepth == 0
let _argsepsOnLevelOne = []; // argseps collected when parenDepth == 1 let _argsepsOnLevelOne = []; // argseps collected when parenDepth == 1
// Scan for unmatched parens and mark off the right operator we must deal with // Scan for unmatched parens and mark off the right operator we must deal with
// every function_call need to re-scan because it is recursively called // every function_call need to re-scan because it is recursively called
for (let k = 0; k < tokens.length; k++) { for (let k = 0; k < tokens.length; k++) {
@@ -2236,24 +2239,27 @@ bF._parseFunctionCall = function(lnum, tokens, states, recDepth) {
if (parenEnd == -1 && parenDepth == 1) parenEnd = k; if (parenEnd == -1 && parenDepth == 1) parenEnd = k;
parenDepth -= 1; parenDepth -= 1;
} }
if (parenDepth == 0 && states[k] == "sep") if (parenDepth == 0 && states[k] == "sep")
_argsepsOnLevelZero.push(k); _argsepsOnLevelZero.push(k);
if (parenDepth == 1 && states[k] == "sep") if (parenDepth == 1 && states[k] == "sep")
_argsepsOnLevelOne.push(k); _argsepsOnLevelOne.push(k);
} }
// unmatched brackets, duh! // unmatched brackets, duh!
if (parenDepth != 0) throw lang.syntaxfehler(lnum, lang.unmatchedBrackets); if (parenDepth != 0) throw lang.syntaxfehler(lnum, lang.unmatchedBrackets);
let parenUsed = (parenStart == 1 && parenEnd == states.length - 1); let parenUsed = (parenStart == 1);
// && parenEnd == tokens.length - 1);
// if starting paren is found, just use it
// this prevents "RND(~~)*K" to be parsed as [RND, (~~)*K]
/*************************************************************************/ /*************************************************************************/
// ## case for: // ## case for:
// ident , "(" , [expr , {argsep , expr} , [argsep]] , ")" // ident , "(" , [expr , {argsep , expr} , [argsep]] , ")"
// | ident , expr , {argsep , expr} , [argsep] ; // | ident , expr , {argsep , expr} , [argsep] ;
bF.parserPrintdbgline(String.fromCharCode(0x192), 'Function Call', lnum, recDepth); bF.parserPrintdbgline(String.fromCharCode(0x192), `Function Call (parenUsed: ${parenUsed})`, lnum, recDepth);
let treeHead = new BasicAST(); let treeHead = new BasicAST();
treeHead.astLnum = lnum; treeHead.astLnum = lnum;
@@ -2265,10 +2271,10 @@ bF._parseFunctionCall = function(lnum, tokens, states, recDepth) {
// 1 6 9 12 // 1 6 9 12
let argStartPos = [1 + (parenUsed)].concat(argSeps.map(k => k+1)); let argStartPos = [1 + (parenUsed)].concat(argSeps.map(k => k+1));
// [1,5) [6,8) [9,11) [12,end) // [1,5) [6,8) [9,11) [12,end)
let argPos = argStartPos.map((s,i) => {return{start:s, end:(argSeps[i] || tokens.length - (parenUsed))}}); // use end of token position as separator position let argPos = argStartPos.map((s,i) => {return{start:s, end:(argSeps[i] || (parenUsed) ? parenEnd : tokens.length )}}); // use end of token position as separator position
// check for trailing separator // check for trailing separator
let hasTrailingSep = (states[states.length - 1 - (parenUsed)] == "sep"); let hasTrailingSep = (states[((parenUsed) ? parenEnd : states.length) - 1] == "sep");
// exclude last separator from recursion if input tokens has trailing separator // exclude last separator from recursion if input tokens has trailing separator
if (hasTrailingSep) argPos.pop(); if (hasTrailingSep) argPos.pop();
@@ -2297,12 +2303,12 @@ bF._parseIdent = function(lnum, tokens, states, recDepth) {
if (!Array.isArray(tokens) && !Array.isArray(states)) throw new ParserError("Tokens and states are not array"); if (!Array.isArray(tokens) && !Array.isArray(states)) throw new ParserError("Tokens and states are not array");
if (tokens.length != 1 || states[0] != "lit") throw new ParserError(`illegal tokens '${tokens}' with states '${states}' in ${lnum}`); if (tokens.length != 1 || states[0] != "lit") throw new ParserError(`illegal tokens '${tokens}' with states '${states}' in ${lnum}`);
let treeHead = new BasicAST(); let treeHead = new BasicAST();
treeHead.astLnum = lnum; treeHead.astLnum = lnum;
treeHead.astValue = tokens[0].toUpperCase(); treeHead.astValue = tokens[0].toUpperCase();
treeHead.astType = "lit"; treeHead.astType = "lit";
return treeHead; return treeHead;
} }
/** /**
@@ -2313,15 +2319,16 @@ bF._parseLit = function(lnum, tokens, states, recDepth) {
if (!Array.isArray(tokens) && !Array.isArray(states)) throw new ParserError("Tokens and states are not array"); if (!Array.isArray(tokens) && !Array.isArray(states)) throw new ParserError("Tokens and states are not array");
if (tokens.length != 1) throw new ParserError("parseLit 1"); if (tokens.length != 1) throw new ParserError("parseLit 1");
let treeHead = new BasicAST(); let treeHead = new BasicAST();
treeHead.astLnum = lnum; treeHead.astLnum = lnum;
treeHead.astValue = ("qot" == states[0]) ? tokens[0] : tokens[0].toUpperCase(); treeHead.astValue = ("qot" == states[0]) ? tokens[0] : tokens[0].toUpperCase();
treeHead.astType = ("qot" == states[0]) ? "string" : ("num" == states[0]) ? "num" : "lit"; treeHead.astType = ("qot" == states[0]) ? "string" : ("num" == states[0]) ? "num" : "lit";
return treeHead; return treeHead;
} }
// @return is defined in BasicAST // @return is defined in BasicAST
let JStoBASICtype = function(object) { let JStoBASICtype = function(object) {
if (typeof object === "boolean") return "bool"; if (typeof object === "boolean") return "bool";