//------------------------------------------------------------------------------------------------------------ private void ifStatement(string[] tokens, int lineNumber) { // Assume only one token to the left of the comparator eg. 20 if x == y goto 50 // [2] = Left, [3] = Comparator, [4] = Right, [5] = 'goto', [6] = LineNumber if (!tokens.Contains("goto")) { throw new SystemException($"'if' statement missing corresponding 'goto' -on code line {lineNumber}"); } string left = tokens[2]; string comparator = tokens[3]; string right = tokens[4]; string goTo = tokens[5]; string gotoLine = tokens[6]; TableEntry leftEntry, rightEntry; //------------------Begin Validations--------Symbol table update------------ // Validate left of comparator if (Int32.TryParse(left, out int intLeft)) // Third token is a number (constant) { leftEntry = _symbolTable.FindOrAddConst(intLeft); _compiledCode.Add(leftEntry.Symbol(), leftEntry.Location()); } else if (Toolbelt.IsValidVariable(left)) // Third token is a valid variable { char leftVar = Convert.ToChar(left); leftEntry = _symbolTable.FindOrAddVar((int)leftVar); } else { throw new SystemException($"{left} not valid following 'if' keyword -on code line {lineNumber}"); } // Validate comparator if (!Toolbelt.IsComparator(comparator)) // Fourth token is a valid comparator { throw new SystemException($"{comparator} is is not a valid comparator in 'if' statement -on code line {lineNumber}"); } // Validate left of comparator if (Int32.TryParse(right, out int intRight)) // Third token is a number (constant) { rightEntry = _symbolTable.FindOrAddConst(intRight); _compiledCode.Add(rightEntry.Symbol(), rightEntry.Location()); } else if (Toolbelt.IsValidVariable(right)) // Third token is a valid variable { char rightVar = Convert.ToChar(right); rightEntry = _symbolTable.FindOrAddVar((int)rightVar); } else { throw new SystemException($"{right} not valid following comparator in 'if' statement -on code line {lineNumber}"); } // validate that 'goto' is in position 5 if (goTo != "goto") { throw new SystemException($"Expected 'goto' after comparison in 'if' statement. ({goTo}) -on code line {lineNumber}"); } // validate that following the 'goto' is a numeric value if (!Int32.TryParse(gotoLine, out int intGotoLine)) { throw new SystemException($"'{gotoLine}' invalid token following 'goto' in 'if' statement. Integer value expected. -on code line {lineNumber}"); } //-------------End Validations-------------------- if (leftEntry == null || rightEntry == null) { throw new SystemException($"Unknown error occurred in 'if/goto' statement -on code line {lineNumber}"); } // lookup goto line number in symbol table var gotoLineEntry = _symbolTable.FindLineNumber(intGotoLine); var gotoLineNumber = 00; bool needsFlag = false; if (gotoLineEntry != null) { gotoLineNumber = gotoLineEntry.Location(); } else { needsFlag = true; } // perform calculations with right operand // add appropriate branch command switch (comparator) { case "==": _compiledCode.Add(Word.Build((int)EPC.Code.LOAD, leftEntry.Location()), _workingLineNumber++); _compiledCode.Add(Word.Build((int)EPC.Code.SUBTRACT, rightEntry.Location()), _workingLineNumber++); if (needsFlag) { _flags.Add(_workingLineNumber, intGotoLine); } _compiledCode.Add(Word.Build((int)EPC.Code.BRANCHZERO, gotoLineNumber), _workingLineNumber++); break; case "!=": // check if greater than _compiledCode.Add(Word.Build((int)EPC.Code.LOAD, rightEntry.Location()), _workingLineNumber++); _compiledCode.Add(Word.Build((int)EPC.Code.SUBTRACT, leftEntry.Location()), _workingLineNumber++); if (needsFlag) { _flags.Add(_workingLineNumber, intGotoLine); } _compiledCode.Add(Word.Build((int)EPC.Code.BRANCHNEG, gotoLineNumber), _workingLineNumber++); // check if less than _compiledCode.Add(Word.Build((int)EPC.Code.LOAD, leftEntry.Location()), _workingLineNumber++); _compiledCode.Add(Word.Build((int)EPC.Code.SUBTRACT, rightEntry.Location()), _workingLineNumber++); if (needsFlag) { _flags.Add(_workingLineNumber, intGotoLine); } _compiledCode.Add(Word.Build((int)EPC.Code.BRANCHNEG, gotoLineNumber), _workingLineNumber++); break; case "<": _compiledCode.Add(Word.Build((int)EPC.Code.LOAD, leftEntry.Location()), _workingLineNumber++); _compiledCode.Add(Word.Build((int)EPC.Code.SUBTRACT, rightEntry.Location()), _workingLineNumber++); if (needsFlag) { _flags.Add(_workingLineNumber, intGotoLine); } _compiledCode.Add(Word.Build((int)EPC.Code.BRANCHNEG, gotoLineNumber), _workingLineNumber++); break; case ">": _compiledCode.Add(Word.Build((int)EPC.Code.LOAD, rightEntry.Location()), _workingLineNumber++); _compiledCode.Add(Word.Build((int)EPC.Code.SUBTRACT, leftEntry.Location()), _workingLineNumber++); if (needsFlag) { _flags.Add(_workingLineNumber, intGotoLine); } _compiledCode.Add(Word.Build((int)EPC.Code.BRANCHNEG, gotoLineNumber), _workingLineNumber++); break; case "<=": _compiledCode.Add(Word.Build((int)EPC.Code.LOAD, leftEntry.Location()), _workingLineNumber++); _compiledCode.Add(Word.Build((int)EPC.Code.SUBTRACT, rightEntry.Location()), _workingLineNumber++); if (needsFlag) { _flags.Add(_workingLineNumber, intGotoLine); } _compiledCode.Add(Word.Build((int)EPC.Code.BRANCHNEG, gotoLineNumber), _workingLineNumber++); if (needsFlag) { _flags.Add(_workingLineNumber, intGotoLine); } _compiledCode.Add(Word.Build((int)EPC.Code.BRANCHZERO, gotoLineNumber), _workingLineNumber++); break; case ">=": _compiledCode.Add(Word.Build((int)EPC.Code.LOAD, rightEntry.Location()), _workingLineNumber++); _compiledCode.Add(Word.Build((int)EPC.Code.SUBTRACT, leftEntry.Location()), _workingLineNumber++); if (needsFlag) { _flags.Add(_workingLineNumber, intGotoLine); } _compiledCode.Add(Word.Build((int)EPC.Code.BRANCHNEG, gotoLineNumber), _workingLineNumber++); if (needsFlag) { _flags.Add(_workingLineNumber, intGotoLine); } _compiledCode.Add(Word.Build((int)EPC.Code.BRANCHZERO, gotoLineNumber), _workingLineNumber++); break; } }