Beispiel #1
0
        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);
        }
Beispiel #2
0
        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;
        }
Beispiel #3
0
 protected virtual void AddEndOfProgram(CodePart linkedObject, bool isMainProgram)
 {
     if (isMainProgram)
     {
         linkedObject.MainCode.Add(new OpcodeEOP());
     }
     else
     {
         linkedObject.MainCode.Add(new OpcodeReturn());
     }
 }
Beispiel #4
0
        private void AddJumpToEntryPoint(CodePart linkedObject)
        {
            if (linkedObject.MainCode.Count <= 0) return;

            var jumpOpcode = new OpcodeBranchJump
            {
                DestinationLabel = GetEntryPointLabel(linkedObject)
            };

            linkedObject.FunctionsCode.Insert(0, jumpOpcode);
        }
Beispiel #5
0
 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));
     }
 }
Beispiel #6
0
 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));
     }
 }
Beispiel #7
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);
        }
Beispiel #8
0
 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));
     }
 }
Beispiel #9
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());
        }
Beispiel #10
0
        private string GetEntryPointLabel(CodePart linkedObject)
        {
            List <Opcode> codeSection = linkedObject.InitializationCode.Count > 0 ? linkedObject.InitializationCode : linkedObject.MainCode;

            return(codeSection[0].Label);
        }
Beispiel #11
0
 protected virtual void AddInitializationCode(CodePart linkedObject, CodePart part)
 {
     linkedObject.InitializationCode.AddRange(part.InitializationCode);
 }
Beispiel #12
0
 private string GetEntryPointLabel(CodePart linkedObject)
 {
     List<Opcode> codeSection = linkedObject.InitializationCode.Count > 0 ? linkedObject.InitializationCode : linkedObject.MainCode;
     return codeSection[0].Label;
 }
Beispiel #13
0
 protected virtual void AddInitializationCode(CodePart linkedObject, CodePart part)
 {
     linkedObject.InitializationCode.AddRange(part.InitializationCode);
 }
Beispiel #14
0
 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));
     }
 }
Beispiel #15
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);
            }

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