Beispiel #1
0
        private void ReplaceLabels(List <Opcode> program)
        {
            var labels = new Dictionary <string, int>();

            // get the index of every label
            for (int index = 0; index < program.Count; index++)
            {
                if (program[index].Label != string.Empty)
                {
                    labels.Add(program[index].Label, index);
                }
            }

            // replace destination labels with the corresponding index
            for (int index = 0; index < program.Count; index++)
            {
                Opcode opcode = program[index];
                if (string.IsNullOrEmpty(opcode.DestinationLabel))
                {
                    continue;
                }

                int destinationIndex = labels[opcode.DestinationLabel];
                if (opcode is BranchOpcode)
                {
                    ((BranchOpcode)opcode).Distance = destinationIndex - index;
                }
                else if (opcode is OpcodePushRelocateLater)
                {
                    // Replace the OpcodePushRelocateLater with the proper OpcodePush:
                    Opcode newOp;
                    if (opcode is OpcodePushDelegateRelocateLater)
                    {
                        newOp = new OpcodePushDelegate(destinationIndex, ((OpcodePushDelegateRelocateLater)opcode).WithClosure);
                    }
                    else
                    {
                        newOp = new OpcodePush(destinationIndex);
                    }
                    newOp.SourceName   = opcode.SourceName;
                    newOp.SourceLine   = opcode.SourceLine;
                    newOp.SourceColumn = opcode.SourceColumn;
                    newOp.Label        = opcode.Label;
                    program[index]     = newOp;
                }
                else if (opcode is OpcodeCall)
                {
                    ((OpcodeCall)opcode).Destination = destinationIndex;
                }
            }

            // complete the entry point address of all the objects
            foreach (var objectFile in objectFiles.Values)
            {
                if (objectFile.EntryPointLabel != string.Empty)
                {
                    objectFile.EntryPointAddress = labels[objectFile.EntryPointLabel];
                }
            }
        }
