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")); }
public void NonexistingSymbol() { var t = new SymbolTable(); try { t.GetSymbol("herp"); } catch (SymbolException) { return; } Assert.Fail(); }
public void DuplicateSymbol() { var t = new SymbolTable(); try { t.AddSymbol("one", "0", Usage.ENTRY, ""); t.AddSymbol("one", "0", Usage.ENTRY, ""); } catch (SymbolException) { return; } Assert.Fail(); }
/** * 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"); }
/// <summary> /// Initializes a new instance of the <see cref="Assembler"/> class. /// </summary> /// <param name="input">The input.</param> public Assembler(string input) { this.InputFilePath = input; this.SymbolTable = new SymbolTable(); }
/** * Parse an operand and fill the intermediate line with found data. * * @param line the line (string) to parse * @param interLine the intermediate line object to fill * @param symb symbol table reference * @param bits number of bits to pad to, if applicable * @refcode S2.4 * @errtest * @errmsg ES.15 * @author Mark Mathis * @creation April 10, 2011 * @modlog * - April 18, 2011 - Jacob - Catch exceptions on parsing issues. * @teststandard Andrew Buelow * @codestandard Mark Mathis */ public static void ParseOperand(ref string line, ref IntermediateLine interLine, ref SymbolTable symb, int bits) { // get the next token string token; Tokenizer.TokenKinds tokenKind; Tokenizer.GetNextToken(ref line, out token, out tokenKind); Logger.Log("Parsing operand " + token + " of kind " + tokenKind.ToString(), "OperandParser"); string operand = null; Literal litOperand = Literal.NONE; try { // if it's a label, then just set the token directly if (tokenKind == Tokenizer.TokenKinds.Label_Or_Command) { litOperand = Literal.NONE; operand = token; } // if it's a number, convert to hex and store else if (tokenKind == Tokenizer.TokenKinds.Number) { litOperand = Literal.NUMBER; int op = Convert.ToInt32(token); op = BinaryHelper.ConvertNumber(op, bits); operand = Convert.ToString(op, 16).ToUpper(); } // do further processing for literals else if (tokenKind == Tokenizer.TokenKinds.Literal) { ParseLiteralOperand(token, out operand, out litOperand, bits); } // the operand is an expression else if (tokenKind == Tokenizer.TokenKinds.Expression) { // check that it's valid operand = token; litOperand = Literal.EXPRESSION; } // anything else is invalid else { litOperand = Literal.NONE; operand = "_ERROR"; interLine.AddError(Errors.Category.Serious, 15); } } catch (Exception) { litOperand = Literal.NONE; operand = "_ERROR"; interLine.AddError(Errors.Category.Serious, 15); } // assign the directive fields if it's a directive if (interLine.Directive != null) { interLine.DirectiveOperand = operand; interLine.DirectiveLitOperand = litOperand; } // otherwise fill the default operands else { interLine.OpOperand = operand; interLine.OpLitOperand = litOperand; } }
/** * Drives the Assembler. * * @param args program runtime arguments * * @refcode N/A * @errtest * Differing program arguments. * @errmsg * - Incorrect number of arguments. * - Usage information * @author Mark * @creation April 5, 2011 * @modlog * - April 6, 2011 - Mark - Initializes Logger. * - April 8, 2011 - Mark - Reads files in from the command line. * - April 8, 2011 - Mark - Initializes and uses a Parser object. * - April 8, 2011 - Mark - Outputs results to screen. * - April 9, 2011 - Mark - Uses an IntermediateFile object. * - April 9, 2011 - Mark - Catches problem with improper number of arguments. * - April 10, 2011 - Mark - Uses a SymbolTable object. * - May 8, 2011 - Jacob - Only process one file. * @teststandard Andrew Buelow * @codestandard Mark Mathis */ public static void Main(string[] args) { string infile = null; string outfile = null; // single arg given, output to stdout if (args.Length == 1) { infile = args[0]; outfile = System.IO.Path.GetFileNameWithoutExtension(args[0]) + ".obj"; } // two args given, read in the first and output to the second else if (args.Length == 2) { infile = args[0]; outfile = args[1]; } // invalid; print usage else { Usage(); System.Environment.Exit(1); } Errors.SetResource(Properties.Resources.errors); // pass 1 Logger.Log("Starting up", "Main"); SymbolTable symb = new SymbolTable(); Parser pars = new Parser(); IntermediateFile interSource; pars.ParseSource(infile, out interSource, out symb); bool fatalerr = false; AssemblyReport report = new AssemblyReport(); // Checking for fatal errors and creating an Assembly Report to display if a fatal error is found. foreach (IntermediateLine line in interSource) { if (line.Fatal) { fatalerr = true; } report.Add(line.ProgramCounter, "0000", ' ', line.SourceLineNumber, line.SourceLine, line.GetThreeErrors()); } if (fatalerr) { // Output the report Console.WriteLine(report); // and symbol table Console.WriteLine(symb); // Stop the assembler System.Environment.Exit(10); } #if DEBUG Console.WriteLine(interSource); #endif // pass 2 Logger.Log("Starting pass 2", "Main"); interSource.CalculateModuleLength(); report = new AssemblyReport(); ObjectFile obj = new ObjectFile(ref interSource, ref symb, ref report); obj.Render(outfile); // print out assembly report Console.WriteLine(report); // and symbol table Console.WriteLine(symb); }
/** * 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 eque 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 D4 * @errtest * N/A * @errmsg * N/A * @author Mark Mathis * @creation April 17, 2011 * @modlog * @teststandard Andrew Buelow * @codestandard Mark Mathis */ private static void ParseEque(ref IntermediateLine interLine, ref SymbolTable symb) { // The expressions will be exactly the same for EQUe as // it will for EQU, EQUe can just have longer expressions ParseEqu(ref interLine, ref symb, 3); }
/** * Parses an entire source code file. * * @param path the path of the source file to parse. * @param interSource resultant intermediate file from this source * @param symb resultant symbol table from this source * * @refcode N/A * @errtest * N/A * @errmsg * N/A * @author Mark Mathis * @creation April 8, 2011 * @modlog * - April 9, 2011 - Mark - Parses entire source code file from a string. * - April 9, 2011 - Mark - Reads source file in from a file. * - April 9, 2011 - Mark - Catches exceptions possibly raised by reading the file. * - April 9, 2011 - Jacob - Adds symbols to the symbol table. Changed the parameters to * pass in an IntermediateFile and SymbolTable with an expected out value. Return type * is now void. * @teststandard Andrew Buelow * @codestandard Mark Mathis */ public void ParseSource(string path, out IntermediateFile interSource, out SymbolTable symb) { string[] sourceCode = new string[1]; try { Logger.Log("Opening file: " + path, "Parser"); sourceCode = File.ReadAllLines(path); } catch (FileNotFoundException ex) { Logger.Log("Failed to open file. Error: " + ex.Message, "Parser"); Console.WriteLine("{0}\n{1}", ex.Message, "Exiting program"); System.Environment.Exit(1); } interSource = new IntermediateFile(); symb = new SymbolTable(); // first line is expected to hold the start directive IntermediateLine line = ParseLine(sourceCode[0], 1, ref symb); interSource.AddLine(line); if (line.Directive != null) { if (line.Directive.ToUpper() != "START") { // file must start with a valid start directive line.AddError(Errors.Category.Fatal, 2); return; } else if (HasFatalError(line)) { return; } } else { line.AddError(Errors.Category.Fatal, 2); return; } bool reachedEnd = false; // iterate the lines of the file for (short i = 2; i <= sourceCode.Length; i++) { // parse a line and create an intermediate version line = ParseLine(sourceCode[i - 1].TrimEnd(), i, ref symb); // if we're at the end and processing another line if (reachedEnd) { if (line.SourceLine.Length > 0) line.AddError(Errors.Category.Fatal, 7); } // check the LC. at this point, the line will have incremented // already, so check if it's 1024 instead of 1023. if (Convert.ToInt32(Parser.LC, 16) > 1024) { line.AddError(Errors.Category.Fatal, 3); } // add to source if (!reachedEnd || line.SourceLine.Length > 0) interSource.AddLine(line); // did we find le end? if (line.Directive == "END") { reachedEnd = true; } // check for fatal errors if (HasFatalError(line)) { break; } } }
public void Sorting() { var t = new SymbolTable(); t.AddSymbol("apple", "5", Usage.EQUATED, "derp"); t.AddSymbol("pear", "20", Usage.ENTRY, ""); t.AddSymbol("orange", "42", Usage.ENTRY, ""); var l = t.SortedSymbols(); Assert.AreEqual(l[0], "apple"); Assert.AreEqual(l[1], "orange"); Assert.AreEqual(l[2], "pear"); }
public void EmptyTable() { var t = new SymbolTable(); Assert.AreEqual(0, t.SortedSymbols().Count); }
/** * 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(); }
/** * 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 operation section of the line if it has an instruction. * * @param line current line to parse. * @param interLine the line as a single line in the intermediate file. * @param symb symbol table reference * * @refcode N/A * @errtest * N/A * @errmsg * N/A * @author Mark Mathis * @creation April 9, 2011 * @modlog * - April 9, 2011 - Mark - ParseInstruction properly parses instructions. * - April 9, 2011 - Mark - Uses new ParseLiteralOperand format. * - April 9, 2011 - Mark - Changed to use ValidOperandField. * - April 10, 2011 - Mark - Handles CLRD and CLRT. * - April 12, 2011 - Jacob - Factor out operand parsing. * @teststandard Andrew Buelow * @codestandard Mark Mathis */ private void ParseInstruction(ref string line, ref IntermediateLine interLine, ref SymbolTable symb) { Logger.Log("Parsing instruction on line " + interLine.SourceLineNumber, "Parser"); string token = ""; Tokenizer.TokenKinds tokenKind = Tokenizer.TokenKinds.Empty; // checks for valid operands in all functions besides CLRD and CLRT if (OperandParser.ValidOperandField(line)) { // get what should be the function name Tokenizer.GetNextToken(ref line, out token, out tokenKind); if (instructionList.IsInstruction(interLine.OpCategory, token)) { interLine.OpFunction = token; } else { interLine.OpFunction = "_ERROR"; } // get what should be the function operand OperandParser.ParseOperand(ref line, ref interLine, ref symb, 10); } else if (interLine.OpCategory.ToUpper() == "CNTL") { // token should be either CLRD or CLRT Tokenizer.GetNextToken(ref line, out token, out tokenKind); if (token.ToUpper() != "CLRD" && token.ToUpper() != "CLRT") { interLine.OpOperand = "_ERROR"; } interLine.OpFunction = token; } else { interLine.OpFunction = "_ERROR"; interLine.OpOperand = "_ERROR"; } Logger.Log("Finished parsing instruction on line " + interLine.SourceLineNumber, "Parser"); }
/** * Parses the operation section of the line if it has a Directive. * * @param line current line to parse * @param interLine the line as a single line in the intermediate file * @param symb symbol table reference * @refcode DS2 * @errtest * N/A * @errmsg * N/A * @author Mark Mathis * @creation April 9, 2011 * @modlog * - April 9, 2011 - Mark - ParseDirective properly parses directives. * - April 9, 2011 - Mark - Uses new ParseLiteralOperand format. * - April 12, 2011 - Jacob - Factor out operand parsing. * - April 14, 2011 - Mark - Moved into DirectiveParser class. * - April 15, 2011 - Mark - Factored out all parsing into separate methods. * @teststandard Andrew Buelow * @codestandard Mark Mathis */ public static void ParseDirective(ref string line, ref IntermediateLine interLine, ref SymbolTable symb) { Logger.Log("Parsing directive on line " + interLine.SourceLineNumber, "DirectiveParser"); if (interLine.Directive.ToUpper() != "NOP") OperandParser.ParseOperand(ref line, ref interLine, ref symb, 16); // This will decide which directive is in this line and how it should // be handled by the parser. string currentDirective = interLine.Directive.ToUpper(); switch (currentDirective) { case "START": { ParseStart(ref interLine, ref symb); } break; case "RESET": { ParseReset(ref interLine, ref symb); } break; case "EQU": { ParseEqu(ref interLine, ref symb); } break; case "EQUE": { ParseEque(ref interLine, ref symb); } break; case "ENTRY": { ParseEntry(ref interLine, ref symb); } break; case "EXTRN": { ParseExtrn(ref interLine, ref symb); } break; case "END": { ParseEnd(ref interLine, ref symb); } break; case "DAT": { ParseDat(ref interLine, ref symb); } break; case "ADC": { ParseAdc(ref interLine, ref symb); } break; case "ADCE": { ParseAdce(ref interLine, ref symb); } break; case "NOP": { interLine.NOPificate(); interLine.ProgramCounter = Parser.LC; Parser.IncrementLocationCounter(); } break; default: { } break; } Logger.Log("Finished parsing directive on line " + interLine.SourceLineNumber, "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; }
/** * Parses the extrn directive, ensuring that operand is correct. * * @param interLine the intermediate line to process * @param symb symbol table reference * * @refcode D6 * @errtest * N/A * @errmsg ES.13, EW.05 * @author Mark Mathis * @creation April 17, 2011 * @modlog * @teststandard Andrew Buelow * @codestandard Mark Mathis */ private static void ParseExtrn(ref IntermediateLine interLine, ref SymbolTable symb) { Logger.Log("Parsing EXTRN directive", "DirectiveParser"); //check for label if (interLine.Label != null) { // extrn doesn't expect a label Logger.Log("ERROR: EW.05 encountered", "DirectiveParser"); interLine.AddError(Errors.Category.Warning, 5); } if (!symb.ContainsSymbol(interLine.DirectiveOperand)) { symb.AddSymbol(interLine.DirectiveOperand, null, Usage.EXTERNAL); } else { // cannot used variables defined in this program Logger.Log("ERROR: ES.13 encountered", "DirectiveParser"); interLine.AddError(Errors.Category.Serious, 13); } Logger.Log("Finished parsing EXTRN directive", "DirectiveParser"); }
/** * Parses the adc directive, ensuring that the operand has proper * syntax and type. * * @param interLine the intermediate line to process * @param symb symbol table reference * * @refcode D8 * @errtest * N/A * @errmsg * N/A * @author Mark Mathis * @creation April 18, 2011 * @modlog * @teststandard Andrew Buelow * @codestandard Mark Mathis */ private static void ParseAdc(ref IntermediateLine interLine, ref SymbolTable symb) { interLine.ProgramCounter = Parser.LC; Parser.IncrementLocationCounter(); }
/** * Parses the start directive, properly assigning the operand of start as the * starting location counter. * * @param interLine the intermediate line to process * @param symb symbol table reference * * @refcode D1 * @errtest * N/A * @errmsg EF.06 * @author Mark Mathis * @creation April 9, 2011 * @modlog * - April 9, 2011 - Mark - Parses the START directive, correctly setting the LC. * - April 14, 2011 - Mark - Moved into DirectiveParser class. * - April 17, 2011 - Mark - Catches errors in the start directive. * - April 19, 2011 - Mark - Reports errors. * @teststandard Andrew Buelow * @codestandard Mark Mathis */ private static void ParseStart(ref IntermediateLine interLine, ref SymbolTable symb) { Logger.Log("Parsing START directive", "DirectiveParser"); // this should only happen if the directive is found on the first line if (interLine.SourceLineNumber == 1) { // expecting operand to be the value of the location counter // check to see if operand is valid start value int startLC; if (interLine.DirectiveLitOperand == OperandParser.Literal.NUMBER) { string startOper = BinaryHelper.HexToInt(interLine.DirectiveOperand, 32).ToString(); if (int.TryParse(startOper, out startLC)) { if (0 <= startLC && startLC <= 1023) { Parser.LC = interLine.DirectiveOperand; } } else { /* * The operand could not be parsed as a number. * This is here as well as below just in case the * Tokenizer has a hiccough and says that something * that is not a number is a number. */ Logger.Log("ERROR: EF.06 encountered", "DirectiveParser"); interLine.AddError(Errors.Category.Fatal, 6); return; } // update the symbol in the symbol table Symbol start = symb.RemoveSymbol(interLine.Label); start.usage = Usage.PRGMNAME; start.lc = null; symb.AddSymbol(start); } else { // the operand could not be parsed as a number Logger.Log("ERROR: EF.06 encountered", "DirectiveParser"); interLine.AddError(Errors.Category.Fatal, 6); return; } } else { // not the first line of the source code. symb.RemoveSymbol(interLine.Label); Logger.Log("ERROR: ES.35 encountered", "DirectiveParser"); interLine.AddError(Errors.Category.Serious, 35); return; } Logger.Log("Finished parsing START directive", "DirectiveParser"); }
/** * Parses the adce directive, ensuring that the operand has proper * syntax and type. * * @param interLine the intermediate line to process * @param symb symbol table reference * * @refcode D9 * @errtest * N/A * @errmsg * N/A * @author Mark Mathis * @creation April 18, 2011 * @modlog * @teststandard Andrew Buelow * @codestandard Mark Mathis */ private static void ParseAdce(ref IntermediateLine interLine, ref SymbolTable symb) { ParseAdc(ref interLine, ref symb); }
/** * 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 dat directive, ensuring that the operand has proper syntax * and is correctly assigned to the current word of memory. * * @param interLine the intermediate line to process * @param symb symbol table reference * * @refcode D8 * @errtest * N/A * @errmsg ES.14 * @author Mark Mathis * @creation April 18, 2011 * @modlog * - April 19, 2011 - Jacob - Fixed padding on values. * - April 24, 2011 - Mark - Commented out the part that put the value of the dat * into the symbol table until that can be made clearer * by Al. * @teststandard Andrew Buelow * @codestandard Mark Mathis */ private static void ParseDat(ref IntermediateLine interLine, ref SymbolTable symb) { Logger.Log("Parsing DAT directive", "DirectiveParser"); if (interLine.DirectiveLitOperand != OperandParser.Literal.NONE && interLine.DirectiveLitOperand != OperandParser.Literal.EXPRESSION && interLine.DirectiveLitOperand != OperandParser.Literal.NUMBER && interLine.DirectiveLitOperand != OperandParser.Literal.UNKNOWN) { if (interLine.Label != null) { if (!symb.ContainsSymbol(interLine.Label)) { symb.AddSymbol(interLine.Label, Parser.LC, Usage.LABEL); //,interLine.DirectiveOperand); } else { Symbol datSym = symb.RemoveSymbol(interLine.Label); datSym.lc = Parser.LC; //datSym.val = interLine.DirectiveOperand; symb.AddSymbol(datSym); } } string val = Convert.ToString(Convert.ToInt32(interLine.DirectiveOperand, 16), 2); // assumed to be in correct representation; always pad to the left interLine.Bytecode = val.PadLeft(16, '0'); } else if (interLine.DirectiveLitOperand == OperandParser.Literal.UNKNOWN) { // error: literal operand in improper format interLine.AddError(Errors.Category.Serious, 37); } else { // error: invalid operand type Logger.Log("ERROR: ES.14 encountered", "DirectiveParser"); interLine.AddError(Errors.Category.Serious, 14); interLine.NOPificate(); } // this should need to happen no matter what interLine.ProgramCounter = Parser.LC; Parser.IncrementLocationCounter(); Logger.Log("Finished parsing DAT directive", "DirectiveParser"); }
/** * Create an object file using the given inputs. * * @param input Input source from pass 1 * @param symb The symbol table * @param report an assembly report to be generated * @refcode OB * @errtest * N/A * @errmsg * N/A * @author Jacob Peddicord * @creation May 10, 2011 * @modlog * @teststandard Andrew Buelow * @codestandard Mark Mathis */ public ObjectFile(ref IntermediateFile input, ref SymbolTable symb, ref AssemblyReport report) { this.input = input; this.symb = symb; this.report = report; }
static void Main() { string title = "Pong"; //Name of source file string title2 = "pong"; //Name for file path string outfile = "/Applications/nand2tetris/projects/06/" + title2 + "/" + title + ".hack"; bool hasMoreCommands = true; string type; int nextMem = 16; int counter = 0; Parser p1 = new Parser("/Applications/nand2tetris/projects/06/" + title2 + "/" + title + ".asm"); SymbolTable st = new SymbolTable(); while (hasMoreCommands == true) //First { p1.advance(); type = p1.commandType(); if (type == "L_COMMAND") { st.addEntry(p1.symbol(), counter); } else { counter += 1; hasMoreCommands = p1.hasMoreCommands(); } } hasMoreCommands = true; Parser p = new Parser("/Applications/nand2tetris/projects/06/" + title2 + "/" + title + ".asm"); Code c = new Code(); while (hasMoreCommands == true) //Second { p.advance(); type = p.commandType(); if (type == "A_COMMAND") { string varOrNum = p.symbol(); char von = varOrNum[0]; if (char.IsDigit(von) == true) { int prexxx = Convert.ToInt32(p.symbol()); string xxx = Convert.ToString(prexxx, 2).PadLeft(16, '0'); using (StreamWriter sw = new StreamWriter(outfile, true)) { sw.WriteLine(xxx); } } else //if(char.IsDigit(von)==false), which means xxx is variable. { bool cont = st.contains(varOrNum); if (cont == false) { st.addEntry(varOrNum, nextMem); string xxx = Convert.ToString(nextMem, 2).PadLeft(16, '0'); using (StreamWriter sw = new StreamWriter(outfile, true)) { sw.WriteLine(xxx); } nextMem += 1; } else { string xxx = Convert.ToString(st.getAddress(varOrNum), 2).PadLeft(16, '0'); using (StreamWriter sw = new StreamWriter(outfile, true)) { sw.WriteLine(xxx); } } } } else if (type == "C_COMMAND") { string destmne = p.dest(); string dest = c.dest(destmne); string compmne = p.comp(); string comp = c.comp(compmne); string jumpmne = p.jump(); string jump = c.jump(jumpmne); string c_command = "111" + comp + dest + jump; using (StreamWriter sw = new StreamWriter(outfile, true)) { sw.WriteLine(c_command); } } else //if (type=="L_COMMAND") { } hasMoreCommands = p.hasMoreCommands(); } }