//------------------------------------------------------------------------------------------------------------ private void letStatement(string[] tokens, int lineNumber) { // Check that first character after 'let' is a valid variable if (!Toolbelt.IsValidVariable(tokens[2])) { throw new SystemException($"Invalid token ({tokens[2]}) after keyword 'let' -on code line {lineNumber}"); } // Check that the next character is the '=' sign if (!(tokens[3].Length == 1 && '=' == Convert.ToChar(tokens[3]))) { throw new SystemException($"Invalid token ({tokens[3]} after assignment variable in 'let' statement -on code line {lineNumber}"); } putInSymbolTable(tokens); // determine location of variable to store result in char storeVar = Convert.ToChar(tokens[2]); int storeLoc = _symbolTable.FindVariable((int)storeVar).Location(); if (tokens.Length > 5) // expression follows '=' sign { compileExpression(tokens, lineNumber, storeLoc); } else // simple value or variable assignment follows '=' sign { compileAssignment(tokens, lineNumber, storeLoc); } }
//------------------------------------------------------------------------------------------------------------ private void inputStatement(string[] tokens, int lineNumber, out int operationCode, out int operand) { if (!Toolbelt.IsValidVariable(tokens[2])) { throw new SystemException($"{tokens[2]} not valid for variable name following 'input' keyword -on code line {lineNumber}"); } char variable = Convert.ToChar(tokens[2]); var entry = _symbolTable.FindOrAdd((int)variable, TableEntry.VARIABLE); // Generate EPML instruction operationCode = (int)EPC.Code.READ; operand = entry.Location(); _compiledCode.Add(Word.Build(operationCode, operand), _workingLineNumber++); }
//------------------------------------------------------------------------------------------------------------ private void putInSymbolTable(string[] tokens) { // place all variables and constants in the symbol table if missing for (int i = 2; i < tokens.Length; ++i) { var token = tokens[i]; if (Int32.TryParse(token, out int intToken)) { var tempEntry = _symbolTable.FindOrAddConst(intToken); _compiledCode.Add(tempEntry.Symbol(), tempEntry.Location()); } else if (Toolbelt.IsValidVariable(token)) { _symbolTable.FindOrAddVar(Convert.ToChar(token)); } } }
//------------------------------------------------------------------------------------------------------------ private void printStatement(string[] tokens, int lineNumber, out int operationCode, out int operand) { if (tokens.Length == 2) { throw new SystemException($"Missing variable after 'print' keyword -on code line {lineNumber}"); } if (!Toolbelt.IsValidVariable(tokens[2])) { throw new SystemException($"Invalid token ({tokens[2]}) following 'print' statement. Single letter variable expected -on code line {lineNumber}"); } operationCode = (int)EPC.Code.WRITE; char printVar = Convert.ToChar(tokens[2]); var printEntry = _symbolTable.GetEntry((int)printVar); if (printEntry == null) { throw new SystemException($"Variable '{tokens[2]}' is missing from the Symbol Table"); } operand = printEntry.Location(); _compiledCode.Add(Word.Build(operationCode, operand), _workingLineNumber++); }
//------------------------------------------------------------------------------------------------------------ private void forStatement(string[] tokens, int lineNumber) { // Place increment value into the symbol table _symbolTable.AddConst(FOR_LOOP_INCREMENT); if (findNext(out int intNextLineLocation)) // validate there is a 'next' statement { // validate that the 'for' statement following the correct syntax // [2] = variable, [3] = comparator, [4] = var/const, [5] = 'to', [6] = var/const string strLHS = tokens[2]; string strRHS = tokens[4]; string strCheck = tokens[6]; if (Toolbelt.IsValidVariable(strLHS) && tokens[3] == "=" && tokens[5] == "to") { putInSymbolTable(tokens); // Format the assignment string so it can be properly processed string assignment = $"00 let {strLHS} = {strRHS}"; letStatement(assignment.Split(' '), lineNumber); // after let statement is process, the next entry will be the start of the commands in the loop _forLoopEntries.Push(ForLoopEntry.Make( step: _workingLineNumber, lhs: _symbolTable.Find(strLHS).Location(), rhs: _symbolTable.Find(strCheck).Location(), increment: FOR_LOOP_INCREMENT )); } else { throw new SystemException($"Invalid 'for' statement -on code line {lineNumber}"); } } else { throw new SystemException($"'for' missing 'next' statment -on code line {lineNumber}"); } }
//------------------------------------------------------------------------------------------------------------ private void compileAssignment(string[] tokens, int lineNumber, int storeLoc) { var token = tokens[4]; int loc = -1; if (Int32.TryParse(token, out int intValue)) // assigning a Constant { loc = _symbolTable.FindConstant(intValue).Location(); } else if (Toolbelt.IsValidVariable(token)) // assigning a variable value { if (Char.TryParse(token, out char chVar)) { loc = _symbolTable.FindVariable((int)chVar).Location(); } else { throw new SystemException($"Something bad happened -on code line {lineNumber}"); } } else { throw new SystemException($"Invalid character following '=' in 'let' statement -on code line {lineNumber}"); } if (loc >= 0) { // load constant or variable value from memory and store in assignment variable _compiledCode.Add(Word.Build((int)EPC.Code.LOAD, loc), _workingLineNumber++); if (_symbolTable.HasLocation(storeLoc) && _symbolTable.AtLocation(storeLoc).IsConst()) { throw new SystemException($"Cannot override constant value at memory[{storeLoc}] -on code line {lineNumber}"); } _compiledCode.Add(Word.Build((int)EPC.Code.STORE, storeLoc), _workingLineNumber++); } }
//------------------------------------------------------------------------------------------------------------ public TableEntry Find(string searchFor) { if (Int32.TryParse(searchFor, out int intConstant)) { // search string is a constant return(FindConstant(intConstant)); } else if (Toolbelt.IsValidVariable(searchFor)) { // search string is a variable if (Char.TryParse(searchFor, out char chVar)) { return(FindVariable((int)chVar)); } else { throw new SystemException($"SymbolTable Find({searchFor}) unexpected error. Something bad happened"); } } else { throw new SystemException($"SymbolTable Find({searchFor}) search string must be a variable or constant"); } }
//------------------------------------------------------------------------------------------------------------ private int evaluatePostfix(string postfix, int lineNumber) { Stack <string> expression = new Stack <string>(postfix.Split(' ').Reverse()); Stack <int> operands = new Stack <int>(); Stack <int> temps = new Stack <int>(); int firstTemp = _symbolTable.TempLocation; while (expression.Count > 0) { string working = expression.Pop(); if (Int32.TryParse(working, out int intWorking)) { // working string is an integer value operands.Push(_symbolTable.FindConstant(intWorking).Location()); } else if (Toolbelt.IsValidVariable(working)) { char workingChar = Convert.ToChar(working); operands.Push(_symbolTable.FindVariable(Convert.ToInt32(workingChar)).Location()); } else if (Toolbelt.IsOperator(working)) { int left, right; char op = Convert.ToChar(working); if (operands.Count() >= 2) { right = operands.Pop(); left = operands.Pop(); } else if (operands.Count() == 1 && temps.Count >= 1) { right = temps.Pop(); left = operands.Pop(); } else if (temps.Count >= 2) { right = temps.Pop(); left = temps.Pop(); } else { return(-1); } // load 'left' from memory _compiledCode.Add(Word.Build((int)EPC.Code.LOAD, left), _workingLineNumber++); // perform calculation on 'left' switch (op) { case '+': _compiledCode.Add(Word.Build((int)EPC.Code.ADD, right), _workingLineNumber++); break; case '-': _compiledCode.Add(Word.Build((int)EPC.Code.SUBTRACT, right), _workingLineNumber++); break; case '*': _compiledCode.Add(Word.Build((int)EPC.Code.MULTIPLY, right), _workingLineNumber++); break; case '/': _compiledCode.Add(Word.Build((int)EPC.Code.DIVIDE, right), _workingLineNumber++); break; } // store result in 'temp' temps.Push(firstTemp - temps.Count()); if (_symbolTable.HasLocation(temps.Peek()) && _symbolTable.AtLocation(temps.Peek()).IsConst()) { throw new SystemException($"Cannot override constant value at memory[{temps.Peek()}] -on code line {lineNumber}"); } _compiledCode.Add(Word.Build((int)EPC.Code.STORE, temps.Peek()), _workingLineNumber++); } else { return(-1); } } return(temps.Pop()); }
//------------------------------------------------------------------------------------------------------------ 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; } }