Beispiel #2
0
        private void ReplaceLabels(List <Opcode> program)
        {
            var labels = new Dictionary <string, int>();

            // get the index of every label
            for (int index = 0; index < program.Count; index++)
            {
                if (program[index].Label != string.Empty)
                {
                    if (labels.ContainsKey(program[index].Label))
                    {
                        if (program[index].Label.EndsWith("-default"))
                        {
                            continue;
                        }
                        // This is one of those "should never happen" errors that if it happens
                        // it means kOS devs screwed up - so dump the partially relabeled program
                        // to the log just to help in diagnosing the bug report that may happen:
                        //
                        Utilities.SafeHouse.Logger.LogError("=====Relabeled Program so far is: =========");
                        Utilities.SafeHouse.Logger.LogError(Utilities.Debug.GetCodeFragment(program));

                        throw new Exceptions.KOSCompileException(LineCol.Unknown(), string.Format(
                                                                     "ProgramBuilder.ReplaceLabels: Cannot add label {0}, label already exists.  Opcode: {1}", program[index].Label, program[index].ToString()));
                    }
                    labels.Add(program[index].Label, index);
                }
            }

            // replace destination labels with the corresponding index
            for (int index = 0; index < program.Count; index++)
            {
                Opcode opcode = program[index];
                if (string.IsNullOrEmpty(opcode.DestinationLabel))
                {
                    continue;
                }

                if (!labels.ContainsKey(opcode.DestinationLabel))
                {
                    Utilities.SafeHouse.Logger.LogError("=====Relabeled Program so far is: =========");
                    Utilities.SafeHouse.Logger.LogError(Utilities.Debug.GetCodeFragment(program));

                    throw new Exceptions.KOSCompileException(LineCol.Unknown(), string.Format(
                                                                 "ProgramBuilder.ReplaceLabels: Cannot find label {0}.  Opcode: {1}", opcode.DestinationLabel, opcode.ToString()));
                }
                int destinationIndex = labels[opcode.DestinationLabel];
                if (opcode is BranchOpcode)
                {
                    ((BranchOpcode)opcode).Distance = destinationIndex - index;
                }
                else if (opcode is OpcodePushRelocateLater)
                {
                    // Replace the OpcodePushRelocateLater with the proper OpcodePush:
                    Opcode newOp;
                    if (opcode is OpcodePushDelegateRelocateLater)
                    {
                        newOp = new OpcodePushDelegate(destinationIndex, ((OpcodePushDelegateRelocateLater)opcode).WithClosure);
                    }
                    else
                    {
                        newOp = new OpcodePush(destinationIndex);
                    }
                    newOp.SourcePath   = opcode.SourcePath;
                    newOp.SourceLine   = opcode.SourceLine;
                    newOp.SourceColumn = opcode.SourceColumn;
                    newOp.Label        = opcode.Label;
                    program[index]     = newOp;
                }
                else if (opcode is OpcodeCall)
                {
                    ((OpcodeCall)opcode).Destination = destinationIndex;
                }
            }

            // complete the entry point address of all the objects
            foreach (var objectFile in objectFiles.Values)
            {
                if (objectFile.EntryPointLabel != string.Empty)
                {
                    objectFile.EntryPointAddress = labels[objectFile.EntryPointLabel];
                }
            }
        }
        protected IEnumerable <Opcode> BuildBoilerplateLoader()
        {
            List <Opcode> boilerplate = new List <Opcode>();

            InternalPath path = new BuiltInPath();

            // First label of the load/runner will be called "@LR00", which is important because that's
            // what we hardcode all the compiler-built VisitRunStatement's to call out to:
            labelCounter = 0;
            labelFormat  = "@LR{0:D2}";
            boilerplate.Add(new OpcodePushScope(-999, 0)
            {
                Label = nextLabel, SourcePath = path
            });

            // High level kerboscript function calls flip the argument orders for us, but
            // low level kRISC does not so the parameters have to be read in stack order:

            // store parameter 2 in a local name:
            boilerplate.Add(new OpcodePush("$runonce")
            {
                Label = nextLabel, SourcePath = path
            });
            boilerplate.Add(new OpcodeSwap()
            {
                Label = nextLabel, SourcePath = path
            });
            boilerplate.Add(new OpcodeStoreLocal()
            {
                Label = nextLabel, SourcePath = path
            });

            // store parameter 1 in a local name:
            boilerplate.Add(new OpcodePush("$filename")
            {
                Label = nextLabel, SourcePath = path
            });
            boilerplate.Add(new OpcodeSwap()
            {
                Label = nextLabel, SourcePath = path
            });
            boilerplate.Add(new OpcodeStoreLocal()
            {
                Label = nextLabel, SourcePath = path
            });

            // Unconditionally call load() no matter what.  load() will abort and return
            // early if the program was already compiled, and tell us that on the stack:
            boilerplate.Add(new OpcodePush(new kOS.Safe.Execution.KOSArgMarkerType())
            {
                Label = nextLabel, SourcePath = path
            });
            boilerplate.Add(new OpcodePush("$filename")
            {
                Label = nextLabel, SourcePath = path
            });
            boilerplate.Add(new OpcodeEval()
            {
                Label = nextLabel, SourcePath = path
            });
            boilerplate.Add(new OpcodePush(true)
            {
                Label = nextLabel, SourcePath = path
            });                                                                           // the flag that tells load() to abort early if it's already loaded:
            boilerplate.Add(new OpcodePush(null)
            {
                Label = nextLabel, SourcePath = path
            });
            boilerplate.Add(new OpcodeCall("load()")
            {
                Label = nextLabel, SourcePath = path
            });

            // Stack now has the 2 return values of load():
            //    Topmost value is a boolean flag for whether or not the program was already loaded.
            //    Second-from-top value is the entry point into the program.

            // If load() didn't claim the program was already loaded, or if we aren't operating
            // in "once" mode, then jump to the part where we call the loaded program, else
            // fall through to a dummy do-nothing return for the "run once, but it already ran" case:
            Opcode branchFromOne = new OpcodeBranchIfFalse()
            {
                Label = nextLabel, SourcePath = path
            };

            boilerplate.Add(branchFromOne);
            boilerplate.Add(new OpcodePush("$runonce")
            {
                Label = nextLabel, SourcePath = path
            });
            Opcode branchFromTwo = new OpcodeBranchIfFalse()
            {
                Label = nextLabel, SourcePath = path
            };

            boilerplate.Add(branchFromTwo);
            boilerplate.Add(new OpcodePop()
            {
                Label = nextLabel, SourcePath = path
            });                                                                      // onsume the entry point that load() returned. We won't be calling it.
            boilerplate.Add(new OpcodePush(0)
            {
                Label = nextLabel, SourcePath = path
            });                                                                          // ---+-- The dummy do-nothing return.
            boilerplate.Add(new OpcodeReturn(1)
            {
                Label = nextLabel, SourcePath = path
            });                                                                          // ---'

            // Actually call the Program from its entry Point, which is now the thing left on top
            // of the stack from the second return value of load():
            Opcode branchTo = new OpcodePush("$entrypoint")
            {
                Label = nextLabel, SourcePath = path
            };

            boilerplate.Add(branchTo);
            boilerplate.Add(new OpcodeSwap()
            {
                Label = nextLabel, SourcePath = path
            });
            boilerplate.Add(new OpcodeStoreLocal()
            {
                Label = nextLabel, SourcePath = path
            });
            boilerplate.Add(new OpcodeCall("$entrypoint")
            {
                Label = nextLabel, SourcePath = path
            });

            boilerplate.Add(new OpcodePop()
            {
                Label = nextLabel, SourcePath = path
            });
            boilerplate.Add(new OpcodePush(0)
            {
                Label = nextLabel, SourcePath = path
            });
            boilerplate.Add(new OpcodeReturn(1)
            {
                Label = nextLabel, SourcePath = path
            });

            branchFromOne.DestinationLabel = branchTo.Label;
            branchFromTwo.DestinationLabel = branchTo.Label;

            return(boilerplate);
        }