public static string GenerateListing(AssemblyOutput output) { // I know this can be optimized, I might optmize it eventually int maxLineNumber = output.Listing.Max(l => l.CodeType == CodeType.Directive ? 0 : l.LineNumber).ToString().Length; int maxFileLength = output.Listing.Max(l => l.FileName.Length); int maxBinaryLength = output.Listing.Max(l => { if (l.Output == null || l.Output.Length == 0) { return(0); } return(l.Output.Length * 3 - 1); }); int addressLength = output.InstructionSet.WordSize / 4 + 2; string formatString = "{0,-" + maxFileLength + "}:{1,-" + maxLineNumber + "} ({2}): {3,-" + maxBinaryLength + "} {4}" + Environment.NewLine; string errorFormatString = "{0,-" + maxFileLength + "}:{1,-" + maxLineNumber + "} {2}: {3}" + Environment.NewLine; string addressFormatString = "X" + addressLength; // Listing format looks something like this: // file.asm/1 (0x1234): DE AD BE EF ld a, 0xBEEF // file.asm/2 (0x1236): label: // file.asm/3 (0x1236): #directive var builder = new StringBuilder(); string file, address, binary, code; int line; foreach (var entry in output.Listing) { file = entry.FileName; line = entry.LineNumber; address = "0x" + entry.Address.ToString(addressFormatString); code = entry.Code; if (entry.Output != null && entry.Output.Length != 0 && entry.CodeType != CodeType.Directive) { binary = string.Empty; for (int i = 0; i < entry.Output.Length; i++) { binary += entry.Output[i].ToString("X2") + " "; } binary = binary.Remove(binary.Length - 1); code = " " + code; } else { binary = string.Empty; } if (entry.Error != AssemblyError.None) { builder.AppendFormat(errorFormatString, file, line, "Error", entry.Error); } if (entry.Warning != AssemblyWarning.None) { builder.AppendFormat(errorFormatString, file, line, "Warning", entry.Warning); } builder.AppendFormat(formatString, file, line, address, binary, code); } return(builder.ToString()); }
public static string GenerateListing(AssemblyOutput output) { // I know this can be optimized, I might optmize it eventually int maxLineNumber = output.Listing.Max(l => l.CodeType == CodeType.Directive ? 0 : l.LineNumber).ToString().Length; int maxFileLength = output.Listing.Max(l => l.FileName.Length); int maxBinaryLength = output.Listing.Max(l => { if (l.Output == null || l.Output.Length == 0) return 0; return l.Output.Length * 3 - 1; }); int addressLength = output.InstructionSet.WordSize / 4 + 2; string formatString = "{0,-" + maxFileLength + "}:{1,-" + maxLineNumber + "} ({2}): {3,-" + maxBinaryLength + "} {4}" + Environment.NewLine; string errorFormatString = "{0,-" + maxFileLength + "}:{1,-" + maxLineNumber + "} {2}: {3}" + Environment.NewLine; string addressFormatString = "X" + addressLength; // Listing format looks something like this: // file.asm/1 (0x1234): DE AD BE EF ld a, 0xBEEF // file.asm/2 (0x1236): label: // file.asm/3 (0x1236): #directive var builder = new StringBuilder(); string file, address, binary, code; int line; foreach (var entry in output.Listing) { file = entry.FileName; line = entry.LineNumber; address = "0x" + entry.Address.ToString(addressFormatString); code = entry.Code; if (entry.Output != null && entry.Output.Length != 0 && entry.CodeType != CodeType.Directive) { binary = string.Empty; for (int i = 0; i < entry.Output.Length; i++) binary += entry.Output[i].ToString("X2") + " "; binary = binary.Remove(binary.Length - 1); code = " " + code; } else binary = string.Empty; if (entry.Error != AssemblyError.None) builder.AppendFormat(errorFormatString, file, line, "Error", entry.Error); if (entry.Warning != AssemblyWarning.None) builder.AppendFormat(errorFormatString, file, line, "Warning", entry.Warning); builder.AppendFormat(formatString, file, line, address, binary, code); } return builder.ToString(); }
private AssemblyOutput Finish(AssemblyOutput output) { var finalBinary = new List<byte>(); ExpressionEngine.LastGlobalLabel = null; for (int i = 0; i < output.Listing.Count; i++) { var entry = output.Listing[i]; RootLineNumber = entry.RootLineNumber; PC = entry.Address; LineNumbers = new Stack<int>(new[] { entry.LineNumber }); if (entry.CodeType == CodeType.Directive) { if (entry.PostponeEvalulation) output.Listing[i] = HandleDirective(entry.Code, true); if (output.Listing[i].Output != null) finalBinary.AddRange(output.Listing[i].Output); continue; } if (entry.Error != AssemblyError.None) continue; if (entry.CodeType == CodeType.Label) { var name = entry.Code.Remove(entry.Code.IndexOf(':')).Trim(':').ToLower(); if (!name.StartsWith(".") && name != "_") ExpressionEngine.LastGlobalLabel = name; } else if (entry.CodeType == CodeType.Instruction) { // Assemble output string string instruction = entry.Instruction.Value.ToLower(); foreach (var operand in entry.Instruction.Operands) instruction = instruction.Replace("@" + operand.Key, operand.Value.Value); foreach (var value in entry.Instruction.ImmediateValues) { try { bool truncated; if (value.Value.RelativeToPC) { var exp = ExpressionEngine.Evaluate(value.Value.Value, entry.Address, entry.RootLineNumber); instruction = instruction.Replace("^" + value.Key, ConvertToBinary( (exp - entry.Instruction.Length) - entry.Address, value.Value.Bits, true, out truncated)); } else if (value.Value.RstOnly) { truncated = false; var rst = (byte)ExpressionEngine.Evaluate(value.Value.Value, entry.Address, entry.RootLineNumber); if ((rst & ~0x7) != rst || rst > 0x38) entry.Error = AssemblyError.InvalidExpression; else { instruction = instruction.Replace("&" + value.Key, ConvertToBinary((ulong)rst >> 3, 3, false, out truncated)); } } else instruction = instruction.Replace("%" + value.Key, ConvertToBinary( ExpressionEngine.Evaluate(value.Value.Value, entry.Address, entry.RootLineNumber), value.Value.Bits, false, out truncated)); if (truncated) entry.Error = AssemblyError.ValueTruncated; } catch (KeyNotFoundException) { entry.Error = AssemblyError.UnknownSymbol; } catch (InvalidOperationException) { entry.Error = AssemblyError.InvalidExpression; } } if (entry.Error == AssemblyError.None) { entry.Output = ExpressionEngine.ConvertFromBinary(instruction); finalBinary.AddRange(entry.Output); } else finalBinary.AddRange(new byte[entry.Instruction.Length]); } } output.Data = finalBinary.ToArray(); return output; }
public AssemblyOutput Assemble(string assembly, string fileName = null) { Output = new AssemblyOutput(); Output.InstructionSet = InstructionSet; assembly = assembly.Replace("\r", ""); PC = 0; Lines = assembly.Split('\n'); FileNames.Push(Path.GetFileName(fileName)); LineNumbers.Push(0); RootLineNumber = 0; IfStack.Push(true); for (CurrentIndex = 0; CurrentIndex < Lines.Length; CurrentIndex++) { CurrentLine = Lines[CurrentIndex].Trim().TrimComments(); if (SuspendedLines == 0) { LineNumbers.Push(LineNumbers.Pop() + 1); RootLineNumber++; } else SuspendedLines--; if (!IfStack.Peek()) { bool match = false; if (CurrentLine.StartsWith("#") || CurrentLine.StartsWith(".")) { var directive = CurrentLine.Substring(1); if (CurrentLine.Contains((' '))) directive = directive.Remove(CurrentLine.IndexOf((' '))).Trim(); if (ifDirectives.Contains(directive.ToLower())) match = true; } if (!match) continue; } if (CurrentLine.SafeContains(".equ") && !CurrentLine.StartsWith(".equ")) { var name = CurrentLine.Remove(CurrentLine.SafeIndexOf(".equ")); var definition = CurrentLine.Substring(CurrentLine.SafeIndexOf(".equ") + 4); CurrentLine = ".equ " + name.Trim() + " " + definition.Trim(); } // Check for macro if (!CurrentLine.StartsWith(".macro") && !CurrentLine.StartsWith("#macro") && !CurrentLine.StartsWith(".undefine") && !CurrentLine.StartsWith("#undefine")) { Macro macroMatch = null; string[] parameters = null; string parameterDefinition = null; foreach (var macro in Macros) { if (CurrentLine.ToLower().SafeContains(macro.Name)) { // Try to match int startIndex = CurrentLine.ToLower().SafeIndexOf(macro.Name); int endIndex = startIndex + macro.Name.Length - 1; if (macro.Parameters.Length != 0) { if (endIndex + 1 >= CurrentLine.Length) continue; if (CurrentLine.Length < endIndex + 1 || CurrentLine[endIndex + 1] != '(') continue; if (macroMatch != null && macro.Name.Length < macroMatch.Name.Length) continue; parameterDefinition = CurrentLine.Substring(endIndex + 2, CurrentLine.LastIndexOf(')') - (endIndex + 2)); parameters = parameterDefinition.SafeSplit(','); if (parameters.Length != macro.Parameters.Length) continue; // Matched macroMatch = macro; } else macroMatch = macro; } } if (macroMatch != null) { // Add an entry to the listing AddOutput(CodeType.Directive); var code = macroMatch.Code; int index = 0; foreach (var parameter in macroMatch.Parameters) code = code.Replace(parameter.Trim(), parameters[index++].Trim()); string newLine; if (parameterDefinition != null) newLine = CurrentLine.Replace(macroMatch.Name + "(" + parameterDefinition + ")", code, StringComparison.InvariantCultureIgnoreCase); else { if (CurrentLine.Substring(CurrentLine.ToLower().IndexOf(macroMatch.Name) + macroMatch.Name.Length).StartsWith("()")) newLine = CurrentLine.Replace(macroMatch.Name + "()", code, StringComparison.InvariantCultureIgnoreCase); else newLine = CurrentLine.Replace(macroMatch.Name, code, StringComparison.InvariantCultureIgnoreCase); } var newLines = newLine.Replace("\r\n", "\n").Split('\n'); SuspendedLines += newLines.Length; // Insert macro Lines = Lines.Take(CurrentIndex).Concat(newLines).Concat(Lines.Skip(CurrentIndex + 1)).ToArray(); CurrentIndex--; continue; } } // Find same-line labels if (CurrentLine.Contains(":")) { int length = 0; bool isLabel = true; for (int j = 0; j < CurrentLine.Length; j++) { if (char.IsLetterOrDigit(CurrentLine[j]) || CurrentLine[j] == '_') length++; else if (CurrentLine[j] == ':') break; else { isLabel = false; break; } } if (isLabel) { var label = CurrentLine.Remove(length).ToLower(); label = label.ToLower(); if (label == "_") { // Relative ExpressionEngine.RelativeLabels.Add(new RelativeLabel { Address = PC, RootLineNumber = RootLineNumber }); AddOutput(CodeType.Label); } else { bool local = label.StartsWith("."); if (local) label = label.Substring(1) + "@" + ExpressionEngine.LastGlobalLabel; bool valid = true; for (int k = 0; k < label.Length; k++) // Validate label { if (!char.IsLetterOrDigit(label[k]) && label[k] != '_') { if (local && label[k] == '@') continue; valid = false; break; } } if (!valid) AddError(CodeType.Label, AssemblyError.InvalidLabel); else if (ExpressionEngine.Symbols.ContainsKey(label.ToLower())) AddError(CodeType.Label, AssemblyError.DuplicateName); else { AddOutput(CodeType.Label); ExpressionEngine.Symbols.Add(label.ToLower(), new Symbol(PC, true)); if (!local) ExpressionEngine.LastGlobalLabel = label.ToLower(); } } CurrentLine = CurrentLine.Substring(length + 1).Trim(); } } if (CurrentLine.StartsWith(":") || CurrentLine.EndsWith(":")) // Label { string label; if (CurrentLine.StartsWith(":")) label = CurrentLine.Substring(1).Trim(); else label = CurrentLine.Remove(CurrentLine.Length - 1).Trim(); label = label.ToLower(); if (label == "_") { // Relative ExpressionEngine.RelativeLabels.Add(new RelativeLabel { Address = PC, RootLineNumber = RootLineNumber }); AddOutput(CodeType.Label); } else { bool local = label.StartsWith("."); if (local) label = label.Substring(1) + "@" + ExpressionEngine.LastGlobalLabel; bool valid = true; for (int k = 0; k < label.Length; k++) // Validate label { if (!char.IsLetterOrDigit(label[k]) && label[k] != '_') { if (local && label[k] == '@') continue; valid = false; break; } } if (!valid) AddError(CodeType.Label, AssemblyError.InvalidLabel); else if (ExpressionEngine.Symbols.ContainsKey(label.ToLower())) AddError(CodeType.Label, AssemblyError.DuplicateName); else { AddOutput(CodeType.Label); ExpressionEngine.Symbols.Add(label.ToLower(), new Symbol(PC, true)); if (!local) ExpressionEngine.LastGlobalLabel = label.ToLower(); } } continue; } if (CurrentLine.SafeContains('\\')) { // Split lines up var split = CurrentLine.SafeSplit('\\'); Lines = Lines.Take(CurrentIndex).Concat(split). Concat(Lines.Skip(CurrentIndex + 1)).ToArray(); SuspendedLines = split.Length; CurrentIndex--; continue; } if (CurrentLine.StartsWith(".") || CurrentLine.StartsWith("#")) // Directive { // Some directives need to be handled higher up var directive = CurrentLine.Substring(1).Trim(); string[] parameters = new string[0]; if (directive.SafeIndexOf(' ') != -1) parameters = directive.Substring(directive.SafeIndexOf(' ')).Trim().SafeSplit(' '); if (directive.ToLower().StartsWith("macro")) { var definitionLine = CurrentLine; // Used to update the listing later if (parameters.Length == 0) { AddError(CodeType.Directive, AssemblyError.InvalidDirective); continue; } string definition = directive.Substring(directive.SafeIndexOf(' ')).Trim(); var macro = new Macro(); if (definition.Contains("(")) { var parameterDefinition = definition.Substring(definition.SafeIndexOf('(') + 1); parameterDefinition = parameterDefinition.Remove(parameterDefinition.SafeIndexOf(')')); // NOTE: This probably introduces the ability to use ".macro foo(bar)this_doesnt_cause_errors" if (string.IsNullOrEmpty(parameterDefinition)) macro.Parameters = new string[0]; else macro.Parameters = parameterDefinition.SafeSplit(','); macro.Name = definition.Remove(definition.SafeIndexOf('(')).ToLower(); } else macro.Name = definition.ToLower(); // TODO: Consider enforcing character usage restrictions for (CurrentIndex++; CurrentIndex < Lines.Length; CurrentIndex++) { CurrentLine = Lines[CurrentIndex].Trim().TrimComments(); LineNumbers.Push(LineNumbers.Pop() + 1); RootLineNumber++; if (CurrentLine == ".endmacro" || CurrentLine == "#endmacro") break; macro.Code += CurrentLine + Environment.NewLine; } macro.Code = macro.Code.Remove(macro.Code.Length - Environment.NewLine.Length); macro.Name = macro.Name.ToLower(); if (Macros.Any(m => m.Name == macro.Name && m.Parameters.Length == macro.Parameters.Length)) { AddError(CodeType.Label, AssemblyError.DuplicateName); continue; } Macros.Add(macro); // Add an entry to the listing Output.Listing.Add(new Listing { Code = definitionLine, CodeType = CodeType.Directive, Error = AssemblyError.None, Warning = AssemblyWarning.None, Address = PC, FileName = FileNames.Peek(), LineNumber = LineNumbers.Peek(), RootLineNumber = RootLineNumber }); } else { var result = HandleDirective(CurrentLine); if (result != null) Output.Listing.Add(result); } continue; } else { if (string.IsNullOrEmpty(CurrentLine) || !Listing) continue; // Check instructions var match = InstructionSet.Match(CurrentLine); if (match == null) AddError(CodeType.Instruction, AssemblyError.InvalidInstruction); // Unknown instruction else { // Instruction to be fully assembled in the next pass Output.Listing.Add(new Listing { Code = CurrentLine, CodeType = CodeType.Instruction, Error = AssemblyError.None, Warning = AssemblyWarning.None, Instruction = match, Address = PC, FileName = FileNames.Peek(), LineNumber = LineNumbers.Peek(), RootLineNumber = RootLineNumber }); PC += match.Length; } } } return Finish(Output); }
private AssemblyOutput Finish(AssemblyOutput output) { List<byte> finalBinary = new List<byte>(); for (int i = 0; i < output.Listing.Count; i++) { var entry = output.Listing[i]; RootLineNumber = entry.RootLineNumber; PC = entry.Address; LineNumbers = new Stack<int>(new[] { entry.LineNumber }); if (entry.CodeType == CodeType.Directive) { if (entry.PostponeEvalulation) output.Listing[i] = HandleDirective(entry.Code, true); if (output.Listing[i].Output != null) finalBinary.AddRange(output.Listing[i].Output); continue; } if (entry.Error != AssemblyError.None) continue; if (entry.CodeType == CodeType.Instruction) { // Assemble output string string instruction = entry.Instruction.Value.ToLower(); foreach (var operand in entry.Instruction.Operands) instruction = instruction.Replace("@" + operand.Key, operand.Value.Value); foreach (var value in entry.Instruction.ImmediateValues) { // TODO: Truncation warning if (value.Value.RelativeToPC) instruction = instruction.Replace("^" + value.Key, ConvertToBinary( entry.Address - (ExpressionEngine.Evaluate(value.Value.Value, entry.Address) + entry.Instruction.Length), value.Value.Bits)); else instruction = instruction.Replace("%" + value.Key, ConvertToBinary( ExpressionEngine.Evaluate(value.Value.Value, entry.Address), value.Value.Bits)); } entry.Output = ExpressionEngine.ConvertFromBinary(instruction); finalBinary.AddRange(entry.Output); } } output.Data = finalBinary.ToArray(); return output; }
public AssemblyOutput Assemble(string assembly, string fileName = null) { var output = new AssemblyOutput(); assembly = assembly.Replace("\r", ""); PC = 0; Lines = assembly.Split('\n'); FileNames.Push(fileName); LineNumbers.Push(0); RootLineNumber = 0; for (CurrentIndex = 0; CurrentIndex < Lines.Length; CurrentIndex++) { string line = Lines[CurrentIndex].Trim().TrimComments().ToLower(); if (SuspendedLines == 0) { LineNumbers.Push(LineNumbers.Pop() + 1); RootLineNumber++; } else SuspendedLines--; if (line.SafeContains('\\')) { // Split lines up var split = line.SafeSplit('\\'); Lines = Lines.Take(CurrentIndex).Concat(split). Concat(Lines.Skip(CurrentIndex + 1)).ToArray(); SuspendedLines = split.Length; CurrentIndex--; continue; } if (line.SafeContains(".equ") && !line.StartsWith(".equ")) { var name = line.Remove(line.SafeIndexOf(".equ")); var definition = line.Substring(line.SafeIndexOf(".equ") + 4); line = ".equ " + name.Trim() + ", " + definition.Trim(); } if (line.StartsWith(".") || line.StartsWith("#")) // Directive { // Some directives need to be handled higher up var directive = line.Substring(1).Trim().ToLower(); string[] parameters = new string[0]; if (directive.SafeIndexOf(' ') != -1) parameters = directive.Substring(directive.SafeIndexOf(' ')).Split(','); if (directive.StartsWith("macro")) { var definitionLine = line; // Used to update the listing later if (parameters.Length == 0) { output.Listing.Add(new Listing { Code = line, CodeType = CodeType.Directive, Error = AssemblyError.InvalidDirective, Warning = AssemblyWarning.None, Address = PC, FileName = FileNames.Peek(), LineNumber = LineNumbers.Peek(), RootLineNumber = RootLineNumber }); continue; } string definition = directive.Substring(directive.SafeIndexOf(' ')).Trim(); var macro = new Macro(); if (definition.Contains("(")) { var parameterDefinition = definition.Substring(definition.SafeIndexOf('(') + 1); parameterDefinition = parameterDefinition.Remove(parameterDefinition.SafeIndexOf(')')); // NOTE: This probably introduces the ability to use ".macro foo(bar)this_doesnt_cause_errors" macro.Parameters = parameterDefinition.SafeSplit(','); macro.Name = definition.Remove(definition.SafeIndexOf('(')); } else macro.Name = definition; // TODO: Consider enforcing character usage restrictions for (CurrentIndex++; CurrentIndex < Lines.Length; CurrentIndex++) { line = Lines[CurrentIndex].Trim().TrimComments(); LineNumbers.Push(LineNumbers.Pop() + 1); RootLineNumber++; if (line == ".endmacro" || line == "#endmacro") break; macro.Code += line + Environment.NewLine; } macro.Code = macro.Code.Remove(macro.Code.Length - Environment.NewLine.Length); macro.Name = macro.Name.ToLower(); if (Macros.Any(m => m.Name == macro.Name)) { output.Listing.Add(new Listing { Code = line, CodeType = CodeType.Directive, Error = AssemblyError.DuplicateName, Warning = AssemblyWarning.None, Address = PC, FileName = FileNames.Peek(), LineNumber = LineNumbers.Peek(), RootLineNumber = RootLineNumber }); continue; } Macros.Add(macro); // Add an entry to the listing output.Listing.Add(new Listing { Code = definitionLine, CodeType = CodeType.Directive, Error = AssemblyError.None, Warning = AssemblyWarning.None, Address = PC, FileName = FileNames.Peek(), LineNumber = LineNumbers.Peek(), RootLineNumber = RootLineNumber }); } else if (directive.StartsWith("include")) { } else { var result = HandleDirective(line); if (result != null) output.Listing.Add(result); } continue; } else if (line.StartsWith(":") || line.EndsWith(":")) // Label { string label; if (line.StartsWith(":")) label = line.Substring(1).Trim(); else label = line.Remove(line.Length - 1).Trim(); label = label.ToLower(); bool valid = true; for (int k = 0; k < label.Length; k++) // Validate label { if (!char.IsLetterOrDigit(label[k]) && k != '_') { valid = false; break; } } if (!valid) { output.Listing.Add(new Listing { Code = line, CodeType = CodeType.Label, Error = AssemblyError.InvalidLabel, Warning = AssemblyWarning.None, Address = PC, FileName = FileNames.Peek(), LineNumber = LineNumbers.Peek(), RootLineNumber = RootLineNumber }); } output.Listing.Add(new Listing { Code = line, CodeType = CodeType.Label, Error = AssemblyError.None, Warning = AssemblyWarning.None, Address = PC, FileName = FileNames.Peek(), LineNumber = LineNumbers.Peek(), RootLineNumber = RootLineNumber }); ExpressionEngine.Equates.Add(label, PC); } else { // Check for macro Macro macroMatch = null; string[] parameters = null; string parameterDefinition = null; foreach (var macro in Macros) { if (line.SafeContains(macro.Name)) { // Try to match int startIndex = line.SafeIndexOf(macro.Name); int endIndex = startIndex + macro.Name.Length - 1; if (macro.Parameters.Length != 0) { if (line[endIndex + 1] != '(') continue; parameterDefinition = line.Substring(endIndex + 2, line.SafeIndexOf(')') - (endIndex + 2)); parameters = parameterDefinition.SafeSplit(','); if (parameters.Length != macro.Parameters.Length) continue; // Matched macroMatch = macro; break; } } } if (macroMatch != null) { // Add an entry to the listing output.Listing.Add(new Listing { Code = line, CodeType = CodeType.Directive, Error = AssemblyError.None, Warning = AssemblyWarning.None, Address = PC, FileName = FileNames.Peek(), LineNumber = LineNumbers.Peek(), RootLineNumber = RootLineNumber }); var code = macroMatch.Code; int index = 0; foreach (var parameter in macroMatch.Parameters) code = code.Replace(parameter, parameters[index++]); string newLine; if (parameterDefinition != null) newLine = line.Replace(macroMatch.Name + "(" + parameterDefinition + ")", code); else newLine = line.Replace(macroMatch.Name, code); var newLines = newLine.Replace("\r\n", "\n").Split('\n'); SuspendedLines += newLines.Length; // Insert macro Lines = Lines.Take(CurrentIndex).Concat(newLines).Concat(Lines.Skip(CurrentIndex + 1)).ToArray(); CurrentIndex--; continue; } if (string.IsNullOrEmpty(line)) continue; // Check instructions var match = InstructionSet.Match(line); if (match == null) { // Unknown instruction output.Listing.Add(new Listing { Code = line, CodeType = CodeType.Instruction, Error = AssemblyError.InvalidInstruction, Warning = AssemblyWarning.None, Instruction = match, Address = PC, FileName = FileNames.Peek(), LineNumber = LineNumbers.Peek(), RootLineNumber = RootLineNumber }); } else { // Instruction to be fully assembled in the next pass output.Listing.Add(new Listing { Code = line, CodeType = CodeType.Instruction, Error = AssemblyError.None, Warning = AssemblyWarning.None, Instruction = match, Address = PC, FileName = FileNames.Peek(), LineNumber = LineNumbers.Peek(), RootLineNumber = RootLineNumber }); PC += match.Length; } } } return Finish(output); }