public void AddSymbolStruct() { var t = new SymbolTable(); Symbol sym; sym.rlabel = "test"; sym.lc = "5"; sym.usage = Usage.EQUATED; sym.val = "DERP"; sym.relocations = 0; t.AddSymbol(sym); Assert.AreEqual(sym, t.GetSymbol("test")); }
/** * Reads an expression and evaluates it as much as it can. If the parsing is * successful, the operand variable is replaced with the most fully parsed * version of the expression possible. If the expression cannot be parsed due * to an error in the expression, thie function returns false and an error is * added to the passed in IntermediateLine parameter. * * @refcode EX1, EX2, EX3 * @errtest N/A * @errmsg ES.2, ES.19, ES.20, ES.22, ES.23, ES.24, ES.27, ES.30, ES.31, ES.32, ES.33 * @author Mark Mathis * @creation April 18, 2011 * @modlog * - April 18, 2011 - Mark - Parses operand expressions (EX1). * - April 19, 2011 - Mark - Parses EQU expressions (EX2). * - April 19, 2011 - Mark - Parses ADC expressions (EX3). * - April 19, 2011 - Mark - Errors are caught and reported in all expressions. * - May 13, 2011 - Mark - Added rec and modifications parameters. * - May 14, 2011 - Mark - Now keeps track of adjustments required for pass 2. * @teststandard Andrew Buelow * @codestandard Mark Mathis * * @param operand the expression to parse, will contain the outgoing value of the expression * @param type the type of expression to be parsed * @param interLine the intermediate line containing this expression * @param symb the symbol table for this source code file * @param rec the modification record for keeping track of adjustments in instruction expressions * and ADC/ADCe expressions * @param modifications the number of adjustments needed for a EQU/EQUe expression * @param maxOperators the maximum number of operators allowed in this type of expression * * @return true if the expression is successfully parsed and evaluated. * false if an error is found. */ public static bool ParseExpression(ref string operand, OperandParser.Expressions type, IntermediateLine interLine, ref SymbolTable symb, ModificationRecord rec, out int modifications, int maxOperators = 1) { modifications = 0; if (operand != null && operand.Length > 0) { // if the expression is just a star, take care of it and return if (operand.Length == 1 && operand[0] == '*') { modifications++; rec.AddAdjustment(true, symb.ProgramName); operand = interLine.ProgramCounter; return true; } char[] validOperators = { '+', '-' }; // if there are too many operators, give an error List<string> operands = operand.Split(validOperators, StringSplitOptions.RemoveEmptyEntries).ToList(); if (operands.Count - 1 > maxOperators) { // error, too many operators interLine.AddError(Errors.Category.Serious, 22); return false; } // check for absolute ADC/ADCe bool absolute = false; if (operand[0] == '+' && type == Expressions.ADC) { absolute = true; operand = operand.Substring(1); } List<char> operators = new List<char>(); int pos = operand.IndexOfAny(validOperators, 0); while (pos != -1) { operators.Add(operand[pos]); pos = operand.IndexOfAny(validOperators, pos + 1); } // check that we have the correct number of operands if (operators.Count != operands.Count - 1) { // error, wrong number of operators interLine.AddError(Errors.Category.Serious, 24); return false; } // it can't always be that easy switch (type) { case OperandParser.Expressions.Operand: { char oprtr; string opr2; string star; if (operand[0] == '*') { star = interLine.ProgramCounter; oprtr = operand[1]; opr2 = operand.Substring(2); rec.AddAdjustment(true, symb.ProgramName); Tokenizer.TokenKinds valid; Tokenizer.GetTokenKind(opr2, out valid); if (valid == Tokenizer.TokenKinds.Label_Or_Command) { if (2 <= opr2.Length && opr2.Length <= 32) { if (symb.ContainsSymbol(opr2)) { if (symb.GetSymbol(opr2).usage == Usage.EQUATED) { opr2 = Convert.ToInt32(symb.GetSymbol(opr2).val, 16).ToString(); } else if (symb.GetSymbol(opr2).usage == Usage.LABEL) { opr2 = Convert.ToInt32(symb.GetSymbol(opr2).lc, 16).ToString(); rec.AddAdjustment(oprtr == '+', symb.ProgramName); } } } else { // error:label is too long Logger.Log("ERROR: ES.2 encountered", "OperandParser"); interLine.AddError(Errors.Category.Serious, 2); return false; } } else if (valid == Tokenizer.TokenKinds.Number) { if (!(0 <= Convert.ToInt32(opr2) && Convert.ToInt32(opr2) <= 1023)) { // error, the number is out of bounds Logger.Log("ERROR: ES.28 encountered", "OperandParser"); interLine.AddError(Errors.Category.Serious, 27); return false; } } else if (opr2 == "*") { // error: star used multiple times interLine.AddError(Errors.Category.Serious, 19); return false; } else { //error, must be number or previously equated symbol Logger.Log("ERROR: ES.29 encountered", "OperandParser"); interLine.AddError(Errors.Category.Serious, 27); return false; } Tokenizer.GetTokenKind(opr2, out valid); if (valid == Tokenizer.TokenKinds.Number) { int result = -1; // if the method gets here, then it's using a number or // symbol we can deal with switch (oprtr) { case '+': { result = Convert.ToInt32(star, 16) + Convert.ToInt32(opr2); } break; case '-': { result = Convert.ToInt32(star, 16) - Convert.ToInt32(opr2); } break; default: { // error invalid operator in expression Logger.Log("ERROR: ES.30 encountered", "OperandParser"); interLine.AddError(Errors.Category.Serious, 30); return false; } } if (0 <= result && result <= 1023) { operand = Convert.ToString(result,16); } else { // error: computation out of bounds Logger.Log("ERROR: ES.27 encountered", "OperandParser"); interLine.AddError(Errors.Category.Serious, 27); return false; } } } else { //error invalid operand expression Logger.Log("ERROR: ES.31 encountered", "OperandParser"); interLine.AddError(Errors.Category.Serious, 31); return false; } } break; case Expressions.EQU: { for (int i = 0; i < operands.Count; i++) { string label = operands[i]; Tokenizer.TokenKinds tokenkind; Tokenizer.GetTokenKind(label, out tokenkind); if (label == "*") { if (i == 0) { operands[i] = Convert.ToInt32(Parser.LC, 16).ToString(); modifications++; } else { // error, star must be first operand Logger.Log("ERROR: invalid star notation in expression.", "OperandParser"); interLine.AddError(Errors.Category.Serious, 19); return false; } } else if (symb.ContainsSymbol(label)) { Symbol operSym = symb.GetSymbol(label); if (operSym.usage == Usage.EQUATED) { operands[i] = Convert.ToInt32(operSym.val, 16).ToString(); modifications += operSym.relocations; } else if (operSym.usage == Usage.LABEL) { operands[i] = Convert.ToInt32(operSym.lc, 16).ToString(); modifications++; } else { // error, can only use equated symbols or local references Logger.Log("ERROR: ES.32 encountered", "OperandParser"); interLine.AddError(Errors.Category.Serious, 32); return false; } } else if (tokenkind == Tokenizer.TokenKinds.Number) { // this needs to be caught, so the next else doesn't get // tripped. but there's nothing to do herp. // I will tell you stories of my people. } else { // undefined symbol Logger.Log("ERROR: ES.20 encountered", "OperandParser"); interLine.AddError(Errors.Category.Serious, 20); return false; } } operands.Reverse(); operators.Reverse(); string possibleOperand = EvaluateExpression(new Stack<string>(operands), new Stack<char>(operators)); if (0 <= int.Parse(possibleOperand) && int.Parse(possibleOperand) <= 1023) { operand = Convert.ToString(int.Parse(possibleOperand), 16); } else { // error, calculation must be within the range of 0 to 1023 Logger.Log("ERROR: ES.27 encountered", "OperandParser"); interLine.AddError(Errors.Category.Serious, 27); return false; } } break; case Expressions.ADC: { bool noLabels = true; for (int i = 0; i < operands.Count; i++) { string label = operands[i]; if (label == "*") { noLabels = false; if (i == 0) { operands[i] = Convert.ToInt32(interLine.ProgramCounter,16).ToString(); rec.AddAdjustment(true, symb.ProgramName); modifications++; } else { // error, star must be first operand Logger.Log("ERROR: ES.19 encountered", "OperandParser"); interLine.AddError(Errors.Category.Serious, 19); return false; } } else if (symb.ContainsSymbol(label)) { noLabels = false; Symbol operSym = symb.GetSymbol(label); if (operSym.usage == Usage.LABEL) { operands[i] = Convert.ToInt32(operSym.lc, 16).ToString(); modifications++; if (i > 0) { rec.AddAdjustment(operators[i - 1] == '+', symb.ProgramName); } else { rec.AddAdjustment(true, symb.ProgramName); } } else if (operSym.usage == Usage.EXTERNAL) { noLabels = false; operands[i] = "0"; modifications++; if (i > 0) { rec.AddAdjustment(operators[i - 1] == '+', operSym.rlabel); } else { rec.AddAdjustment(true, operSym.rlabel); } } else { // error: symbols can only be external, local reference // in ADC/ADCe expressions Logger.Log("ERROR: ES.33 encountered", "OperandParser"); interLine.AddError(Errors.Category.Serious, 33); return false; } } } if (noLabels) { rec.AddAdjustment(true, symb.ProgramName); modifications++; } bool allNumbers = true; foreach (string op in operands) { Tokenizer.TokenKinds tokenKind; Tokenizer.GetTokenKind(op, out tokenKind); if (tokenKind == Tokenizer.TokenKinds.Number) { allNumbers = allNumbers && true; } else { allNumbers = false; } } if (allNumbers) { operands.Reverse(); operators.Reverse(); operand = EvaluateExpression(new Stack<string>(operands), new Stack<char>(operators)); operand = Convert.ToString(Convert.ToInt32(operand), 16); } else { operand = operands[0]; for (int i = 0; i + 1 < operands.Count; i++) { operand += operators[i] + operands[i + 1]; } } if (absolute) modifications = 0; } break; } } return true; }
/** * Parses the reset directive, ensuring that the reset operand is a number * that is higher than any previously or currently used location counter. * * @param interLine the intermediate line to process * @param symb symbol table reference * * @refcode D2 * @errtest * N/A * @errmsg ES.08, ES.10, ES.25 * @author Mark Mathis * @creation April 15, 2011 * @modlog * - April 17, 2011 - Mark - Changes the location counter to the operand value. * - April 17, 2011 - Mark - Checks that the operand value is valid. * @teststandard Andrew Buelow * @codestandard Mark Mathis */ private static void ParseReset(ref IntermediateLine interLine, ref SymbolTable symb) { Logger.Log("Parsing RESET directive", "DirectiveParser"); if (interLine.Label != null) { // the operand of the RESET directive must either be an equated label // or a literal number. if (symb.ContainsSymbol(interLine.DirectiveOperand) && symb.GetSymbol(interLine.DirectiveOperand).usage == Usage.EQUATED) { int curLC = Convert.ToInt32(Parser.LC, 16); int newLC = Convert.ToInt32(symb.GetSymbol(interLine.DirectiveOperand).val, 16); if (curLC < newLC) { Parser.LC = Convert.ToString(newLC,16); } else { // error, attempt to use a previously used LC value Logger.Log("ERROR: ES.08 encountered.", "DirectiveParser"); interLine.AddError(Errors.Category.Serious, 8); } } else if (interLine.DirectiveLitOperand == OperandParser.Literal.NUMBER) { int curLC = Convert.ToInt32(Parser.LC, 16); int newLC = Convert.ToInt32(interLine.DirectiveOperand, 16); if (curLC < newLC) { Parser.LC = Convert.ToString(newLC, 16); } else { // error, attempt to use a previously used LC value Logger.Log("ERROR: ES.08 encountered.", "DirectiveParser"); interLine.AddError(Errors.Category.Serious, 8); } } else { // error invalid value Logger.Log("ERROR: ES.10 encountered.", "DirectiveParser"); interLine.AddError(Errors.Category.Serious, 10); } } else { // error, label is required for reset directive Logger.Log("ERROR: ES.25 encountered.", "DirectiveParser"); interLine.AddError(Errors.Category.Serious,25); } Logger.Log("Finished parsing RESET directive", "DirectiveParser"); }
/** * Parses the equ directive, ensuring that the operand is a valid value for an * equated symbol. * * @param interLine the intermediate line to process * @param symb symbol table reference * @param maxOp maximum number of operations to process * * @refcode D3 * @errtest * N/A * @errmsg ES.21, ES.22, ES.26 * @author Mark Mathis * @creation April 15, 2011 * @modlog * @teststandard Andrew Buelow * @codestandard Mark Mathis */ private static void ParseEqu(ref IntermediateLine interLine, ref SymbolTable symb, int maxOp = 1) { Logger.Log("Parsing EQU directive", "DirectiveParser"); bool success = true; if (symb.ContainsSymbol(interLine.Label)) { Symbol equSym = symb.RemoveSymbol(interLine.Label); interLine.ProgramCounter = equSym.lc; if (interLine.DirectiveLitOperand == OperandParser.Literal.NUMBER) { // check that number is in bounds int num = BinaryHelper.HexToInt(interLine.DirectiveOperand, 10); if (0 <= num && num <= 1023) { equSym.usage = Usage.EQUATED; equSym.val = interLine.DirectiveOperand; } else { // error: out of bounds Logger.Log("ERROR: ES.26 encountered", "DirectiveParser"); interLine.AddError(Errors.Category.Serious, 26); success = false; } } else if (symb.ContainsSymbol(interLine.DirectiveOperand) && symb.GetSymbol(interLine.DirectiveOperand).usage == Usage.EQUATED) { // do stuff with the symbol equSym.usage = Usage.EQUATED; equSym.val = symb.GetSymbol(interLine.DirectiveOperand).val; equSym.relocations = symb.GetSymbol(interLine.DirectiveOperand).relocations; } else if (interLine.DirectiveLitOperand == OperandParser.Literal.EXPRESSION) { string oper = interLine.DirectiveOperand; int modifications; success = OperandParser.ParseExpression(ref oper, OperandParser.Expressions.EQU, interLine, ref symb, new ModificationRecord("junk"), out modifications, maxOp); equSym.usage = Usage.EQUATED; equSym.val = oper; equSym.relocations = modifications; } else { // error: invalid operand for equ Logger.Log("ERROR: EW.21 encountered", "DirectiveParser"); interLine.AddError(Errors.Category.Serious, 21); success = false; } interLine.ProgramCounter = null; equSym.lc = null; if (success) { // this needs to be checked here in case ParseExpression // finds an error int finval = Convert.ToInt32(equSym.val, 16); if (!(0 <= finval && finval <= 1023)) { // the final value of the equ is out of bounds Logger.Log("ERROR: EW.22 encountered", "DirectiveParser"); interLine.AddError(Errors.Category.Serious, 22); success = false; } symb.AddSymbol(equSym); } } Logger.Log("Finished parsing EQU directive", "DirectiveParser"); }
/** * Parses the entry directive, ensuring that the operand is a valid value * for an equated symbol using extended expressions. * * @param interLine the intermediate line to process * @param symb symbol table reference * * @refcode D5 * @errtest * N/A * @errmsg EW.05 * @author Mark Mathis * @creation April 17, 2011 * @modlog * @teststandard Andrew Buelow * @codestandard Mark Mathis */ private static void ParseEntry(ref IntermediateLine interLine, ref SymbolTable symb) { Logger.Log("Parsing ENTRY directive", "DirectiveParser"); // check for a label if (interLine.Label != null) { // entry doesn't expect a label Logger.Log("ERROR: EW.05 encountered", "DirectiveParser"); interLine.AddError(Errors.Category.Warning, 5); } if (symb.ContainsSymbol(interLine.DirectiveOperand)) { if (symb.GetSymbol(interLine.DirectiveOperand).usage != Usage.EQUATED) { Symbol tempsym = symb.RemoveSymbol(interLine.DirectiveOperand); tempsym.usage = Usage.ENTRY; symb.AddSymbol(tempsym); } } else { symb.AddSymbol(interLine.DirectiveOperand, null, Usage.ENTRY); } Logger.Log("Finished parsing ENTRY directive", "DirectiveParser"); }
/** * Parses the end directive, ensuring that the end operand is the same as * the start directive's rlabel. * * @param interLine the intermediate line to process * @param symb symbol table reference * * @refcode D7 * @errtest * N/A * @errmsg EF.05, EW.05 * @author Mark Mathis * @creation April 9, 2011 * @modlog * - April 9, 2011 - Mark - Not sure if needed. * - April 14, 2011 - Mark - Moved into DirectiveParser class. * - April 17, 2011 - Mark - Actually checks that the operand is correct. * - April 19, 2011 - Mark - Reports errors. * @teststandard Andrew Buelow * @codestandard Mark Mathis */ private static void ParseEnd(ref IntermediateLine interLine, ref SymbolTable symb) { Logger.Log("Parsing END directive", "DirectiveParser"); // check to see if this line has a label if (interLine.Label != null) { // the end directive should not have a label interLine.AddError(Errors.Category.Warning, 5); } // check to see if the operand of the END directive matches the program name if (!(symb.ContainsSymbol(interLine.DirectiveOperand) && symb.GetSymbol(interLine.DirectiveOperand).usage == Usage.PRGMNAME)) { // error things interLine.AddError(Errors.Category.Fatal, 5); } Logger.Log("Finished parsing END directive.", "DirectiveParser"); }
/** * Parses a single line of source code. * * @param line current line to parse * @param lineNum line number of current line * @param symb symbol table reference * @return the line to be parsed as a single line in the intermediate file * * @refcode N/A * @errtest * N/A * @errmsg * N/A * @author Mark Mathis * @creation April 8, 2011 * @modlog * - April 9, 2011 - Mark - ParseLine parses lines with instructions. * - April 9, 2011 - Mark - ParseLine parses lines with directives. * - April 9, 2011 - Mark - Increments program counter after parsing instructions. * - April 9, 2011 - Mark - Sets OpCategory = "_ERROR" if the token expected to be * an instruction category or a directive is niether of those. * - April 10, 2011 - Mark - Properly handles lines that only have a comment. * @teststandard Andrew Buelow * @codestandard Mark Mathis */ private IntermediateLine ParseLine(string line, short lineNum, ref SymbolTable symb) { Logger.Log("Parsing line " + lineNum, "Parser"); string token = ""; Tokenizer.TokenKinds tokenKind = Tokenizer.TokenKinds.Empty; // make Intermediate version of this line to be returned IntermediateLine interLine = new IntermediateLine(line, lineNum); // check for a label at the beginning of the line if (line.Trim().Length > 0) { if (char.IsLetter(line[0])) { Logger.Log(String.Format("Line {0} has a label, parsing label", lineNum), "Parser"); Tokenizer.GetNextToken(ref line, out token, out tokenKind); if (tokenKind == Tokenizer.TokenKinds.Label_Or_Command && (2 <= token.Length && token.Length <= 32)) { interLine.Label = token; if (symb.ContainsSymbol(token)) { if (symb.GetSymbol(token).usage != Usage.ENTRY) { // error: cannot redefine symbol interLine.AddError(Errors.Category.Warning, 4); } } else { // the symbol is not defined, define it symb.AddSymbol(token, LC, Usage.LABEL); } } else { interLine.Label = "_ERROR"; interLine.AddError(Errors.Category.Serious, 2); } } else if (!char.IsWhiteSpace(line[0]) && line[0] != ':') { // invalid label start interLine.Label = "_ERROR"; interLine.AddError(Errors.Category.Serious, 2); } } // Get the next token, which will specify whether or not the line has a // directive or an instruction. Tokenizer.GetNextToken(ref line, out token, out tokenKind); if (tokenKind == Tokenizer.TokenKinds.Label_Or_Command) { // coerce into uppercase token = token.ToUpper(); // instruction if (instructionList.IsGroup(token)) { interLine.OpCategory = token; ParseInstruction(ref line, ref interLine, ref symb); interLine.ProgramCounter = LC; IncrementLocationCounter(); } // directive else if (directiveList.Contains(token)) { interLine.Directive = token; DirectiveParser.ParseDirective(ref line, ref interLine, ref symb); } else { // bad category, but don't NOP interLine.OpCategory = "_ERROR"; interLine.AddError(Errors.Category.Serious, 1); return interLine; } } else if (tokenKind == Tokenizer.TokenKinds.Comment) { interLine.Comment = token; return interLine; } else if (tokenKind != Tokenizer.TokenKinds.Empty) { // garbage data interLine.AddError(Errors.Category.Serious, 18); return interLine; } // If there's anything else, get it. If there's anything there, // it should be a comment. Tokenizer.GetNextToken(ref line, out token, out tokenKind); if (tokenKind == Tokenizer.TokenKinds.Comment) { interLine.Comment = token; } else if (tokenKind != Tokenizer.TokenKinds.Empty) { // error: invalid input after the operand Logger.Log("ERROR: EW.6 encountered", "Parser"); interLine.AddError(Errors.Category.Warning, 6); } // process this line if it's an instruction if (interLine.OpCategory != null) { interLine.ProcessLine(ref symb); } Logger.Log("Finished parsing line " + lineNum, "Parser"); return interLine; }
public void NonexistingSymbol() { var t = new SymbolTable(); try { t.GetSymbol("herp"); } catch (SymbolException) { return; } Assert.Fail(); }
/** * Process a line, generating partial bytecode and appropriate flags. * Errors may be set on lines (and NOP'd) as they occur. * * @param symb symbol table reference * * @refcode OP * @errtest * N/A * @errmsg * ES.3, ES.4, ES.9, ES.11, ES.12, ES.16, EW.3 * @author Jacob Peddicord * @creation April 10, 2011 * @modlog * - April 15, 2011 - Jacob - Converted to a property; begin generating full bytecode * - April 15, 2011 - Jacob - Changed to ProcessLine; we'll do more general things here * - April 16, 2011 - Jacob - Fix padding on generated instructions. * - April 17, 2011 - Jacob - Handle error conditions. * @codestandard Mark Mathis * @teststandard Andrew Buelow */ public void ProcessLine(ref SymbolTable symb) { Logger.Log("Processing line \"" + this.source + "\"", "IntermediateLine"); // get the first 5 bits StringBuilder code = new StringBuilder(); try { code.Append(Instructions.GetInstance().GetBytecodeString( this.category == null ? "" : this.category, this.function == null ? "" : this.function )); } catch (InstructionException) { this.AddError(Errors.Category.Serious, 3); this.NOPificate(); return; } // fetch equated symbols if (this.OpLitOperand == OperandParser.Literal.NONE && this.OpOperand != null && symb.ContainsSymbol(this.OpOperand) && symb.GetSymbol(this.OpOperand).usage == Usage.EQUATED) { Logger.Log("Evaluating equated symbol " + this.OpOperand, "IntermediateLine"); this.Equated = this.OpOperand; this.OpOperand = symb.GetSymbol(this.OpOperand).val; } // from here on, everything is instruction-dependent switch (this.category) { case "CNTL": { // unused bit code.Append("0"); // validation if (this.function == "HALT") { // we want a number if (this.OpLitOperand == OperandParser.Literal.NUMBER) { int val = BinaryHelper.HexToInt(this.OpOperand, 16); // out of bounds if (val < 0 || val > 1023) { this.AddError(Errors.Category.Serious, 12); this.NOPificate(); return; } } // wrong operand type else { this.AddError(Errors.Category.Serious, 12); this.NOPificate(); return; } } else if (this.function == "DUMP") { // not a 1, 2, or 3 if (this.OpOperand != "1" && this.OpOperand != "2" && this.OpOperand != "3") { this.AddError(Errors.Category.Serious, 11); this.NOPificate(); return; } } else if (this.function == "CLRD" || this.function == "CLRT") { // no operand for CLRD/CLRT if (this.OpOperand != "" && this.OpOperand != null) { this.AddError(Errors.Category.Warning, 3); this.NOPificate(); return; } } else if (this.function == "GOTO") { // make sure there's a label or expression if ((this.OpLitOperand != OperandParser.Literal.EXPRESSION && this.OpLitOperand != OperandParser.Literal.NONE) || this.OpOperand == "" || this.OpOperand == null) { this.AddError(Errors.Category.Serious, 9); this.NOPificate(); return; } } // actual processing! // numeric operand if (this.OpLitOperand == OperandParser.Literal.NUMBER) { code.Append(BinaryHelper.BinaryString(this.OpOperand).PadLeft(10, '0')); } // otherwise pad with zeros (labels & expressions in pass 2) else { code.Append("0000000000"); } } break; case "STACK": { // ensure there is an operand if (this.OpOperand.Length == 0) { this.AddError(Errors.Category.Serious, 16); this.NOPificate(); return; } // literal operand if (this.OpLitOperand != OperandParser.Literal.NONE && this.OpLitOperand != OperandParser.Literal.EXPRESSION) { // bounds-check int val = Convert.ToInt32(this.OpOperand, 16); if (val < 0 || val > 1023) // actually (val < -512 || val > 511) in 10 bits { this.AddError(Errors.Category.Serious, 4); this.NOPificate(); return; } // literal flag code.Append("1"); // and the value code.Append(BinaryHelper.BinaryString(this.OpOperand).PadLeft(10, '0')); } // expression else if (this.OpLitOperand == OperandParser.Literal.EXPRESSION) { // we'll have literal data once the expression is evaluated. code.Append("1"); code.Append("0000000000"); } // label else { // non-literal (reference) bit code.Append("0"); // and the reference itself, which will be filled in pass 2 code.Append("0000000000"); } } break; case "JUMP": { // ensure there is an operand if (this.OpOperand.Length == 0) { this.AddError(Errors.Category.Serious, 16); this.NOPificate(); return; } // unused bit code.Append("0"); // ensure that JUMP is taking a label if (this.OpLitOperand == OperandParser.Literal.NONE) { // reference label, filled in pass 2 code.Append("0000000000"); } // or a number else if (this.OpLitOperand == OperandParser.Literal.NUMBER) { int val = Convert.ToInt32(this.OpOperand, 16); if (val < 0 || val > 1023) { this.AddError(Errors.Category.Serious, 12); this.NOPificate(); return; } code.Append(BinaryHelper.BinaryString(this.OpOperand).PadLeft(10, '0')); } // or an expression (processed later) else if (this.OpLitOperand == OperandParser.Literal.EXPRESSION) { code.Append("0000000000"); } // otherwise, error else { this.AddError(Errors.Category.Serious, 9); this.NOPificate(); return; } } break; case "SOPER": { // ensure there is an operand of type Number if (this.OpLitOperand != OperandParser.Literal.NUMBER) { this.AddError(Errors.Category.Serious, 17); this.NOPificate(); return; } // bounds-check int val = Convert.ToInt32(this.OpOperand, 16); if (val < 0 || val > 255) // will catch 2's complement negatives as well { this.AddError(Errors.Category.Serious, 17); this.NOPificate(); return; } // the write flag is only set for character operations if (this.OpFunction == "READC" || this.OpFunction == "WRITEC") { code.Append("1"); } // for everything else, it's a zero else { code.Append("0"); } // unused 2 bits code.Append("00"); // operand (assumed literal) code.Append(BinaryHelper.BinaryString(this.OpOperand).PadLeft(8, '0')); } break; case "MOPER": { // ensure there is an operand if (this.OpOperand.Length == 0) { this.AddError(Errors.Category.Serious, 16); this.NOPificate(); return; } // the write flag is only set for character operations if (this.OpFunction == "READC" || this.OpFunction == "WRITEC") { code.Append("1"); } // for everything else, it's a zero else { code.Append("0"); } // ensure that MOPER is taking a label if (this.OpLitOperand == OperandParser.Literal.NONE) { // reference label, filled pass 2 code.Append("0000000000"); } // or a number else if (this.OpLitOperand == OperandParser.Literal.NUMBER) { int val = Convert.ToInt32(this.OpOperand, 16); if (val < 0 || val > 1023) { this.AddError(Errors.Category.Serious, 4); this.NOPificate(); return; } code.Append(BinaryHelper.BinaryString(this.OpOperand).PadLeft(10, '0')); } // or an expression (pass 2) else if (this.OpLitOperand == OperandParser.Literal.EXPRESSION) { code.Append("0000000000"); } // otherwise, it's invalid else { this.AddError(Errors.Category.Serious, 9); this.NOPificate(); return; } } break; } // set the bytecode this.bytecode = code.ToString(); }