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 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()); } }