public static Node ParseProgram() { //Diagram rules //1st -> SubDec | FuncDec //SubDec | FuncDec -> SubDec | FuncDec //SubDec | FuncDec -> EOF Statements root = new Statements(); while (tokens.actual.type != "EOF") { if (tokens.actual.type == "SUB" || tokens.actual.type == "FUNCTION") { root.Add(ParseFunction()); } else { if (tokens.actual.type == "LINEBREAK") { CurrentLine++; tokens.SelectNext(); } else { throw new SystemException($"Statement line outside functions are not allowed. Got a {tokens.actual.type}.(position {tokens.position}) [Line: {CurrentLine}]"); } } } //add a main funccall FuncCall mainCall = new FuncCall(); mainCall.value = "main"; root.Add(mainCall); return(root); }
public static Node ParseFactor() { //Console.WriteLine("Parsing Factor"); //Factor rules //1st -> num //1st -> + //1st -> - //1st -> not //1st -> ( //+ -> factor //- -> factor //not -> factor //( -> expression //expression -> ) //identifier acts as num //True | False acts as num Node root; switch (tokens.actual.type) { case "INT": root = new IntVal(); root.value = tokens.actual.value; tokens.SelectNext(); return(root); case "IDENTIFIER": root = new Identifier((string)tokens.actual.value); root.value = tokens.actual.value; tokens.SelectNext(); //check if this is a function if (tokens.actual.type == "POPEN") { FuncCall call = new FuncCall(); call.value = root.value; tokens.SelectNext(); if (tokens.actual.type != "PCLOSE") { do { if (tokens.actual.type == "COMMA") { tokens.SelectNext(); } call.Add(ParseRelExpression()); } while(tokens.actual.type == "COMMA"); } Expect("PCLOSE", true); return(call); } return(root); case "TRUE": case "FALSE": root = new UnOp(); root.value = tokens.actual.type == "TRUE" ? "true": "false"; tokens.SelectNext(); return(root); case "PLUS": case "MINUS": root = new UnOp(); root.value = tokens.actual.type == "PLUS" ? '+': '-'; tokens.SelectNext(); root.children[0] = ParseFactor(); return(root); case "NOT": root = new UnOp(); root.value = "not"; tokens.SelectNext(); root.children[0] = ParseFactor(); return(root); case "POPEN": tokens.SelectNext(); root = ParseRelExpression(); if (tokens.actual.type != "PCLOSE") { throw new SystemException($"Missing closing parentesis (position {tokens.position}) [Line: {CurrentLine}]"); } tokens.SelectNext(); return(root); case "INPUT": root = new UnOp(); root.value = "input"; tokens.SelectNext(); return(root); } //End of term reached, but exiting was not allowed throw new SystemException($"Invalid expression format. Expression end was unexpected(position {tokens.position}) [Line: {CurrentLine}]"); }
//public static Node ParseStatements(string poi){ // return ParseStatements("none"); // } public static Node ParseStatement() { //Console.WriteLine("parsing expression"); //Diagram rules //1st - Identfier //identifier - = //= - expression //1st - print //print - expression //1st - statements Node root; //TODO- condense this code by replacing similar code with some functions (expect line end for example) switch (tokens.actual.type) { case "END": return(new NoOp()); case "IDENTIFIER": // IDENTIFIER - = - EXPRESSION // get identifier Identifier ident = new Identifier((string)tokens.actual.value); tokens.SelectNext(); if (tokens.actual.type != "EQUAL") //expecting a EQUAL { throw new SystemException($"Identifier with no assignment ({tokens.actual.value}) (position {tokens.position}) [Line: {CurrentLine}]"); } root = new BinOp(); //create the assign biop node root.value = '='; root.children[0] = ident; //left is the identfier tokens.SelectNext(); root.children[1] = ParseRelExpression(); //right is a relative expression if (tokens.actual.type != "LINEBREAK") //expect linebreak after the expression; { throw new SystemException($"No LINEBREAK after assignment (position {tokens.position}) [Line: {CurrentLine}]"); } CurrentLine++; tokens.SelectNext(); //go to next token after linebreak return(root); case "CALL": tokens.SelectNext(); Expect("IDENTIFIER", false); FuncCall call = new FuncCall(); call.value = (string)tokens.actual.value; tokens.SelectNext(); Expect("POPEN", true); if (tokens.actual.type != "PCLOSE") { do { if (tokens.actual.type == "COMMA") { tokens.SelectNext(); } call.Add(ParseRelExpression()); }while (tokens.actual.type == "COMMA"); } Expect("PCLOSE", true); return(call); case "PRINT": //print - expression root = new UnOp(); root.value = "print"; tokens.SelectNext(); root.children[0] = ParseRelExpression(); if (tokens.actual.type != "LINEBREAK") //expect linebreak after the expression; { throw new SystemException($"No LINEBREAK after PRINT (position {tokens.position}) [Line: {CurrentLine}]"); } CurrentLine++; tokens.SelectNext(); //go to next token after linebreak return(root); case "WHILE": root = new WhileNode(); tokens.SelectNext(); root.children[0] = ParseRelExpression(); if (tokens.actual.type != "LINEBREAK") //expect linebreak after the expression; { throw new SystemException($"No LINEBREAK after Relative Expression (position {tokens.position}) [Line: {CurrentLine}]"); } CurrentLine++; tokens.SelectNext(); //go to next token after linebreak root.children[1] = ParseStatements("while"); //already goes to next line, no select next required return(root); case "DIM": root = new BinOp(); root.value = "vardec"; tokens.SelectNext(); if (tokens.actual.type != "IDENTIFIER") { throw new SystemException($"IDENTIFIER is required after an variable declaration declaration (position {tokens.position}) [Line: {CurrentLine}]"); } root.children[0] = new NoOp(); root.children[0].value = (string)tokens.actual.value; tokens.SelectNext(); if (tokens.actual.type != "AS") { throw new SystemException($"'As' is required in an variable declaration (position {tokens.position}) [Line: {CurrentLine}]"); } tokens.SelectNext(); root.children[1] = parseType(); if (tokens.actual.type != "LINEBREAK") //expect linebreak after the expression; { throw new SystemException($"No LINEBREAK after Variable declaration(position {tokens.position}) [Line: {CurrentLine}]"); } CurrentLine++; tokens.SelectNext(); //go to next token after linebreak return(root); case "IF": root = new IfNode(); tokens.SelectNext(); root.children[0] = ParseRelExpression(); if (tokens.actual.type != "THEN") //expect THEN after the rel expression; { throw new SystemException($"THEN is required after an IF's Relative Expression (position {tokens.position}) [Line: {CurrentLine}]"); } tokens.SelectNext(); if (tokens.actual.type != "LINEBREAK") //expect linebreak after THEN; { throw new SystemException($"No LINEBREAK after Relative Expression (position {tokens.position}) [Line: {CurrentLine}]"); } CurrentLine++; tokens.SelectNext(); //go to next token after linebreak root.children[1] = ParseStatements("if"); //already goes to next line, no select next required if (tokens.actual.type == "ELSE") { tokens.SelectNext(); if (tokens.actual.type != "LINEBREAK") //expect linebreak after ELSE; { throw new SystemException($"No LINEBREAK after ELSE (position {tokens.position}) [Line: {CurrentLine}]"); } CurrentLine++; tokens.SelectNext(); //go to next token after linebreak root.children[2] = ParseStatements("else"); //left the token after the END, so it is probably on IF (END IF\n) } if (tokens.actual.type != "IF") //expect IF after the statements END for END IF\n construction; { throw new SystemException($"IF section end symbol not found, found END instead of END IF (position {tokens.position}) [Line: {CurrentLine}]"); } tokens.SelectNext(); if (tokens.actual.type != "LINEBREAK") //expect linebreak after THEN; { throw new SystemException($"No LINEBREAK after Relative Expression (position {tokens.position}) [Line: {CurrentLine}]"); } CurrentLine++; tokens.SelectNext(); //go to next token after linebreak return(root); default: return(new NoOp()); } }