示例#1
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);
        }
示例#2
0
文件: Compiler.cs 项目: gisikw/KOS
        /// <summary>
        /// Handles the short-circuit logic of boolean OR and boolean AND
        /// chains.  It is like VisitExpressionChain (see elsewhere) but
        /// in this case it has the special logic to short circuit and skip
        /// executing the righthand expression if it can.  (The generic VisitExpressionXhain
        /// always evaluates both the left and right sides of the operator first, then
        /// does the operation).
        /// </summary>
        /// <param name="node"></param>
        private void VisitShortCircuitBoolean(ParseNode node)
        {
            NodeStartHousekeeping(node);

            if (node.Nodes.Count > 1)
            {
                // it should always be odd, two arguments and one operator
                if ((node.Nodes.Count % 2) != 1) return;

                // Determine if this is a chain of ANDs or a chain or ORs.  The parser will
                // never mix ANDs and ORs into the same ParseNode level.  We are guaranteed
                // that all the operators in this chain match the first operator in the chain:
                // That guarantee is important.  Without it, we can't do short-circuiting like this
                // because you can't short-circuit a mix of AND and OR at the same precedence.
                TokenType operation = node.Nodes[1].Token.Type; // Guaranteed to be either TokenType.AND or TokenType.OR

                // For remembering the instruction pointers from which short-circuit branch jumps came:
                List<int> shortCircuitFromIndeces = new List<int>();

                int nodeIndex = 0;
                while (nodeIndex < node.Nodes.Count)
                {
                    if (nodeIndex > 0) // After each term, insert the branch test (which consumes the expr from the stack regardless of if it branches):
                    {
                       shortCircuitFromIndeces.Add(currentCodeSection.Count());
                       if (operation == TokenType.AND)
                           AddOpcode(new OpcodeBranchIfFalse());
                       else if (operation == TokenType.OR)
                           AddOpcode(new OpcodeBranchIfTrue());
                       else
                           throw new KOSException("Assertion check:  Broken kerboscript compiler (VisitShortCircuitBoolean).  See kOS devs");
                    }

                    VisitNode(node.Nodes[nodeIndex]); // pushes the next term onto the stack.
                    nodeIndex += 2; // Skip the operator, moving to the next term over.
                }
                // If it gets to the end of all that and it still hasn't aborted, then the whole expression's
                // Boolean value is just the value of its lastmost term, that's already gotten pushed atop the stack.
                // Leave the lastmost term there, and just skip ahead past the short-circuit landing target:
                OpcodeBranchJump skipShortCircuitTarget = new OpcodeBranchJump();
                skipShortCircuitTarget.Distance = 2; // Hardcoded +2 jump distance skips the upcoming OpcodePush and just lands on
                                                     // whatever comes next after this VisitNode.  Avoids using DestinationLabel
                                                     // for later relocation because it would be messy to reassign this label later
                                                     // in whatever VisitNode happens to come up next, when that could be anything.
                AddOpcode(skipShortCircuitTarget);

                // Build the instruction all the short circuit checks will jump to if aborting partway through.
                // (AND's abort when they're false.  OR's abort when they're true.)
                AddOpcode(operation == TokenType.AND ? new OpcodePush(false) : new OpcodePush(true));
                string shortCircuitTargetLabel = currentCodeSection[currentCodeSection.Count()-1].Label;

                // Retroactively re-assign the jump labels of all the short circuit branch operations:
                foreach (int index in shortCircuitFromIndeces)
                {
                    currentCodeSection[index].DestinationLabel = shortCircuitTargetLabel;
                }
            }
            else if (node.Nodes.Count == 1)
            {
                VisitNode(node.Nodes[0]); // This ParseNode isn't *realy* an expression of AND or OR operators, because
                                          // the regex chain of "zero or more" righthand terms.. had zero such terms.
                                          // So just delve in deeper to compile whatever part of speech it is further down.
            }
        }