private void WalkGoal(KnowledgeBase kb, KnowledgeBaseRule rule, object goal) { goal = Term.Deref(goal); var atom = goal as Symbol; if (atom != null) { var p = new PredicateIndicator(atom, 0); if (PrologPrimitives.IsDefined(p)) { return; } var predicate = kb.CheckForPredicateInfo(p); if (predicate == null) { rule.PrintWarning("undefined predicate {0}", p); } else { MarkReferenced(predicate); } } else { var s = goal as Structure; if (s != null) { WalkGoal(kb, rule, s); } else if (!(goal is LogicVariable) && !(goal is bool)) { rule.PrintWarning("malformed goal: {0}", goal); } } }
/// <summary> /// Adds a new user-defined binary primitive predicate given /// C# delegates to implement its different modes. Assumes /// arguments are always atomic, and that the relation won't /// be called with the same unbound variable for both arguments. /// </summary> /// <param name="name">Name to give to the predicate</param> /// <param name="documentation">Description of the operation of the predicate</param> /// <param name="arg1Name">Name of the first argument (for documentation and error messages)</param> /// <param name="arg2Name">Name of hte second argument (for documentation and error messages)</param> /// <param name="filter">Implementation of predicate for case where both arguments are instantiated.</param> /// <param name="arg1Enumerator">For non-left-unique predicates: implementation for case where only the second argument is instantiated, so the values of the first argument must be enumerated.</param> /// <param name="arg1Function">For left-unique predicates: implementation for the case where only the second argument is instantiated, so need to compute the value of the first (if any).</param> /// <param name="arg2Enumerator">For non-right-unique predicates: implementation for case where only the first argument is instantiated, so the values of the second argument must be enumerated.</param> /// <param name="arg2Function">For right-unique predicates: implementation for the case where only the first argument is instantiated, so need to compute the value of the second (if any)</param> /// <param name="doubleEnumerator">Implementation of the case where neither argument is instantiated.</param> public static void Declare( string name, string documentation, string arg1Name, string arg2Name, Filter filter, Arg1Enumerator arg1Enumerator = null, Arg1Function arg1Function = null, Arg2Enumerator arg2Enumerator = null, Arg2Function arg2Function = null, DoubleEnumerator doubleEnumerator = null) { PrologPrimitives.DefinePrimitive( Symbol.Intern(name), new BinaryPrimitive <T1, T2>( name, arg1Name, arg2Name, filter, arg1Enumerator, arg1Function, arg2Enumerator, arg2Function, doubleEnumerator).BinaryPrimitiveImplementation, null, documentation, arg1Name, arg2Name); }
/// <summary> /// True if the specified functor/arity is undefined. /// </summary> public bool Undefined(PredicateIndicator p) { if (PrologPrimitives.IsDefined(p)) return false; if (CheckForPredicateInfoInThisKB(p) != null) return false; foreach (KnowledgeBase import in imports) if (!import.Undefined(p)) return false; return true; }
private ushort StartCallInstruction(PrologContext context, int framePointer, ref ushort pc, out ushort succeedPC, out IEnumerator <CutState> iterator) { int iteratorRegister = code[pc++]; ushort failPC = GetUShort(ref pc); succeedPC = GetUShort(ref pc); iterator = null; // Make the iterator. How we do this depends on the opcode, so re-fetch it. switch ((Opcode)code[pc - CallTargetOffset]) { case Opcode.CallWokenGoals: { if (context.GoalsHaveWoken) { iterator = context.ProveAllWokenGoals().GetEnumerator(); } } break; case Opcode.Call: { // It's a user-defined predicate call PredicateInfo calledPredicate = GetPredicate(ref pc); PushCallArgs(context, framePointer, predicate.Arity, ref pc); iterator = calledPredicate.StackCall(context).GetEnumerator(); } break; case Opcode.CallPrimitive: { // It's a primitive call PrologPrimitives.PrimitiveImplementation implementation = GetPrimitive(ref pc); int arity = code[pc++]; PushCallArgs(context, framePointer, arity, ref pc); iterator = PrologPrimitives.StackCall(implementation, arity, context).GetEnumerator(); } break; default: Debug.Assert(false, "Bad call opcode"); break; } context.SetStack(framePointer, iteratorRegister, iterator); return(failPC); }
/// <summary> /// True if the specified functor/arity is undefined. /// </summary> public bool Undefined(PredicateIndicator p) { if (PrologPrimitives.IsDefined(p)) { return(false); } if (CheckForPredicateInfoInThisKB(p) != null) { return(false); } foreach (KnowledgeBase import in imports) { if (!import.Undefined(p)) { return(false); } } return(true); }
/// <summary> /// Prints the byte code for the rule to System.Console. /// </summary> public void Disassemble() { ushort pc = 0; while (pc < code.Length) { var opcode = (Opcode)code[pc++]; Console.Write("L{0}: {1} ", pc - 1, opcode.ToString()); switch (opcode) { case Opcode.MatchStructure: { Symbol functor = GetSymbol(ref pc); int arity = code[pc++]; int endofMatch = GetUShort(ref pc); Console.Write("{0}/{1}, L{2}, ", functor.Name, arity, endofMatch); DisassembleOperand(ref pc); } break; case Opcode.MatchVar: case Opcode.MatchVarFirst: { if (opcode == Opcode.MatchVarFirst) { Console.Write("{0}, ", GetSymbol(ref pc)); } byte register = code[pc++]; Console.Write("{0}, ", FormatRegister(register)); DisassembleOperand(ref pc); } break; case Opcode.MatchLiteral: { Console.Write(GetLiteral(ref pc)); Console.Write(", "); DisassembleOperand(ref pc); } break; case Opcode.BuildStructure: { Console.Write(GetSymbol(ref pc)); Console.Write("/{0}, ", code[pc++]); DisassembleOperand(ref pc); } break; case Opcode.BuildVar: { Console.Write(GetSymbol(ref pc)); Console.Write(", "); DisassembleOperand(ref pc); } break; case Opcode.BuildReg: { byte reg = code[pc++]; Console.Write("{0}, ", FormatRegister(reg)); DisassembleOperand(ref pc); } break; case Opcode.BuildLiteral: { Console.Write(GetLiteral(ref pc)); DisassembleOperand(ref pc); } break; case Opcode.Call: case Opcode.CallPrimitive: case Opcode.CallWokenGoals: { Console.Write("{0}", FormatRegister(code[pc++])); Console.Write(", {0}", FormatLabel(GetUShort(ref pc))); Console.Write(", {0}", FormatLabel(GetUShort(ref pc))); if (opcode != Opcode.CallWokenGoals) { int arity; if (opcode == Opcode.Call) { PredicateInfo p = GetPredicate(ref pc); Console.Write(", {0}/{1}", p.Name, p.Arity); arity = p.Arity; } else { PrologPrimitives.PrimitiveImplementation impl = GetPrimitive(ref pc); arity = code[pc++]; Console.Write(", {0}/{1}", PrologPrimitives.PrimitiveName(impl), arity); } while (arity-- > 0) { Console.Write(", "); int arg = code[pc++]; if (arg < 0x80) { Console.Write("{0}", FormatRegister(arg)); // It's a register } else { // It's a literal arg = ((arg & 0x7f) << 8) + code[pc++]; Console.Write(GlobalLiteralTable[arg]); } } } } break; default: throw new Exception("Unknown opcode " + opcode); } Console.WriteLine(); } }
static KnowledgeBase() { Global = new KnowledgeBase("global", null, null); PrologPrimitives.InstallPrimitives(); }
private void WalkGoal(KnowledgeBase kb, KnowledgeBaseRule rule, Structure goal) { var predicateIndicator = goal.PredicateIndicator; Symbol functor = goal.Functor; int arity = goal.Arity; switch (functor.Name) { case "begin": foreach (var arg in goal.Arguments) { WalkGoal(kb, rule, arg); } break; case "once": case "check": case "randomize": case "not": case "\\+": if (arity == 1) { WalkGoal(kb, rule, goal.Argument(0)); } else { WarnUndefined(rule, functor, arity); } break; case ",": case ";": case "->": if (arity == 2) { WalkGoal(kb, rule, goal.Argument(0)); WalkGoal(kb, rule, goal.Argument(1)); } else { WarnUndefined(rule, functor, arity); } break; case "call": case "maplist": if (arity < 1) { WarnUndefined(rule, functor, arity); } else { object goalToCall = goal.Argument(0); var goalToCallAsStructure = goalToCall as Structure; if (goalToCallAsStructure != null) { var newArgs = new object[arity - 1 + goalToCallAsStructure.Arity]; goalToCallAsStructure.Arguments.CopyTo(newArgs, 0); WalkGoal(kb, rule, new Structure(goalToCallAsStructure.Functor, newArgs)); } else { var call = goalToCall as Symbol; if (call != null) { this.WalkGoal(kb, rule, new Structure(call, new object[arity - 1])); } } } break; case "arg_min": case "arg_max": if (arity == 3) { WalkGoal(kb, rule, goal.Argument(2)); } else { WarnUndefined(rule, functor, arity); } break; case "find_all": if (arity == 3) { WalkGoal(kb, rule, goal.Argument(1)); } else { WarnUndefined(rule, functor, arity); } break; default: if (PrologPrimitives.IsDefined(predicateIndicator)) { var arglist = PrologPrimitives.Arglist(predicateIndicator.Functor); for (int i = 0; i < Math.Min(predicateIndicator.Arity, arglist.Count); i++) { var argSym = arglist[i] as Symbol; if (argSym != null) { var arg = argSym.Name; if (arg[0] == ':') { WalkGoal(kb, rule, goal.Argument(i)); } else if (arg == "..." && arglist[i - 1] is string && ((string)arglist[i - 1])[0] == ':') { // Predicate accepts a rest arg of goals for (int j = i; j < predicateIndicator.Arity; j++) { WalkGoal(kb, rule, goal.Argument(j)); } } } } } else { var predicate = kb.CheckForPredicateInfo(predicateIndicator); if (predicate == null) { WarnUndefined(rule, functor, arity); } else { MarkReferenced(predicate); if (predicate.HigherOrderArguments != null) { foreach (int argIndex in predicate.HigherOrderArguments) { WalkGoal(kb, rule, goal.Argument(argIndex)); } } } } break; } }