private void CompileMatcher(byte register, byte argument, object obj) { obj = Term.Deref(obj); var lv = obj as LogicVariable; if (lv != null) { var info = env[lv]; if (register != NoRegister || info.register != argument) // If top level and first occurance, don't bother. { env.InsureAllocated(info); if (info.AlreadyStored) { Emit(Opcode.MatchVar, info.register); } else { Emit(Opcode.MatchVarFirst, SymbolTable.IndexOf(lv.Name), info.register); } EmitOperand(register, argument); } env.OneUseCompiled(info); } else { var structure = obj as Structure; if (structure != null) { Structure s = structure; byte destinationRegister = (register == NoRegister)?argument:this.env.GetRegister(); this.Emit(Opcode.MatchStructure, SymbolTable.IndexOf(s.Functor), (byte)s.Arity); ushort backPatchAddress = this.CurrentPC; this.EmitUShort(0); this.EmitOperand(register, argument, destinationRegister); for (byte i = 0; i < s.Arity; i++) { this.CompileMatcher(destinationRegister, i, s.Argument(i)); } this.BackPatch(backPatchAddress, this.CurrentPC); if (register != NoRegister) { this.env.FreeRegister(destinationRegister); } } else { this.Emit(Opcode.MatchLiteral, GlobalLiteralTable.IndexOf(obj)); this.EmitOperand(register, argument); } } }
private void CompileBuildLiteral(object term, byte argRegister, byte argument) { Emit(Opcode.BuildLiteral, GlobalLiteralTable.IndexOf(term)); EmitOperand(argRegister, argument); }
private void CompileGoal(Structure goal, ref ushort failAddress, ref ushort backPatchAddress) { byte continuationRegister = env.GetRegister(); // Allocate registers to goal arguments. var argRegisters = new byte[goal.Arity]; for (int i = 0; i < goal.Arity; i++) { object arg = goal.Argument(i); if (arg is Structure) { argRegisters[i] = env.GetRegister(); } else { var @var = arg as LogicVariable; if (@var != null) { argRegisters[i] = this.env.InsureRegisterAndLock(@var); } else { // It's a literal. argRegisters[i] = NoRegister; } } } // Build goal arguments into registers. for (int i = 0; i < goal.Arity; i++) { if (argRegisters[i] != NoRegister) { CompileBuild(goal.Argument(i), NoRegister, argRegisters[i]); } } // Emit call instruction ushort startOfCallInstruction = CurrentPC; BackPatch(backPatchAddress, startOfCallInstruction); PrologPrimitives.PrimitiveImplementation primitiveImplementation; bool isPrimitive = PrologPrimitives.Implementations.TryGetValue(goal.Functor, out primitiveImplementation); // Call header Emit(isPrimitive?Opcode.CallPrimitive : Opcode.Call, continuationRegister); EmitUShort(failAddress); backPatchAddress = CurrentPC; EmitUShort(0); // This will get backpatched // Call target if (isPrimitive) { EmitUShort(PrimitiveTable.IndexOf(primitiveImplementation)); EmitByte((byte)goal.Arity); } else { EmitUShort(PredicateTable.IndexOf(this.knowledgeBase.EntryForStoring(goal.PredicateIndicator))); } // Call arguments for (int i = 0; i < goal.Arity; i++) { byte reg = argRegisters[i]; if (reg == NoRegister) { EmitUShort((ushort)(0x8000 + GlobalLiteralTable.IndexOf(goal.Argument(i)))); } else { EmitByte(reg); } } failAddress = startOfCallInstruction; }