From 401bb474812f3797aaae1842723268a8c87a8602 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Thu, 10 Dec 2020 21:50:33 +0900 Subject: [PATCH] basic: more parser wip --- assets/basic.js | 44 +++++++++++++++++++++++------------- assets/tbas/parser_wip.js | 43 +++++++++++++++++++++++++++++++---- assets/tbas/syntax.txt | 47 +++++++++++++++++++++++++++++++++------ 3 files changed, 107 insertions(+), 27 deletions(-) diff --git a/assets/basic.js b/assets/basic.js index 309c91b..290b012 100644 --- a/assets/basic.js +++ b/assets/basic.js @@ -1602,28 +1602,40 @@ bF._recurseApplyAST = function(tree, action) { } } /** EBNF notation: -stmt = - "IF" , equation , "THEN" , stmt , ["ELSE" , stmt] - | "DEFUN" , [lit] , "(" , [lit , {" , " , lit}] , ")" , "=" , stmt - | "ON" , lit , function , equation , [{"," , equation}] - | function , [equation , {argsep , equation}] - | function , "(" , [equation , {argsep , equation}] , ")" - | equation - | "(" , stmt , ")" ; +line = linenumber , stmt , {":" , stmt} ; +linenumber = digits ; -equation = lit , op , lit - | op_uni , lit +stmt = + "IF" , if_equation , "THEN" , stmt , ["ELSE" , stmt] + | "DEFUN" , [lit] , "(" , [lit , {" , " , lit}] , ")" , "=" , stmt + | "ON" , lit , lit , equation , {"," , equation} + | function_call + | "(" , stmt , ")" ; + +function_call = + lit + | lit , function_call , {argsep , function_call} + | lit , "(" , [function_call , {argsep , function_call}] , ")" + | equation + +equation = equation , op , equation + | op_uni , equation | lit | "(" , equation , ")" -(* don't bother looking at these, because you already know the stuff *) - +if_equation = if_equation , op - ("=") , if_equation + | op_uni , if_equation + | lit + | "(" , if_equation , ")" + +(* don't bother looking at these, because you already know the stuff *) + function = lit ; argsep = ","|";" ; -lit = alph , [digits] | num | string ; +lit = alph , [digits] | num | string ; (* example: "MyVar_2" *) op = "^" | "*" | "/" | "MOD" | "+" | "-" | "<<" | ">>" | "<" | ">" | "<=" | "=<" | ">=" | "=>" | "==" | "<>" | "><" | "BAND" | "BXOR" | "BOR" - | "AND" | "OR" | "TO" | "STEP" | "!" | "~" | "#" | "=" | ":" ; + | "AND" | "OR" | "TO" | "STEP" | "!" | "~" | "#" | "=" ; op_uni = "-" | "+" ; alph = letter | letter , alph ; @@ -1631,7 +1643,7 @@ digits = digit | digit , digits ; hexdigits = hexdigit | hexdigit , hexdigits ; bindigits = bindigit | bindigit , bindigits ; num = digits | digits , "." , [digits] | "." , digits - | ("0x"|"0X") , hexdigits + | ("0x"|"0X") , hexdigits | ("0b"|"0B") , bindigits ; (* sorry, no e-notation! *) visible = ? ASCII 0x20 to 0x7E ? ; string = '"' , (visible | visible , stringlit) , '"' ; @@ -2356,4 +2368,4 @@ while (!tbasexit) { } } -0; \ No newline at end of file +0; diff --git a/assets/tbas/parser_wip.js b/assets/tbas/parser_wip.js index 5907d11..4b57c97 100644 --- a/assets/tbas/parser_wip.js +++ b/assets/tbas/parser_wip.js @@ -24,6 +24,8 @@ bF._parseStmt = function(lnum, tokens, states, recDepth) { treeHead.astDepth = recDepth; treeHead.astLnum = lnum; + // ## case for: + // "IF" , if_equation , "THEN" , stmt , ["ELSE" , stmt] if ("IF" == headTkn && "lit" == headSta) { // find nearest THEN and ELSE but also take parens into account let thenPos = -1; @@ -59,14 +61,43 @@ bF._parseStmt = function(lnum, tokens, states, recDepth) { // "THEN" not found, raise error! if (thenPos == -1) throw ParserError("IF without THEN in " + lnum); - // TODO gotta go home :) + treeHead.astValue = "IF"; + treeHead.astType = "function"; + + treeHead.astLeaves[0] = bF._parseEquation(lnum, + tokens.slice(1, thenPos), + states.slice(1, thenPos), + recDepth + 1, + true // if_equation mode + ); + treeHead.astLeaves[1] = bF._parseStmt(lnum, + tokens.slice(thenPos + 1, (elsePos != -1) ? elsePos : tokens.length), + states.slice(thenPos + 1, (elsePos != -1) ? elsePos : tokens.length), + recDepth + 1 + ); + if (elsePos != -1) + treeHead.astLeaves[2] = bF._parseStmt(lnum, + tokens.slice(elsePos + 1, tokens.length), + states.slice(elsePos + 1, tokens.length), + recDepth + 1 + ); + + return treeHead; } + + // ## case for: + // ??? + + // TODO + } /** Parses following EBNF rule: * lit (* which is parsed by the tokeniser already *) * @return: BasicAST */ bF._parseLit = function(lnum, tokens, states, recDepth) { + if (tokens.length > 1) throw ParserError(); + let treeHead = new BasicAST(); treeHead.astDepth = recDepth; treeHead.astLnum = lnum; @@ -82,7 +113,7 @@ bF._parseLit = function(lnum, tokens, states, recDepth) { } // else, screw it else { - throw lang.syntaxfehler(lnum, "TRAP_LITERALLY_LITERAL"); + throw ParserError("TRAP_LITERALLY_LITERAL"); } } @@ -98,7 +129,7 @@ bF._parseLit = function(lnum, tokens, states, recDepth) { * @return: BasicAST */ bF._EquationIllegalTokens = ["IF","THEN","ELSE","DEFUN","ON"]; -bF._parseEquation = function(lnum, tokens, states, recDepth) { +bF._parseEquation = function(lnum, tokens, states, recDepth, ifMode) { // scan for operators with highest precedence, use rightmost one if multiple were found let topmostOp; let topmostOpPrc = 0; @@ -156,6 +187,10 @@ bF._parseEquation = function(lnum, tokens, states, recDepth) { if (topmostOp !== undefined) { if (_debugSyntaxAnalysis) serial.println("operator: "+topmostOp+", pos: "+operatorPos); + if (ifMode && topmostOp == "=") throw lang.syntaxfehler(lnum, "'=' used on IF, did you mean '=='?"); + if (ifMode && topmostOp == ":") throw lang.syntaxfehler(lnum, "':' used on IF"); + + // this is the AST we're going to build up and return // (other IF clauses don't use this) let treeHead = new BasicAST(); @@ -188,7 +223,7 @@ bF._parseEquation = function(lnum, tokens, states, recDepth) { // ## case for: // lit let headTkn = tokens[0].toUpperCase(); - if (!bF._EquationIllegalTokens.includes(headTkn)) { + if (!bF._EquationIllegalTokens.includes(headTkn) && tokens.length == 1) { return bF._parseLit(lnum, tokens, states, recDepth + 1); } diff --git a/assets/tbas/syntax.txt b/assets/tbas/syntax.txt index 8a37769..15f8c9b 100644 --- a/assets/tbas/syntax.txt +++ b/assets/tbas/syntax.txt @@ -1,25 +1,37 @@ +line = linenumber , stmt , {":" , stmt} ; +linenumber = digits ; + stmt = - "IF" , equation , "THEN" , stmt , ["ELSE" , stmt] + "IF" , if_equation , "THEN" , stmt , ["ELSE" , stmt] | "DEFUN" , [lit] , "(" , [lit , {" , " , lit}] , ")" , "=" , stmt - | "ON" , lit , function , equation , [{"," , equation}] - | function , [equation , {argsep , equation}] - | function , "(" , [equation , {argsep , equation}] , ")" - | equation + | "ON" , lit , lit , equation , {"," , equation} + | function_call | "(" , stmt , ")" ; +function_call = + lit + | lit , function_call , {argsep , function_call} + | lit , "(" , [function_call , {argsep , function_call}] , ")" + | equation + equation = equation , op , equation | op_uni , equation | lit | "(" , equation , ")" +if_equation = if_equation , op - ("=") , if_equation + | op_uni , if_equation + | lit + | "(" , if_equation , ")" + (* don't bother looking at these, because you already know the stuff *) function = lit ; argsep = ","|";" ; -lit = alph , [digits] | num | string ; +lit = alph , [digits] | num | string ; (* example: "MyVar_2" *) op = "^" | "*" | "/" | "MOD" | "+" | "-" | "<<" | ">>" | "<" | ">" | "<=" | "=<" | ">=" | "=>" | "==" | "<>" | "><" | "BAND" | "BXOR" | "BOR" - | "AND" | "OR" | "TO" | "STEP" | "!" | "~" | "#" | "=" | ":" ; + | "AND" | "OR" | "TO" | "STEP" | "!" | "~" | "#" | "=" ; op_uni = "-" | "+" ; alph = letter | letter , alph ; @@ -47,3 +59,24 @@ hexdigit = "A" | "B" | "C" | "D" | "E" | "F" | "a" | "b" bindigit = "0" | "1" ; (* all possible token states: lit num op bool qot paren sep *) + + +IF +1. cond +2. true +[3. false] + +DEFUN +1. funcname + 1. arg0 + [2. arg1] + [3. argN...] +2. stmt + +ON +1. varname +2. functionname +3. arg0 +[4. arg1] +[5. argN...] +