public static InstructionInstanceBase Assemble(string instructionLine, int locationCounter, out ParsedSourceLine parsedLine, SymbolCollection symbols, out AssemblyFindingCollection findings) { var status = new ParsingStatus(symbols) { LocationCounter = locationCounter, LineNumber = 0 }; parsedLine = Parser.ParseInstructionLine(instructionLine, status); findings = status.Findings; // if errors were found while parsing, abort assembly if (status.Findings.ContainsErrors) { return(null); } if (!parsedLine.IsDefined) { status.Findings.Add(new AssemblyError(0, LineSection.EntireLine, 0, 0, new ValidationError("line is not an instruction"))); return(null); } status.LocationCounter = locationCounter; status.LineNumber = 0; var instructionInstance = parsedLine.CreateInstance(status); // if errors were found while assembling, don't return the instruction instance: it would be useless anyway if (status.Findings.ContainsErrors) { return(null); } return(instructionInstance); }
static SymbolBase ParseLocField(string locField, ParsingStatus status) { if (locField == "") { return(null); } status.LineSection = LineSection.LocationField; var symbol = ValueSymbol.ParseDefinition(locField, 0, status); if (symbol == null) { status.ReportParsingError(0, locField.Length, "invalid symbol name"); return(null); } if (status.Symbols.Contains(symbol)) { symbol = status.Symbols[symbol.Name]; if (symbol.IsSymbolDefined && !symbol.IsMultiValuedSymbol) { status.ReportParsingError(0, locField.Length, "symbol already defined"); return(null); } return(symbol); } status.Symbols.Add(symbol); return(symbol); }
public static PreInstruction[] ParseSource(string[] sourceLines, ParsingStatus status) { status.LocationCounter = 0; int endLineNumber = -1; var preInstructions = new List <PreInstruction>(); for (int lineNumber = 0; lineNumber < sourceLines.Length; lineNumber++) { status.LineNumber = lineNumber; if (endLineNumber != -1 && !IsCommentLine(sourceLines[lineNumber])) { status.ReportParsingWarning(LineSection.CommentField, 0, sourceLines[lineNumber].Length, "END has been parsed; line will be treated as comment"); preInstructions.Add(new ParsedSourceLine(lineNumber, sourceLines[lineNumber])); } else { var parsedLine = ParseLine(sourceLines[lineNumber], status); preInstructions.Add(parsedLine); if (parsedLine.OpField == "END") { endLineNumber = preInstructions.Count - 1; } } } if (endLineNumber == -1) { status.Findings.Add(new AssemblyError(int.MinValue, LineSection.CommentField, 0, 0, new ParsingError("END operation is mandatory but not included"))); } else { // all symbols that are not yet defined at the end of the parsing process are treated as if "<symbolname> CON *" instructions were included just before the END instruction foreach (SymbolBase symbol in status.Symbols) { if (!symbol.IsSymbolDefined) { symbol.SetValue(status.LocationCounter); var parameters = new LoaderInstructionParameters(new NumberValue(symbol.MemoryWordSign, symbol.MemoryWordMagnitude), 0); var instruction = new PreInstruction(mLoaderInstructions["CON"], parameters); preInstructions.Insert(endLineNumber, instruction); status.LocationCounter++; endLineNumber++; } } } return(preInstructions.ToArray()); }
static ParsedSourceLine ParseLine(string sourceLine, ParsingStatus status) { if (IsCommentLine(sourceLine)) { return(new ParsedSourceLine(status.LineNumber, sourceLine)); } var lineFields = SplitLine(sourceLine); lineFields[locFieldIndex] = lineFields[locFieldIndex].ToUpper(); lineFields[opFieldIndex] = lineFields[opFieldIndex].ToUpper(); lineFields[addressFieldIndex] = lineFields[addressFieldIndex].ToUpper(); if (lineFields[opFieldIndex] == "") { status.ReportParsingError(LineSection.LocationField, 0, sourceLine.Length, "op and address fields are missing"); return(new ParsedSourceLine(status.LineNumber, lineFields[0], "", "", "", null, null)); } var symbol = ParseLocField(lineFields[locFieldIndex], status); // if the location field contains a symbol name, set its value to the location counter symbol?.SetValue(status.LocationCounter); GetMixOrLoaderInstructionAndParameters(lineFields[opFieldIndex], lineFields[addressFieldIndex], status, out InstructionBase instruction, out IInstructionParameters instructionParameters); // the following call must be made even if a MIX or loader instruction was found, as some loader instructions require the assembler to act, as well var assemblyInstructionHandled = HandleAssemblyInstruction(lineFields[opFieldIndex], lineFields[addressFieldIndex], symbol, status); // if the line isn't a comment or a MIX or loader instruction, it must be an assembler instruction. If not, we don't know the mnemonic if (instruction == null && !assemblyInstructionHandled) { status.ReportParsingError(LineSection.OpField, 0, lineFields[opFieldIndex].Length, "operation mnemonic unknown"); } return(new ParsedSourceLine(status.LineNumber, lineFields[locFieldIndex], lineFields[opFieldIndex], lineFields[addressFieldIndex], lineFields[commentFieldIndex], instruction, instructionParameters)); }
public static InstructionInstanceBase[] Assemble(string[] sourceLines, out PreInstruction[] preInstructions, out SymbolCollection symbols, out AssemblyFindingCollection findings) { var list = new List <InstructionInstanceBase>(); var status = new ParsingStatus(); preInstructions = Parser.ParseSource(sourceLines, status); findings = status.Findings; symbols = null; // if errors were found during parsing, abort assembly if (status.Findings.ContainsErrors) { return(null); } status.LocationCounter = 0; status.LineNumber = 0; // compose the instruction instances based on the preinstructions returned by the parser foreach (PreInstruction instruction in preInstructions) { if (instruction.IsDefined) { var parsedSourceLine = instruction as ParsedSourceLine; status.LineNumber = parsedSourceLine != null ? parsedSourceLine.LineNumber : sourceLines.Length; var instructionInstance = instruction.CreateInstance(status); if (parsedSourceLine != null && instructionInstance != null) { string sourceLineText = parsedSourceLine.LocationField + new string(' ', Math.Max(Parser.MinLocLength - parsedSourceLine.LocationField.Length, 0) + Parser.FieldSpacing); sourceLineText += parsedSourceLine.OpField + new string(' ', Math.Max(Parser.MinOpLength - parsedSourceLine.OpField.Length, 0) + Parser.FieldSpacing); sourceLineText += parsedSourceLine.AddressField + new string(' ', Math.Max(Parser.MinAddressLength - parsedSourceLine.AddressField.Length, 0) + Parser.FieldSpacing); sourceLineText += parsedSourceLine.Comment; instructionInstance.SourceLine = sourceLineText; } list.Add(instructionInstance); if (instructionInstance != null && instructionInstance.Instruction is LoaderInstruction) { var loaderInstruction = (LoaderInstruction)instructionInstance.Instruction; if (loaderInstruction.Operation == LoaderInstruction.Operations.SetLocationCounter) { status.LocationCounter = (int)((LoaderInstruction.Instance)instructionInstance).Value.LongValue; continue; } // in case the PC is set by this instruction instance, prevent the location counter from being increased if (loaderInstruction.Operation == LoaderInstruction.Operations.SetProgramCounter) { continue; } } status.LocationCounter++; } } // if errors were found during assembly, don't return the instruction instances: they would be useless anyway if (status.Findings.ContainsErrors) { return(null); } symbols = new SymbolCollection(); foreach (SymbolBase symbol in status.Symbols) { if (symbol is ValueSymbol) { symbols.Add(symbol); } } status.Findings.Add(new AssemblyInfo("assembly completed successfully", int.MinValue, LineSection.EntireLine, 0, 0)); return(list.ToArray()); }
/// <summary> /// This method is used to handle instructions targeted at the assembler itself. /// </summary> static bool HandleAssemblyInstruction(string opField, string addressField, SymbolBase symbol, ParsingStatus status) { IValue expression; status.LineSection = LineSection.AddressField; switch (opField) { case "EQU": // set value of the instruction symbol (first field) to the value of the expression that is in the address field if (symbol != null) { expression = WValue.ParseValue(addressField, 0, status); if (!expression.IsValueDefined(status.LocationCounter)) { status.ReportParsingError(0, addressField.Length, "expression value is undefined"); return(true); } symbol.SetValue(expression.GetSign(status.LocationCounter), expression.GetMagnitude(status.LocationCounter)); } return(true); case "ORIG": // set the location counter to the value of the expression that is in the address field expression = WValue.ParseValue(addressField, 0, status); if (!expression.IsValueDefined(status.LocationCounter)) { status.ReportParsingError(0, addressField.Length, "expression value is undefined"); return(true); } status.LocationCounter = (int)expression.GetValue(status.LocationCounter); return(true); case "CON": case "ALF": // these instructions set the value of the memory word at the location counter, which is actually a loader instruction. // However, during assembly these memory words must be skipped, which is why we increase the location counter. status.LocationCounter++; return(true); } return(false); }
/// <summary> /// This method parses an "in-memory" instruction. That is: an instruction without a location field. /// </summary> public static ParsedSourceLine ParseInstructionLine(string instructionLine, ParsingStatus status) => // add an empty location field, then parse as usual. ParseLine(" " + instructionLine, status);
static void GetMixOrLoaderInstructionAndParameters(string opField, string addressField, ParsingStatus status, out InstructionBase instruction, out IInstructionParameters instructionParameters) { status.LineSection = LineSection.AddressField; instructionParameters = null; instruction = mLoaderInstructions[opField]; if (instruction != null) { instructionParameters = LoaderInstructionParameters.ParseAddressField(instruction, addressField, status); } else { instruction = mInstructionSet[opField]; if (instruction != null) { instructionParameters = MixInstructionParameters.ParseAddressField(instruction, addressField, status); status.LocationCounter++; } } }