diff --git a/assets/basic.js b/assets/basic.js index 1e9dbcb..85816b4 100644 --- a/assets/basic.js +++ b/assets/basic.js @@ -869,7 +869,6 @@ if no arg text were given (e.g. "10 NEXT"), args will have zero length var varname = asgnObj.asgnVarName; var generator = asgnObj.asgnValue; - // assign new variable // the var itself will have head of the array, and the head itself will be removed from the array bStatus.vars[varname] = new BasicVar(generator.start, "num"); @@ -1732,7 +1731,9 @@ bF.parserPrintdbgline = function(icon, msg, lnum, recDepth) { */ bF._parseTokens = function(lnum, tokens, states) { bF.parserPrintdbg2('Line ', lnum, tokens, states, 0); - + + if (tokens.length !== states.length) throw lang.syntaxfehler(lnum); + /*************************************************************************/ let parenDepth = 0; @@ -1801,6 +1802,16 @@ bF._parseStmt = function(lnum, tokens, states, recDepth) { let treeHead = new BasicAST(); treeHead.astLnum = lnum; + /*************************************************************************/ + + // case for: single word (e.g. NEXT for FOR loop) + if (tokens.length == 1 && states.length == 1) { + bF.parserPrintdbgline('$', "Single Word Function Call", lnum, recDepth); + return bF._parseLit(lnum, tokens, states, recDepth + 1, true); + } + + /*************************************************************************/ + let parenDepth = 0; let parenStart = -1; let parenEnd = -1; @@ -2341,7 +2352,7 @@ bF._parseIdent = function(lnum, tokens, states, recDepth) { /** * @return: BasicAST */ -bF._parseLit = function(lnum, tokens, states, recDepth) { +bF._parseLit = function(lnum, tokens, states, recDepth, functionMode) { bF.parserPrintdbg2(String.fromCharCode(0xA2), lnum, tokens, states, recDepth); if (!Array.isArray(tokens) && !Array.isArray(states)) throw new ParserError("Tokens and states are not array"); @@ -2350,7 +2361,7 @@ bF._parseLit = function(lnum, tokens, states, recDepth) { let treeHead = new BasicAST(); treeHead.astLnum = lnum; treeHead.astValue = ("qot" == states[0]) ? tokens[0] : tokens[0].toUpperCase(); - treeHead.astType = ("qot" == states[0]) ? "string" : ("num" == states[0]) ? "num" : "lit"; + treeHead.astType = (functionMode) ? "function" : ("qot" == states[0]) ? "string" : ("num" == states[0]) ? "num" : "lit"; return treeHead; } @@ -2579,7 +2590,7 @@ bF._executeAndGet = function(lnum, syntaxTree) { try { var execResult = bF._executeSyntaxTree(lnum, syntaxTree, 0); - serial.println(`Line ${lnum} TRO: ${Object.entries(execResult)}`); + if (bF.parserDoDebugPrint) serial.println(`Line ${lnum} TRO: ${Object.entries(execResult)}`); return execResult.troNextLine; } diff --git a/assets/tbas/parser_wip.js b/assets/tbas/parser_wip.js index 179d32e..98b4d1c 100644 --- a/assets/tbas/parser_wip.js +++ b/assets/tbas/parser_wip.js @@ -21,7 +21,9 @@ bF.parserPrintdbgline = function(icon, msg, lnum, recDepth) { */ bF._parseTokens = function(lnum, tokens, states) { bF.parserPrintdbg2('Line ', lnum, tokens, states, 0); - + + if (tokens.length !== states.length) throw lang.syntaxfehler(lnum); + /*************************************************************************/ let parenDepth = 0; @@ -90,6 +92,16 @@ bF._parseStmt = function(lnum, tokens, states, recDepth) { let treeHead = new BasicAST(); treeHead.astLnum = lnum; + /*************************************************************************/ + + // case for: single word (e.g. NEXT for FOR loop) + if (tokens.length == 1 && states.length == 1) { + bF.parserPrintdbgline('$', "Single Word Function Call", lnum, recDepth); + return bF._parseLit(lnum, tokens, states, recDepth + 1, true); + } + + /*************************************************************************/ + let parenDepth = 0; let parenStart = -1; let parenEnd = -1; @@ -631,7 +643,7 @@ bF._parseIdent = function(lnum, tokens, states, recDepth) { /** * @return: BasicAST */ -bF._parseLit = function(lnum, tokens, states, recDepth) { +bF._parseLit = function(lnum, tokens, states, recDepth, functionMode) { bF.parserPrintdbg2(String.fromCharCode(0xA2), lnum, tokens, states, recDepth); if (!Array.isArray(tokens) && !Array.isArray(states)) throw new ParserError("Tokens and states are not array"); @@ -640,7 +652,7 @@ bF._parseLit = function(lnum, tokens, states, recDepth) { let treeHead = new BasicAST(); treeHead.astLnum = lnum; treeHead.astValue = ("qot" == states[0]) ? tokens[0] : tokens[0].toUpperCase(); - treeHead.astType = ("qot" == states[0]) ? "string" : ("num" == states[0]) ? "num" : "lit"; + treeHead.astType = (functionMode) ? "function" : ("qot" == states[0]) ? "string" : ("num" == states[0]) ? "num" : "lit"; return treeHead; } @@ -729,8 +741,8 @@ let tokens5 = ["ON","6","*","SQR","(","X","-","3",")","GOTO","X","+","1",",","X" let states5 = ["lit","num","op","lit","paren","lit","op","num","paren","lit","lit","op","num","sep","lit","op","num","sep","lit","op","num"]; // FOR K=1 TO 10 -let tokens6 = ["FOR","K","=","1","TO","10"]; -let states6 = ["lit","lit","op","num","op","num"]; +let tokens6 = ["FOR","K","=","10","TO","1","STEP","-","1"]; +let states6 = ["lit","lit","op","num","op","num","op","op","num"]; // FIXME print(chr(47+round(rnd(1))*45);) outputs bad tree let tokens7 = ["PRINT","(","CHR","(","47","+","ROUND","(","RND","(","1",")",")","*","45",")",";",")"]; @@ -740,10 +752,14 @@ let states7 = ["lit","paren","lit","paren","num","op","lit","paren","lit","paren let tokens8 = ["PRINT","4","+","5","*","9"]; let states8 = ["lit","num","op","num","op","num"]; +// NEXT +let tokens9 = ["NEXT"]; +let states9 = ["lit"]; + try { let trees = bF._parseTokens(lnum, - tokens8, - states8 + tokens6, + states6 ); trees.forEach((t,i) => { serial.println("\nParsed Statement #"+(i+1)); diff --git a/assets/tbas/syntax.txt b/assets/tbas/syntax.txt index a283a06..7dccee3 100644 --- a/assets/tbas/syntax.txt +++ b/assets/tbas/syntax.txt @@ -11,7 +11,7 @@ stmt = | "DEFUN" , [ident] , "(" , [ident , {" , " , ident}] , ")" , "=" , expr | "ON" , expr_sans_asgn , ("GOTO" | "GOSUB") , expr_sans_asgn , {"," , expr_sans_asgn} | "(" , stmt , ")" - | expr ; + | expr ; (* if the statement contains only one word, treat it as function_call e.g. NEXT for FOR loop *) expr = (* this basically blocks some funny attemps such as using DEFUN as anon function because everything is global in BASIC *) lit