private byte[] GetInstructionBytes(IList<AssemblerMessage> messages, IDictionary<string, byte> labels, ParsedInstruction parsedInstruction) { if (parsedInstruction.OpCodeInfo.InstructionSize > 1) { var generator = parsedInstruction.OpCodeInfo.InstructionGenerator; if (generator == null) throw new Exception("The generator was null!!!!"); var context = new FinalAssembleContext(labels, messages, parsedInstruction); var argumentBytes = generator.GenerateInstruction(context); if (argumentBytes == null) return null; if (argumentBytes.Length != parsedInstruction.OpCodeInfo.InstructionSize - 1) { messages.Add(new AssemblerMessage(ErrorLevel.Error, string.Format("The number of bytes produced does not match the instruction size."))); return null; } return new byte[] { parsedInstruction.OpCodeInfo.OpCode }.Concat(argumentBytes).ToArray(); } else { return new byte[] {parsedInstruction.OpCodeInfo.OpCode}; } }
public Pass1Result(IDictionary<string, byte> labels, ParsedInstruction[] parsedInstructions) { if (labels == null) throw new ArgumentNullException("labels"); if (parsedInstructions == null) throw new ArgumentNullException("parsedInstructions"); this.Labels = labels; this.ParsedInstructions = parsedInstructions; }
public FinalAssembleContext(IDictionary<string, byte> labels, IList<AssemblerMessage> messages, ParsedInstruction parsedInstruction) { if (labels == null) throw new ArgumentNullException("labels"); if (messages == null) throw new ArgumentNullException("messages"); if (parsedInstruction == null) throw new ArgumentNullException("parsedInstruction"); _labels = labels; _messages = messages; _parsedInstruction = parsedInstruction; }
private Pass1Result Pass1(IList<AssemblerMessage> messages, SourceLine[] sourceLines) { if (messages == null) throw new NullReferenceException("messages"); if (sourceLines == null) throw new NullReferenceException("sourceLines"); byte currentLocation = 0; var parsedInstructions = new List<ParsedInstruction>(sourceLines.Length); Dictionary<string, byte> labels = new Dictionary<string, byte>(); foreach (var sourceLine in sourceLines) { //Ditch the whitespace var cleanedLine = sourceLine.Line.RemoveWhitespace(); if (cleanedLine.StartsWith(":")) { //This is a label string labelName = LabelNameGetter.GetLabelName(cleanedLine); if (string.IsNullOrWhiteSpace(labelName)) { messages.Add(new AssemblerMessage(ErrorLevel.Error, string.Format("Invalid label on line {0}", sourceLine.LineNumber), sourceLine.LineNumber)); } else { labels.Add(labelName, currentLocation); } } else { //This out to be a bloody instruction var parts = cleanedLine.Split(','); //This is the number of arguments specified var numberOfArgumentsSpecified = parts.Length - 1; //Get the instruction name string instructionName = parts[0]; //Attempt to get the op code info var opCodeInfo = OpCodeFactory.GetOpCodeInfo(parts[0]); //Check to see if (opCodeInfo == null) { messages.Add(new AssemblerMessage(ErrorLevel.Error, string.Format("Invalid instruction '{0}' on line {1}", instructionName, sourceLine.LineNumber), sourceLine.LineNumber)); } else { if (numberOfArgumentsSpecified != opCodeInfo.NumberOfArguments) { messages.Add(new AssemblerMessage(ErrorLevel.Error, string.Format("The instruction '{0}' takes {1} parameters but {2} were specified.", opCodeInfo.AssemblerKeyword, opCodeInfo.NumberOfArguments, numberOfArgumentsSpecified))); } else { //Get the arguments var arguments = parts.Skip(1).ToArray(); //Create the parsed instruction var parsedInstruction = new ParsedInstruction(sourceLine, arguments, opCodeInfo); parsedInstructions.Add(parsedInstruction); //Move the current location so that labels can be correctly set. currentLocation += opCodeInfo.InstructionSize; } } } } return new Pass1Result(labels, parsedInstructions.ToArray()); }