PopFrame() public method

Resets stack pointer to point at base of old frame.
public PopFrame ( int framePointer ) : void
framePointer int Base of the frame we're popping off
return void
示例#1
0
        private const byte NoRegister      = 0xff;            // Target register meaning not to write to register

        // So here's append([], X, X). :
        //    MatchLiteral([], 0)
        //    MatchVarFirst(1)               % This is actually a no-op
        //    MatchVar(1, 2)
        //    Return
        //
        // And here's append([H|T], X, [H|T1]) :- append(T, X, T1).
        //    MatchStructure(dot, 2, L1, 0)
        //    MatchVarFirst(0>0>3)      % H is at 3
        //    MatchVarFirst(0>1>4)      % T is at 4
        // L1 MatchVarFirst(1)               % Actually a no-op
        //    MatchStructure(dot, 2, L2, 2)
        //    MatchVar(3, 2>0)
        //    MatchVarFirst(5, 2>1)        % T1 is at 5
        // L2 Call(6, Fail, Succeed, append/3, register(4), register(2), register(5))
        #endregion

        #region Interpreter
        internal IEnumerable <CutState> StackCall(PrologContext context)
        {
            int traceMark = context.MarkTrail();
            // On entry, the stack pointer points at the base of our arguments.
            int    framePointer        = context.MakeFrame(frameSize);
            ushort pc                  = 0;
            ushort writeModeEndAddress = 0; // We're in write mode if pc < writeModeEndAddress.
// ReSharper disable TooWideLocalVariableScope
            // Resharper is confused - can't move this inside the while loop, or its lifetime changes.
            ushort endOfBuilds;         // PC of last call instruction whose arguments have been built.

// ReSharper restore TooWideLocalVariableScope

            while (true)
            {
                switch ((Opcode)code[pc++])
                {
                    #region Head opcodes
                case Opcode.MatchLiteral:
                {
                    object literal = GetLiteral(ref pc);
                    if (pc < writeModeEndAddress)
                    {
                        // Write mode
                        SetOperand(context, framePointer, ref pc, literal);
                    }
                    else
                    {
                        // Read mode
                        if (!Term.Unify(DecodeOperand(context, framePointer, ref pc), literal, context))
                        {
                            goto fail;
                        }
                    }
                }
                break;

                case Opcode.MatchVarFirst:
                {
                    if (pc < writeModeEndAddress)
                    {
                        // Write mode
                        Symbol name     = GetSymbol(ref pc);
                        int    register = code[pc++];
                        var    l        = new LogicVariable(name);
                        SetOperand(context, framePointer, ref pc, l);
                        if (register != NoRegister)
                        {
                            context.SetStack(framePointer, register, l);
                        }
                    }
                    else
                    {
                        pc += 2;         // Skip over variable name.
                        int register = code[pc++];
                        // Read mode
                        object operand = DecodeOperand(context, framePointer, ref pc);
                        if (register != NoRegister)
                        {
                            context.SetStack(framePointer, register, operand);
                        }
                    }
                }
                break;

                case Opcode.MatchVar:
                {
                    object register = Register(context, framePointer, pc++);
                    if (pc < writeModeEndAddress)
                    {
                        // Write mode
                        SetOperand(context, framePointer, ref pc, register);
                    }
                    else
                    {
                        // Read mode
                        if (!Term.Unify(DecodeOperand(context, framePointer, ref pc), register, context))
                        {
                            goto fail;
                        }
                    }
                }
                break;

                case Opcode.MatchStructure:
                {
                    Symbol functor    = GetSymbol(ref pc);
                    int    arity      = code[pc++];
                    ushort endAddress = GetUShort(ref pc);

                    if (pc < writeModeEndAddress)
                    {
                        // Write mode
                        SetOperand(context, framePointer, ref pc, new Structure(functor, new object[arity]));
                    }
                    else
                    {
                        // Read mode
                        object arg = DecodeOperand(context, framePointer, ref pc);
                        var    s   = arg as Structure;
                        if (s == null || !s.IsFunctor(functor, arity))
                        {
                            var l = arg as LogicVariable;
                            if (l == null)
                            {
                                goto fail;
                            }
                            l.UnifyWithStructure(new Structure(functor, new object[arity]));
                            writeModeEndAddress = endAddress;
                        }
                    }
                }
                break;
                    #endregion

                    #region Body opcodes: structure building
                case Opcode.BuildStructure:
                {
                    Symbol functor = GetSymbol(ref pc);
                    int    arity   = code[pc++];
                    SetOperand(context, framePointer, ref pc,
                               new Structure(functor, new object[arity]));
                }
                break;

                case Opcode.BuildLiteral:
                    SetOperand(context, framePointer, ref pc, GetLiteral(ref pc));
                    break;

                case Opcode.BuildVar:
                {
                    Symbol name = GetSymbol(ref pc);
                    SetOperand(context, framePointer, ref pc, new LogicVariable(name));
                }
                break;

                case Opcode.BuildReg:
                    object registerValue = Register(context, framePointer, pc++);
                    SetOperand(context, framePointer, ref pc, registerValue);
                    break;
                    #endregion

                    #region Body: control flow
                case Opcode.CallWokenGoals:
                case Opcode.Call:
                case Opcode.CallPrimitive:
                    endOfBuilds = pc;
                    // ReSharper disable once InconsistentNaming
                    ushort succeedPC;
                    IEnumerator <CutState> iterator;
                    var failPC = StartCallInstruction(context, framePointer, ref pc, out succeedPC, out iterator);
                    while (true)
                    {
                        if (iterator == null || iterator.MoveNext())
                        {
                            // Call succeeds
                            if (succeedPC == SuccessContinuationPC)
                            {
                                yield return(CutState.Continue);

                                // If we get here, then our caller is requesting a redo
                                // Fall through and continue this iterator.
                                if (iterator == null)
                                {
                                    goto fail;                     // Kluge: special case to handle CallWokenGoals instruction where there are no woken goals.
                                }
                            }
                            else
                            {
                                if (succeedPC > endOfBuilds)
                                {
                                    // Haven't run the build instructions for next goal, so break out and run them.
                                    break;
                                }
                                pc = (ushort)(succeedPC + 1);   // StartCallInstruction assumes we've skipped over the opcode.
                                // succeedPC is address of call/callprimitive instruction; next byte is iterator register
                                failPC = this.StartCallInstruction(context, framePointer, ref pc, out succeedPC, out iterator);
                                // Continue while loop
                            }
                        }
                        else
                        {
                            // Call fails
                            switch (failPC)
                            {
                            case FailContinuationPC:
                                goto fail;

                            case CutContinuationPC:
                                goto cut;

                            default:
                                // failPC is address of call/callprimitive instruction; next byte is iterator register
                                pc       = (ushort)(failPC + 1);    // +1 because we're skipping over the opcode
                                iterator =
                                    (IEnumerator <CutState>)context.GetStack(framePointer, code[pc++]);
                                if (iterator == null)          // Kluge: special case to handle CallWokenGoals instruction where there are no woken goals.
                                {
                                    goto fail;
                                }

                                failPC    = GetUShort(ref pc);
                                succeedPC = GetUShort(ref pc);
                                break;
                            }
                        }
                    }
                    break;
                    #endregion

                default:
                    Debug.Assert(false, "Bad opcode in byte compiled Prolog rule, pc=" + (pc - 1) + ", opcode=" + ((Opcode)code[pc - 1]));
                    break;
                }
            }

            // The while loop above never terminates normally; it only yeilds or branches to one of the following labels
cut:
            context.PopFrame(framePointer);
            context.RestoreVariables(traceMark);
            yield return(CutState.ForceFail);

fail:
            context.PopFrame(framePointer);
            context.RestoreVariables(traceMark);
        }