/************************************************************************* * * * YAP Prolog * * * * Yap Prolog was developed at NCCUP - Universidade do Porto * * * * Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 * * * ************************************************************************** * * * File: userpreds.c * * Last rev: * * mods: * * comments: an entry for user defined predicates * * * *************************************************************************/ #ifdef SCCS static char SccsId[] = "%W% %G%"; #endif /* * This file is an entry for user defined C-predicates. * * There are two sorts of C-Predicates: deterministic - which should be defined * in the function InitUserCPreds(). * * backtrackable - they include a start and a continuation function, the first * one called by the first invocation, the last one called after a fail. This * can be seen as: pred :- init ; repeat, cont. These predicates should be * defined in the function InitUserBacks() * * These two functions are called after any "restore" operation. * * The function InitUserExtensions() is called once, when starting the execution * of the program, and should be used to initialize any user-defined * extensions (like the execution environment or interfaces to other * programs). * */ #include "Yap.h" #include "Yatom.h" #include "YapHeap.h" #if EUROTRA #include "yapio.h" #if HAVE_UNISTD_H #include #endif #endif /* You should include here the prototypes for all static functions */ #ifdef EUROTRA static int p_clean(void); static int p_namelength(void); static int p_getpid(void); static int p_exit(void); static int p_incrcounter(void); static int p_setcounter(void); static int p_trapsignal(void); static int subsumes(Term, Term); static int p_subsumes(void); static int p_grab_tokens(void); #endif #ifdef MACYAP static typedef int (*SignalProc)(); static SignalProc skel_signal(int, SignalProc); static int chdir(char *); #endif #ifdef SFUNC static int p_softfunctor(void); #endif /* SFUNC */ #ifdef USERPREDS /* These are some examples of user-defined functions */ /* * unify(A,B) --> unification with occurs-check it uses the functions * full_unification and occurs_in * * occurs_check(V,S) :- var(S), !, S \== V. occurs_check(V,S) :- primitive(S), * !. occurs_check(V,[H|T]) :- !, occurs_check(V,H), occurs_check(V,T). * occurs_check(V,St) :- functor(T,_,N), occurs_check_struct(N,V,St). * * occurs_check_struct(1,V,T) :- !, arg(1,T,A), occurs_check(V,A). * occurs_check_struct(N,V,T) :- N1 is N-1, occurs_check_structure(N1,V,T), * arg(N,T,A), occurs_check(V,A). * * unify(X,Y) :- var(X), var(Y), !, X = Y. unify(X,Y) :- var(X), !, * occurs_check(X,Y), X = Y. unify(X,Y) :- var(Y), !, occurs_check(Y,X), X = * Y. unify([H0|T0],[H1|T1]) :- !, unify(H0,H1), unify(T0,T1). unify(X,Y) :- * functor(X,A,N), functor(Y,A,N), unify_structs(N,X,Y). * * unify_structs(1,X,Y) :- !, arg(1,X,A), arg(1,Y,B), unify(A,B). * unify_structs(N,Y,Z) :- N1 is N-1, unify_structs(N1,X,Y), arg(N,X,A), * arg(N,Y,B), unify(A,B). */ /* occurs-in --> checks if the variable V occurs in term S */ static int occurs_check(V, T) Term V, T; { /* V and S are always derefed */ if (IsVarTerm(T)) { return (V != T); } else if (IsPrimitiveTerm(T)) { return (TRUE); } else if (IsPairTerm(T)) { return (occurs_check(V, HeadOfTerm(T)) && occurs_check(V, TailOfTerm(T))); } else if (IsApplTerm(T)) { unsigned int i; unsigned int arity = ArityOfFunctor(FunctorOfTerm(T)); for (i = 1; i <= arity; ++i) if (!occurs_check(V, ArgOfTerm(i, T))) return (FALSE); return (TRUE); } return (FALSE); } /* If you worry about coroutining the routine must receive the arguments before dereferencing, otherwise unify() won't be to wake possible bound variables */ static int full_unification(T1, T2) Term T1, T2; { Term t1 = Deref(T1); Term t2 = Deref(T2); if (IsVarTerm(t1)) {/* Testing for variables should be done first */ if (IsVarTerm(t2) || IsPrimitiveTerm(t2)) return (Yap_unify(T1, t2)); if (occurs_check(t1, t2)) return (Yap_unify(T1, t2)); return (FALSE); } if (IsVarTerm(t2)) { if (occurs_check(t2, t1)) return (Yap_unify(T2, t1)); return (FALSE); } if (IsPrimitiveTerm(t1)) { if (IsFloatTerm(t1)) return (IsFloatTerm(t2) && FloatOfTerm(t1) == FloatOfTerm(t2)); else if (IsRefTerm(t1)) return (IsRefTerm(t2) && RefOfTerm(t1) == RefOfTerm(t2)); if (IsLongIntTerm(t1)) return (IsLongIntTerm(t2) && LongIntOfTerm(t1) == LongIntOfTerm(t2)); else return (t1 == t2); } if (IsPairTerm(t1)) { if (!IsPairTerm(t2)) return (FALSE); return (full_unification(HeadOfTermCell(t1), HeadOfTermCell(t2)) && full_unification(TailOfTermCell(t1), TailOfTermCell(t2))); } if (IsApplTerm(t1)) { unsigned int i, arity; if (!IsApplTerm(t2)) return (FALSE); if (FunctorOfTerm(t1) != FunctorOfTerm(t2)) return (FALSE); arity = ArityOfFunctor(FunctorOfTerm(t1)); for (i = 1; i <= arity; ++i) if (!full_unification(ArgOfTermCell(i, t1), ArgOfTerm(i, t2))) return (FALSE); return (TRUE); } #ifdef lint return (FALSE); #endif } static int p_occurs_check() { /* occurs_check(?,?) */ return (occurs_check(Deref(ARG1), Deref(DARG2))); } /* Out of date, use unify_with_occurs_check instead*/ static int p_unify() { /* unify(?,?) */ /* routines that perform unification must receive the original arguments */ return (full_unification(ARG1, ARG2)); } /* * One example of a counter using the atom value functions counter(Atom,M,N) * * If the second argument is uninstantiated, then it will be unified with the * current value of the counter, otherwyse the counter will be set to its * value. The third argument then be unified with the next integer, which * will become the current counter value. */ static int p_counter() { /* counter(+Atom,?Number,?Next) */ Term TCount, TNext, T1, T2; Atom a; /* Int -> an YAP integer */ Int val; T1 = Deref(ARG1); ARG2 = Deref(ARG2); /* No need to deref ARG3, we don't want to know what's in there */ if (IsVarTerm(T1) || !IsAtomTerm(T1)) return (FALSE); a = AtomOfTerm(T1); if (IsVarTerm(T2)) { TCount = Yap_GetValue(a); if (!IsIntTerm(TCount)) return (FALSE); Yap_unify_constant(ARG2, TCount); /* always succeeds */ val = IntOfTerm(TCount); } else { if (!IsIntTerm(T2)) return (FALSE); val = IntOfTerm(T2); } val++; /* The atom will now take the incremented value */ Yap_PutValue(a, TNext = MkIntTerm(val)); return (Yap_unify_constant(ARG3, TNext)); } /* * Concatenate an instantiated list to another list, and unify with third * argument */ /* * In order to be more efficient, iconcat instead of unifying the terms in * the old structure with the ones in the new one just copies them. This is a * dangerous behaviour, though acceptable in this case, and you should try to * avoid it whenever possible */ #ifdef COMMENT static int p_iconcat() { /* iconcat(+L1,+L2,-L) */ Term Tkeep[1025]; /* Will do it just for lists less * than 1024 elements long */ register Term *Tkp = Tkeep; register Term L0, L1; Term T2; L0 = Deref(ARG1); *Tkp++ = Unsigned(0); L1 = TermNil; while (L0 != L1) { /* * Usually you should test if L1 a var, if (!IsPairTerm(L0)) * return(FALSE); */ *Tkp++ = HeadOfTerm(L0); L0 = TailOfTerm(L0); } L1 = Deref(ARG2); while (L0 = *--Tkp) L1 = MkPairTerm(L0, L1); T2 = L1; return (Yap_unify(T2, ARG3)); } #endif /* COMMENT */ static int p_iconcat() { /* iconcat(+L1,+L2,-L) */ register Term *Tkp = H, *tp; register Term L0, L1; Term T2; L0 = Deref(ARG1); L1 = TermNil; while (L0 != L1) { /* if (!IsPairTerm(L0)) return(FALSE); */ tp = Tkp; *tp = AbsPair(++Tkp); *Tkp++ = HeadOfTerm(L0); L0 = TailOfTerm(L0); } *Tkp++ = Deref(ARG2); T2 = *H; H = Tkp; return (Yap_unify(T2, ARG3)); } #endif /* USERPREDS */ #ifdef EUROTRA static int p_clean() /* predicate clean for ets */ /* * clean(FB,CFB) :- FB =.. [fb|L],!, clean1(L,CL), CFB =.. [fb|CL]. * clean(FB,CFB) :- var(FB). * * clean1([],[]) :- !. clean1([H|T],[CH|CT]) :- H==$u,!, clean1(T,CT). * clean1([H|T],[H|CT]) :- clean1(T,CT). */ { unsigned int arity, i; Term t, Args[255]; Term t1 = Deref(ARG1); if (IsVarTerm(t1)) return (TRUE); if (!(IsApplTerm(t1) && NameOfFunctor(FunctorOfTerm(t1)) == AtomFB)) return (FALSE); arity = ArityOfFunctor(FunctorOfTerm(t1)); #ifdef SFUNC if (arity == SFArity) { CELL *pt = H, *ntp = ArgsOfSFTerm(t1); Term tn = AbsAppl(H); *pt++ = FunctorOfTerm(t1); RESET_VARIABLE(pt); pt++; while (*pt++ = *ntp++) if ((*pt++ = *ntp++) == MkAtomTerm(AtomDollarUndef)) pt -= 2; H = pt; return (Yap_unify(tn, ARG2)); } #endif for (i = 1; i <= arity; ++i) { if ((t = ArgOfTerm(i, t1)) == TermDollarU) t = MkVarTerm(); Args[i - 1] = t; } t = Yap_MkApplTerm(FunctorOfTerm(t1), arity, Args); return (Yap_unify(ARG2, t)); } static Term *subs_table; static int subs_entries; #define SUBS_TABLE_SIZE 500 static int subsumes(T1, T2) Term T1, T2; { int i; if (IsVarTerm(T1)) { if (!IsVarTerm(T2)) return (FALSE); if (T1 == T2) return (TRUE); for (i = 0; i < subs_entries; ++i) if (subs_table[i] == T2) return (FALSE); if (T2 < T1) {/* T1 gets instantiated with T2 */ Yap_unify(T1, T2); for (i = 0; i < subs_entries; ++i) if (subs_table[i] == T1) { subs_table[i] = T2; return (TRUE); } subs_table[subs_entries++] = T2; return (TRUE); } /* T2 gets instantiated with T1 */ Yap_unify(T1, T2); for (i = 0; i < subs_entries; ++i) if (subs_table[i] == T1) return (TRUE); subs_table[subs_entries++] = T1; return (TRUE); } if (IsVarTerm(T2)) { for (i = 0; i < subs_entries; ++i) if (subs_table[i] == T2) return (FALSE); return (Yap_unify(T1, T2)); } if (IsPrimitiveTerm(T1)) { if (IsFloatTerm(T1)) return (IsFloatTerm(T2) && FloatOfTerm(T1) == FloatOfTerm(T2)); else if (IsRefTerm(T1)) return (IsRefTerm(T2) && RefOfTerm(T1) == RefOfTerm(T2)); else if (IsLongIntTerm(T1)) return (IsLongIntTerm(T2) && LongIntOfTerm(T1) == LongIntOfTerm(T2)); else return (T1 == T2); } if (IsPairTerm(T1)) { if (!IsPairTerm(T2)) return (FALSE); return (subsumes(HeadOfTerm(T1), HeadOfTerm(T2)) && subsumes(TailOfTerm(T1), TailOfTerm(T2))); } if (IsApplTerm(T1)) { int arity; if (!IsApplTerm(T2)) return (FALSE); if (FunctorOfTerm(T1) != FunctorOfTerm(T2)) return (FALSE); arity = ArityOfFunctor(FunctorOfTerm(T1)); #ifdef SFUNC if (arity == SFArity) { CELL *a1a = ArgsOfSFTerm(T1), *a2a = ArgsOfSFTerm(T2); CELL *a1p = a1a - 1, *a2p = a2a - 1; CELL *pt = H; int flags = 0; Term t1, t2; *pt++ = FunctorOfTerm(T1); RESET_VARIABLE(pt); pt++; while (1) { if (*a2a < *a1a || *a1a == 0) { if (*a2a) { *pt++ = *a2a++; t2 = Derefa(a2a); ++a2a; if (!IsVarTerm(t2)) return (FALSE); for (i = 0; i < subs_entries; ++i) if (subs_table[i] == t2) return (FALSE); subs_table[subs_entries++] = t2; *pt++ = t2; flags |= 1; } else { /* T2 is finished */ if ((flags & 1) == 0) {/* containned in first */ *a2p = Unsigned(a1p - 1); if (a2p < HB) *TR++ = Unsigned(a2p); return (TRUE); } while ((*pt++ = *a1a++)) ; *a1p = Unsigned(H); if (a1p < HB) *TR++ = Unsigned(a1p); *a2p = Unsigned(H); if (a2p < HB) *TR++ = Unsigned(a2p); H = pt; return (TRUE); } } else if (*a2a > *a1a || *a2a == 0) { *pt++ = *a1a++; t1 = Derefa(a1a); ++a1a; if (IsVarTerm(t1)) { for (i = 0; i < subs_entries; ++i) if (subs_table[i] == t1) break; if (i >= subs_entries) subs_table[subs_entries++] = t1; } *pt++ = t1; flags |= 2; } else if (*a1a == *a2a) { *pt++ = *a1a++; ++a2a; t1 = Derefa(a1a); ++a1a; t2 = Derefa(a2a); ++a2a; *pt++ = t1; if (!subsumes(t1, t2)) return (FALSE); } } } #endif for (i = 1; i <= arity; ++i) if (!subsumes(ArgOfTerm(i, T1), ArgOfTerm(i, T2))) return (FALSE); return (TRUE); } return (FALSE); } static int p_subsumes() { Term work_space[SUBS_TABLE_SIZE]; subs_table = work_space; subs_entries = 0; return (subsumes(Deref(ARG1), Deref(ARG2))); } static int p_namelength() { register Term t = Deref(ARG1); Term tf; if (IsVarTerm(t)) { return (FALSE); } if (IsAtomTerm(t)) { Term tf = MkIntTerm(strlen(RepAtom(AtomOfTerm(t))->StrOfAE)); return (Yap_unify_constant(ARG2, tf)); } else if (IsIntTerm(t)) { register int i = 1, k = IntOfTerm(t); if (k < 0) ++i, k = -k; while (k > 10) ++i, k /= 10; tf = MkIntTerm(i); return (Yap_unify_constant(ARG2, tf)); } else return (FALSE); } static int p_getpid() { #ifndef MPW Term t = MkIntTerm(getpid()); #else Term t = MkIntTerm(1); #endif return (Yap_unify_constant(ARG1, t)); } static int p_exit() { register Term t = Deref(ARG1); if (IsVarTerm(t) || !IsIntTerm(t)) return (FALSE); Yap_exit((int)IntOfTerm(t)); return (FALSE); } static int current_pos; static int p_incrcounter() { register Term t = Deref(ARG1); if (IsVarTerm(t) || !IsIntTerm(t)) return (FALSE); current_pos += IntOfTerm(t); return (TRUE); } static int p_setcounter() { register Term t = Deref(ARG1); if (IsVarTerm(t) || !IsIntTerm(t)) { return (Yap_unify_constant(ARG1, MkIntTerm(current_pos))); } else { current_pos = IntOfTerm(t); return (TRUE); } } #include #ifdef MACYAP #define signal(A, B) skel_signal(A, B) #endif #ifndef EOF #define EOF -1 #endif static int p_trapsignal(void) { #ifndef MPW signal(SIGINT, SIG_IGN); #endif return (TRUE); } #define varstarter(ch) ((ch >= 'A' && ch <= 'Z') || ch == '_') #define idstarter(ch) (ch >= 'a' && ch <= 'z') #define idchar(ch) \ ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || \ (ch >= 'a' && ch <= 'z') || ch == '_') static int p_grab_tokens() { Term *p = ASP - 20, *p0, t; Functor IdFunctor, VarFunctor; char ch, IdChars[256], *chp; IdFunctor = FunctorId; VarFunctor = FunctorDollarVar; p0 = p; ch = Yap_PlGetchar(); while (1) { while (ch <= ' ' && ch != EOF) ch = Yap_PlGetchar(); if (ch == '.' || ch == EOF) break; if (ch == '%') { while ((ch = Yap_PlGetchar()) != 10) ; ch = Yap_PlGetchar(); continue; } if (ch == '\'') { chp = IdChars; while (1) { ch = Yap_PlGetchar(); if (ch == '\'') break; *chp++ = ch; } *chp = 0; t = MkAtomTerm(Yap_LookupAtom(IdChars)); *p-- = Yap_MkApplTerm(IdFunctor, 1, &t); ch = Yap_PlGetchar(); continue; } if (varstarter(ch)) { chp = IdChars; *chp++ = ch; while (1) { ch = Yap_PlGetchar(); if (!idchar(ch)) break; *chp++ = ch; } *chp = 0; t = MkAtomTerm(Yap_LookupAtom(IdChars)); *p-- = Yap_MkApplTerm(VarFunctor, 1, &t); continue; } if (idstarter(ch)) { chp = IdChars; *chp++ = ch; while (1) { ch = Yap_PlGetchar(); if (!idchar(ch)) break; *chp++ = ch; } *chp = 0; t = MkAtomTerm(Yap_LookupAtom(IdChars)); *p-- = Yap_MkApplTerm(IdFunctor, 1, &t); continue; } IdChars[0] = ch; IdChars[1] = 0; *p-- = MkAtomTerm(Yap_LookupAtom(IdChars)); ch = Yap_PlGetchar(); } t = MkAtomTerm(AtomNil); while (p != p0) { t = MkPairTerm(*++p, t); } return (Yap_unify(ARG1, t)); } #endif /* EUROTRA */ #ifdef SFUNC static p_softfunctor() { Term nilvalue = 0; SFEntry *pe; Prop p0; Atom a; Term t1 = Deref(ARG1); Term t2 = Deref(ARG2); if (IsAtomTerm(t2)) nilvalue = t2; if (!IsAtomTerm(t1)) return (FALSE); a = AtomOfTerm(t1); WRITE_LOCK(RepAtom(a)->ARWLock); if ((p0 = Yap_GetAProp(a, SFProperty)) == NIL) { pe = (SFEntry *)Yap_AllocAtomSpace(sizeof(*pe)); pe->KindOfPE = SFProperty; AddPropToAtom(RepAtom(a), (PropEntry *)pe); } else pe = RepSFProp(p0); WRITE_UNLOCK(RepAtom(a)->ARWLock); pe->NilValue = nilvalue; return (TRUE); } #endif /* SFUNC */ #include /* static Int p_matching_distances(void) { return(fabs(FloatOfTerm(Deref(ARG1))-FloatOfTerm(Deref(ARG2))) <= FloatOfTerm(Deref(ARG3))); } */ void Yap_InitUserCPreds(void) { #ifdef XINTERFACE Yap_InitXPreds(); #endif #ifdef EUROTRA Yap_InitCPred("clean", 2, p_clean, SafePredFlag | SyncPredFlag); Yap_InitCPred("name_length", 2, p_namelength, SafePredFlag | SyncPredFlag); Yap_InitCPred("get_pid", 1, p_getpid, SafePredFlag); Yap_InitCPred("exit", 1, p_exit, SafePredFlag | SyncPredFlag); Yap_InitCPred("incr_counter", 1, p_incrcounter, SafePredFlag | SyncPredFlag); Yap_InitCPred("set_counter", 1, p_setcounter, SafePredFlag | SyncPredFlag); Yap_InitCPred("trap_signal", 0, p_trapsignal, SafePredFlag | SyncPredFlag); Yap_InitCPred("mark2_grab_tokens", 1, p_grab_tokens, SafePredFlag | SyncPredFlag); Yap_InitCPred("subsumes", 2, p_subsumes, SafePredFlag); #endif #ifdef SFUNC Yap_InitCPred("sparse_functor", 2, p_softfunctor, SafePredFlag); #endif /* SFUNC */ /* Yap_InitCPred("match_distances", 3, p_matching_distances, SafePredFlag); */ /* Yap_InitCPred("unify",2,p_unify,SafePredFlag); */ /* Yap_InitCPred("occurs_check",2,p_occurs_check,SafePredFlag); */ /* Yap_InitCPred("counter",3,p_counter,SafePredFlag); */ /* Yap_InitCPred("iconcat",3,p_iconcat,SafePredFlag); */ } void Yap_InitUserBacks(void) {}