public List <Step> ParseTokens() // Due to the size of this method I am not using IEnumerable 'yield return' as it is hard to track nested return statements. { List <Step> EvaluationSteps = new List <Step>(); while (tokQueue.More()) // While more tokens in queue (returns bool) { Token nextTok = tokQueue.MoveNext(); // pop next out of TokenQueue if (nextTok.Type().Equals("identifier")) // All statements in our language begin with identifiers. // We do not know what we have at this point, so let's check the identifier to see which tokens should follow after. { if (Syntax.IsType(nextTok.Value())) // If it is a var type, e.g "int", "string" - if it is, this is a variable declaration ("int x = 0;") { /* * EXPECTED PATTERN: varType varName = expr; * e.g int x = 2 + y*10; * e.g string testing = "Hello World!"; */ VarDeclare varDeclare = CaptureVarDeclare(nextTok.Value()); // Call method with argument storing the type of var being declared, e.g 'string' EvaluationSteps.Add(varDeclare); // Add Event object to the overall list of 'Steps' for the Evaluator module } else if (nextTok.Value().ToLower().Equals("if")) // Start of an if statement { /* * EXPECTED PATTERN: if(operands) { codeblock } * e.g if (x > 0) { * output(x); * x = 0; * } */ IfStatement ifState = CaptureIfStatement(); // Capture all useful information of the following if statements // We COULD have an else statement, so let's check the next token // First check there are still MORE tokens to check to avoid out of range errors // Then check it's an IDENTIFIER ('else') if (tokQueue.More() && tokQueue.Next().Type().Equals("identifier") && tokQueue.Next().Value().Equals("else")) { // If next token is 'else' and an identifier ElseStatement elseState = CaptureElseStatement(); EvaluationSteps.Add(ifState); EvaluationSteps.Add(elseState); // Add if state then else directly after (ordered list!) } else { EvaluationSteps.Add(ifState); // if no 'else' statement exists just add the if statement } } else if (nextTok.Value().ToLower().Equals("while")) { IfStatement template = CaptureIfStatement(); // Trick the program to think it's capturing an if statement WhileLoop whileLoop = new WhileLoop(template.GetCBContents(), template.GetOp1(), template.GetOp2(), template.GetComparator()); // Reuse code from the if statement because while & if follow the exact same structure: // while (condition) { codeblock } // if (condition) { codeblock } // We just captured an if statement 'template' then used the information it collected to create a while loop instead EvaluationSteps.Add(whileLoop); } else if (GrammarTokenCheck(tokQueue.Next(), "(")) // This condition will also return true if it finds an if/while statement, so it is AFTER the check for those. // As we're using else if, if the program didn't recognise a 'while' or 'if' statement, we will reach this check // We can GUARANTEE now that this must be a function call as 'if(){}' and 'while(){}' have been ruled out { /* * EXPECTED PATTERN: funcName(expr); // Can take any expression! * e.g output("Testing"); * e.g output(1 + 23); * e.g output(x); */ tokQueue.MoveNext(); // Skip the '(' token // Remember, nextTok still holds the value of the token before '(' // This is the name of our function ('funcName') FuncCall funcCall = CaptureFunctionCall(nextTok.Value()); // Pass the function name, e.g 'output' EvaluationSteps.Add(funcCall); } else if (GrammarTokenCheck(tokQueue.Next(), "=")) // .Next() is PEEK not POP. // Check if the token AFTER this one is "=" { /* * EXPECTED PATTERN: varName = expr; * e.g x = 2 + y*10; * e.g testing = "Hello World!"; */ tokQueue.MoveNext(); // Skip the '=' token // Remember, nextTok still holds the value of the token before the '=' // This is the name of our variable to change ('varName') VarChange varChan = CaptureVarChange(nextTok.Value()); EvaluationSteps.Add(varChan); } else { throw new SyntaxError(); } // If there is a rogue 'else' statement it will be caught in this // Else statements are not 'looked' for on there own, they are only recognised when an if statement is found } else { throw new SyntaxError(); // Statement doesn't begin with identifier - throw error. } } return(EvaluationSteps); }