public List <Opcode> BuildProgram() { var program = new List <Opcode>(); foreach (var objectFile in objectFiles.Values) { var linkedObject = new CodePart(); foreach (var part in objectFile.Parts) { AddInitializationCode(linkedObject, part); linkedObject.FunctionsCode.AddRange(part.FunctionsCode); linkedObject.MainCode.AddRange(part.MainCode); } // we assume that the first object is the main program and the rest are subprograms/libraries bool isMainProgram = (objectFile == objectFiles.Values.First()); // add a jump to the entry point so the execution skips the functions code if (isMainProgram) { AddJumpToEntryPoint(linkedObject); } // add an instruction to indicate the end of the program AddEndOfProgram(linkedObject, isMainProgram); // save the entry point of the object objectFile.EntryPointLabel = GetEntryPointLabel(linkedObject); // add the linked object to the final program program.AddRange(linkedObject.MergeSections()); } // replace all the labels references with the corresponding address ReplaceLabels(program); return(program); }
public List<Opcode> BuildProgram() { var program = new List<Opcode>(); foreach (var objectFile in objectFiles.Values) { var linkedObject = new CodePart(); foreach (var part in objectFile.Parts) { AddInitializationCode(linkedObject, part); linkedObject.FunctionsCode.AddRange(part.FunctionsCode); linkedObject.MainCode.AddRange(part.MainCode); } // we assume that the first object is the main program and the rest are subprograms/libraries bool isMainProgram = (objectFile == objectFiles.Values.First()); // add a jump to the entry point so the execution skips the functions code if (isMainProgram) AddJumpToEntryPoint(linkedObject); // add an instruction to indicate the end of the program AddEndOfProgram(linkedObject, isMainProgram); // save the entry point of the object objectFile.EntryPointLabel = GetEntryPointLabel(linkedObject); // add the linked object to the final program program.AddRange(linkedObject.MergeSections()); } // replace all the labels references with the corresponding address ReplaceLabels(program); return program; }
protected virtual void AddEndOfProgram(CodePart linkedObject, bool isMainProgram) { if (isMainProgram) { linkedObject.MainCode.Add(new OpcodeEOP()); } else { linkedObject.MainCode.Add(new OpcodeReturn()); } }
private void AddJumpToEntryPoint(CodePart linkedObject) { if (linkedObject.MainCode.Count <= 0) return; var jumpOpcode = new OpcodeBranchJump { DestinationLabel = GetEntryPointLabel(linkedObject) }; linkedObject.FunctionsCode.Insert(0, jumpOpcode); }
protected virtual void AddEndOfProgram(CodePart linkedObject, bool isMainProgram) { if (isMainProgram) { linkedObject.MainCode.Add(new OpcodeEOP()); } else { linkedObject.MainCode.Add(new OpcodePush(0)); // all Returns now need a dummy return value on them. linkedObject.MainCode.Add(new OpcodeReturn(0)); } }
private void AddJumpToEntryPoint(CodePart linkedObject) { if (linkedObject.MainCode.Count <= 0) { return; } var jumpOpcode = new OpcodeBranchJump(); jumpOpcode.DestinationLabel = GetEntryPointLabel(linkedObject); linkedObject.FunctionsCode.Insert(0, jumpOpcode); }
protected virtual void AddEndOfProgram(CodePart linkedObject, bool isMainProgram) { // possible refactor: this logic needs to be moved into the compiler // itself eventually, so that we can make an "exit" statement. As it stands, // the fact that the final exit code is only dealt with here outside the // compiler, and the fact that it changes depending on if it's called from // the interpreter or from another program (the interpreter doesn't expect an exit // code, and won't pop it, which is the reason for this if/else below), is // what makes that non-trivial. if (isMainProgram) { linkedObject.MainCode.Add(new OpcodePop()); // to consume the argbottom mark. linkedObject.MainCode.Add(new OpcodeEOP()); } else { linkedObject.MainCode.Add(new OpcodePush(0)); // all Returns now need a dummy return value on them. linkedObject.MainCode.Add(new OpcodeReturn(0)); } }
private static string previousLabel = "######"; // bogus value that is ensured to differ from any real value the first time through. /// <summary> /// Returns the compiled program's opcodes packed into a tight form, that is a direct /// streamed dump of the list of opcodes. /// </summary> /// <param name="program">The list of opcode codeparts for the compiled program.</param> /// <returns>The packed bytes that should be written to the binary file.</returns> public static byte[] Pack(List <CodePart> program) { packTempWriter = new BinaryWriter(new MemoryStream()); var allCodeBuff = new List <byte>(); var headBuff = new List <byte>(); argumentPack = new byte[8]; // this will grow bigger (be replaced by new arrays) as needed. argumentPackLogicalLength = 0; // nothing in the argumentPack yet. argumentPackFinder = new Dictionary <object, int>(); lineMap = new DebugLineMap(); previousLabel = "######"; // bogus value that is ensured to differ from any real value the first time through. for (int index = 0; index < program.Count; ++index) // --. This can be replaced with a { // |--- foreach. I do it this way so I CodePart codePart = program[index]; // --' can print the index in debugging. PackArgs(codePart.FunctionsCode); PackArgs(codePart.InitializationCode); PackArgs(codePart.MainCode); } // Now that we've seen every argument, we know how many bytes are needed // to store the argumentPack, and thus the largest possible index into it. // This will be how many bytes our indeces will be in this packed ML file. int numArgIndexBytes = FewestBytesToHold(argumentPackLogicalLength); headBuff.Add((byte)'%'); headBuff.Add((byte)'A'); headBuff.Add(((byte)numArgIndexBytes)); var truncatedArgumentPack = new byte[argumentPackLogicalLength]; Array.Copy(argumentPack, 0, truncatedArgumentPack, 0, argumentPackLogicalLength); headBuff.AddRange(truncatedArgumentPack); for (int index = 0; index < program.Count; ++index) // --. This can be replaced with a { // |--- foreach. I do it this way so I CodePart codePart = program[index]; // --' can print the index in debugging. var codeBuff = new List <byte>(); int indexSoFar = allCodeBuff.Count + codeBuff.Count; codeBuff.Add((byte)'%'); codeBuff.Add((byte)'F'); byte[] packedCode = PackCode(codePart.FunctionsCode, numArgIndexBytes, indexSoFar + 2); codeBuff.AddRange(packedCode); indexSoFar = allCodeBuff.Count + codeBuff.Count; codeBuff.Add((byte)'%'); codeBuff.Add((byte)'I'); packedCode = PackCode(codePart.InitializationCode, numArgIndexBytes, indexSoFar + 2); codeBuff.AddRange(packedCode); indexSoFar = allCodeBuff.Count + codeBuff.Count; codeBuff.Add((byte)'%'); codeBuff.Add((byte)'M'); packedCode = PackCode(codePart.MainCode, numArgIndexBytes, indexSoFar + 2); codeBuff.AddRange(packedCode); allCodeBuff.AddRange(codeBuff); } var everything = new List <byte>(); everything.AddRange(MagicId); everything.AddRange(headBuff); everything.AddRange(allCodeBuff); everything.AddRange(lineMap.Pack()); return(everything.ToArray()); }
private string GetEntryPointLabel(CodePart linkedObject) { List <Opcode> codeSection = linkedObject.InitializationCode.Count > 0 ? linkedObject.InitializationCode : linkedObject.MainCode; return(codeSection[0].Label); }
protected virtual void AddInitializationCode(CodePart linkedObject, CodePart part) { linkedObject.InitializationCode.AddRange(part.InitializationCode); }
private string GetEntryPointLabel(CodePart linkedObject) { List<Opcode> codeSection = linkedObject.InitializationCode.Count > 0 ? linkedObject.InitializationCode : linkedObject.MainCode; return codeSection[0].Label; }
private static string previousLabel = "######"; // bogus value that is ensured to differ from any real value the first time through. /// <summary> /// Returns the compiled program's opcodes packed into a tight form, that is a direct /// streamed dump of the list of opcodes. /// </summary> /// <param name="program">The list of opcode codeparts for the compiled program.</param> /// <returns>The packed bytes that should be written to the binary file.</returns> public static byte[] Pack(List <CodePart> program) { packTempWriter = new BinaryWriter(new MemoryStream()); var allCodeBuff = new List <byte>(); var headBuff = new List <byte>(); argumentPack = new byte[8]; // this will grow bigger (be replaced by new arrays) as needed. argumentPackLogicalLength = 0; // nothing in the argumentPack yet. argumentPackFinder = new Dictionary <object, int>(); lineMap = new DebugLineMap(); previousLabel = "######"; // bogus value that is ensured to differ from any real value the first time through. for (int index = 0; index < program.Count; ++index) // --. This can be replaced with a { // |--- foreach. I do it this way so I CodePart codePart = program[index]; // --' can print the index in debugging. PackArgs(codePart.FunctionsCode); PackArgs(codePart.InitializationCode); PackArgs(codePart.MainCode); } // Purpose of numArgIndexBytes calculated below: // The first thing in the argument pack section after the "%A" idicator // is a single byte that tells how big the addresses into the argment pack // are. The argument pack might address arguments using a single byte if // the argument pack is small enough that you don't need addresses bigger than // 255. If you need addresses bigger than 255, then it might take two bytes // to store addresses so it can cover values up to 65535, and so on. int argSectionHeaderBytes = 3; // Adjust this if you add or subtract headBuf.Add() lines below: int numArgIndexBytes = FewestBytesToHold(argumentPackLogicalLength + argSectionHeaderBytes); headBuff.Add((byte)'%'); headBuff.Add((byte)'A'); headBuff.Add(((byte)numArgIndexBytes)); // ^^^ IF YOU ADD OR REMOVE ANY headBuff.Add(...) LINES ABOVE YOU MUST ALSO CHANGE argSectionHeaderBytes. var truncatedArgumentPack = new byte[argumentPackLogicalLength]; Array.Copy(argumentPack, 0, truncatedArgumentPack, 0, argumentPackLogicalLength); headBuff.AddRange(truncatedArgumentPack); for (int index = 0; index < program.Count; ++index) // --. This can be replaced with a { // |--- foreach. I do it this way so I CodePart codePart = program[index]; // --' can print the index in debugging. var codeBuff = new List <byte>(); int indexSoFar = allCodeBuff.Count + codeBuff.Count; codeBuff.Add((byte)'%'); codeBuff.Add((byte)'F'); byte[] packedCode = PackCode(codePart.FunctionsCode, numArgIndexBytes, indexSoFar + 2); codeBuff.AddRange(packedCode); indexSoFar = allCodeBuff.Count + codeBuff.Count; codeBuff.Add((byte)'%'); codeBuff.Add((byte)'I'); packedCode = PackCode(codePart.InitializationCode, numArgIndexBytes, indexSoFar + 2); codeBuff.AddRange(packedCode); indexSoFar = allCodeBuff.Count + codeBuff.Count; codeBuff.Add((byte)'%'); codeBuff.Add((byte)'M'); packedCode = PackCode(codePart.MainCode, numArgIndexBytes, indexSoFar + 2); codeBuff.AddRange(packedCode); allCodeBuff.AddRange(codeBuff); } var everything = new List <byte>(); everything.AddRange(MagicId); everything.AddRange(headBuff); everything.AddRange(allCodeBuff); everything.AddRange(lineMap.Pack()); using (var compressedStream = new MemoryStream()) { using (var csStream = new GZipOutputStream(compressedStream)) { csStream.Write(everything.ToArray(), 0, everything.Count); csStream.Flush(); } return(compressedStream.ToArray()); } }