This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
yap-6.3/C/corout.c

581 lines
13 KiB
C
Raw Normal View History

/*************************************************************************
* *
* YAP Prolog *
* *
* Yap Prolog was developed at NCCUP - Universidade do Porto *
* *
* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
* *
**************************************************************************
* *
* File: corout.c *
* Last rev: *
* mods: *
* comments: Co-routining from within YAP *
* *
*************************************************************************/
#ifdef SCCS
static char SccsId[]="%W% %G%";
#endif
#include "Yap.h"
#include "Yatom.h"
#include "YapHeap.h"
#include "heapgc.h"
#include "attvar.h"
#ifndef NULL
#define NULL (void *)0
#endif
#ifdef COROUTINING
/* check if variable was there */
static Term AddVarIfNotThere(Term var , Term dest USES_REGS)
{
Term test = dest;
while (test != TermNil) {
if ((RepPair(test))[0] == var) return(dest);
else test = (RepPair(test))[1];
}
return(MkPairTerm(var,dest));
}
/* This routine verifies whether two complex structures can unify. */
static int can_unify_complex(register CELL *pt0,
register CELL *pt0_end,
register CELL *pt1,
Term *Vars USES_REGS)
{
/* This is really just unification, folks */
tr_fr_ptr saved_TR;
CELL *saved_HB;
choiceptr saved_B;
register CELL **to_visit = (CELL **)Yap_PreAllocCodeSpace();
CELL **to_visit_base = to_visit;
/* make sure to trail all bindings */
saved_TR = TR;
saved_B = B;
saved_HB = HB;
HB = H;
loop:
while (pt0 < pt0_end) {
register CELL d0, d1;
++ pt0;
++ pt1;
d0 = Derefa(pt0);
d1 = Derefa(pt1);
if (IsVarTerm(d0)) {
if (IsVarTerm(d1)) {
if (d0 != d1) {
/* we need to suspend on both variables ! */
*Vars = AddVarIfNotThere(d0, AddVarIfNotThere(d1,*Vars PASS_REGS) PASS_REGS);
/* bind the two variables, we would have to do that to unify
them */
if (d1 > d0) { /* youngest */
/* we don't want to wake up goals */
Bind_Global((CELL *)d1, d0);
} else {
Bind_Global((CELL *)d0, d1);
}
}
/* continue the loop */
continue;
}
else {
/* oh no, some more variables! */
*Vars = AddVarIfNotThere(d0, *Vars PASS_REGS);
}
/* now bind it */
Bind_Global((CELL *)d0, d1);
/* continue the loop */
} else if (IsVarTerm(d1)) {
*Vars = AddVarIfNotThere(d1, *Vars PASS_REGS);
/* and bind it */
Bind_Global((CELL *)d1, d0);
/* continue the loop */
} else {
if (d0 == d1) continue;
if (IsAtomOrIntTerm(d0) || IsAtomOrIntTerm(d1)) {
if (d0 != d1) goto comparison_failed;
/* else continue the loop */
}
else if (IsPairTerm(d0)) {
if (!IsPairTerm(d1)) goto comparison_failed;
#ifdef RATIONAL_TREES
to_visit[0] = pt0;
to_visit[1] = pt0_end;
to_visit[2] = pt1;
to_visit[3] = (CELL *)*pt0;
to_visit += 4;
*pt0 = d1;
#else
/* store the terms to visit */
if (pt0 < pt0_end) {
to_visit[0] = pt0;
to_visit[1] = pt0_end;
to_visit[2] = pt1;
to_visit += 3;
}
#endif
pt0 = RepPair(d0) - 1;
pt0_end = RepPair(d0) + 1;
pt1 = RepPair(d1) - 1;
continue;
}
else if (IsApplTerm(d0)) {
register Functor f;
register CELL *ap2, *ap3;
if (!IsApplTerm(d1)) {
goto comparison_failed;
} else {
/* store the terms to visit */
ap2 = RepAppl(d0);
ap3 = RepAppl(d1);
f = (Functor)(*ap2);
/* compare functors */
if (f != (Functor)*ap3) {
goto comparison_failed;
}
if (IsExtensionFunctor(f)) {
switch((CELL)f) {
case (CELL)FunctorDBRef:
if (d0 == d1) continue;
goto comparison_failed;
case (CELL)FunctorLongInt:
if (ap2[1] == ap3[1]) continue;
goto comparison_failed;
case (CELL)FunctorDouble:
if (FloatOfTerm(d0) == FloatOfTerm(d1)) continue;
goto comparison_failed;
case (CELL)FunctorString:
if (strcmp(StringOfTerm(d0), StringOfTerm(d1)) == 0) continue;
goto comparison_failed;
#ifdef USE_GMP
case (CELL)FunctorBigInt:
if (Yap_gmp_tcmp_big_big(d0,d1) == 0) continue;
goto comparison_failed;
#endif /* USE_GMP */
default:
goto comparison_failed;
}
}
#ifdef RATIONAL_TREES
to_visit[0] = pt0;
to_visit[1] = pt0_end;
to_visit[2] = pt1;
to_visit[3] = (CELL *)*pt0;
to_visit += 4;
*pt0 = d1;
#else
/* store the terms to visit */
if (pt0 < pt0_end) {
to_visit[0] = pt0;
to_visit[1] = pt0_end;
to_visit[2] = pt1;
to_visit += 3;
}
#endif
d0 = ArityOfFunctor(f);
pt0 = ap2;
pt0_end = ap2 + d0;
pt1 = ap3;
continue;
}
}
}
}
/* Do we still have compound terms to visit */
if (to_visit > (CELL **)to_visit_base) {
#ifdef RATIONAL_TREES
to_visit -= 4;
pt0 = to_visit[0];
pt0_end = to_visit[1];
pt1 = to_visit[2];
*pt0 = (CELL)to_visit[3];
#else
to_visit -= 3;
pt0 = to_visit[0];
pt0_end = to_visit[1];
pt1 = to_visit[2];
#endif
goto loop;
}
/* success */
Yap_ReleasePreAllocCodeSpace((ADDR)to_visit);
/* restore B, and later HB */
B = saved_B;
HB = saved_HB;
/* untrail all bindings made by IUnify */
while (TR != saved_TR) {
pt1 = (CELL *)(TrailTerm(--TR));
RESET_VARIABLE(pt1);
}
return(TRUE);
comparison_failed:
/* failure */
Yap_ReleasePreAllocCodeSpace((ADDR)to_visit);
#ifdef RATIONAL_TREES
while (to_visit > (CELL **)to_visit_base) {
to_visit -= 4;
pt0 = to_visit[0];
pt0_end = to_visit[1];
pt1 = to_visit[2];
*pt0 = (CELL)to_visit[3];
}
#endif
/* restore B, and later HB */
B = saved_B;
HB = saved_HB;
/* the system will take care of TR for me, no need to worry here! */
return(FALSE);
}
static int
can_unify(Term t1, Term t2, Term *Vars USES_REGS)
{
t1 = Deref(t1);
t2 = Deref(t2);
if (t1 == t2) {
*Vars = TermNil;
return TRUE;
}
if (IsVarTerm(t1)) {
/* we know for sure they can't be different */
if (IsVarTerm(t2)) {
/* we need to suspend on both variables because otherwise
Y = susp(_) would not wakeup susp ! */
*Vars = MkPairTerm(t1,MkPairTerm(t2,TermNil));
return TRUE;
} else {
*Vars = MkPairTerm(t1,TermNil);
return TRUE;
}
} else if (IsVarTerm(t2)) {
/* wait until t2 is bound */
*Vars = MkPairTerm(t2,TermNil);
return TRUE;
}
/* Two standard terms at last! */
if (IsAtomOrIntTerm(t1) || IsAtomOrIntTerm(t2)) {
/* Two primitive terms can only be equal if they are
the same. If they are, $eq succeeds without further ado.
*/
if (t1 != t2)
return FALSE;
else {
*Vars = TermNil;
return TRUE;
}
} else if (IsPairTerm(t1)) {
if (IsPairTerm(t2)) {
return(can_unify_complex(RepPair(t1)-1, RepPair(t1)+1,
RepPair(t2)-1, Vars PASS_REGS));
} else return FALSE;
} else {
Functor f = FunctorOfTerm(t1);
if (f != FunctorOfTerm(t2))
return FALSE;
if (IsExtensionFunctor(f)) {
switch((CELL)f) {
case (CELL)FunctorDBRef:
if (t1 == t2) return FALSE;
return FALSE;
case (CELL)FunctorLongInt:
if (RepAppl(t1)[1] == RepAppl(t2)[1]) return(TRUE);
return FALSE;
case (CELL)FunctorString:
if (strcmp(StringOfTerm(t1), StringOfTerm(t2)) == 0) return(TRUE);
return FALSE;
case (CELL)FunctorDouble:
if (FloatOfTerm(t1) == FloatOfTerm(t2)) return(TRUE);
return FALSE;
#ifdef USE_GMP
case (CELL)FunctorBigInt:
if (Yap_gmp_tcmp_big_big(t1,t2) == 0) return(TRUE);
return(FALSE);
#endif /* USE_GMP */
default:
return FALSE;
}
}
/* Two complex terms with the same functor */
return can_unify_complex(RepAppl(t1),
RepAppl(t1)+ArityOfFunctor(f),
RepAppl(t2), Vars PASS_REGS);
}
}
/* This routine verifies whether a complex has variables. */
static int non_ground_complex(register CELL *pt0,
register CELL *pt0_end,
Term *Var USES_REGS)
{
register CELL **to_visit = (CELL **)Yap_PreAllocCodeSpace();
CELL **to_visit_base = to_visit;
loop:
while (pt0 < pt0_end) {
register CELL d0;
++ pt0;
d0 = Derefa(pt0);
if (IsVarTerm(d0)) {
*Var = d0;
goto var_found;
}
if (IsPairTerm(d0)) {
if (to_visit + 1024 >= (CELL **)AuxSp) {
goto aux_overflow;
}
#ifdef RATIONAL_TREES
to_visit[0] = pt0;
to_visit[1] = pt0_end;
to_visit[2] = (CELL *)*pt0;
to_visit += 3;
*pt0 = TermNil;
#else
/* store the terms to visit */
if (pt0 < pt0_end) {
to_visit[0] = pt0;
to_visit[1] = pt0_end;
to_visit += 2;
}
#endif
pt0 = RepPair(d0) - 1;
pt0_end = RepPair(d0) + 1;
}
else if (IsApplTerm(d0)) {
register Functor f;
register CELL *ap2;
/* store the terms to visit */
ap2 = RepAppl(d0);
f = (Functor)(*ap2);
if (IsExtensionFunctor(f)) {
continue;
}
if (to_visit + 1024 >= (CELL **)AuxSp) {
goto aux_overflow;
}
#ifdef RATIONAL_TREES
to_visit[0] = pt0;
to_visit[1] = pt0_end;
to_visit[2] = (CELL *)*pt0;
to_visit += 3;
*pt0 = TermNil;
#else
/* store the terms to visit */
if (pt0 < pt0_end) {
to_visit[0] = pt0;
to_visit[1] = pt0_end;
to_visit += 2;
}
#endif
d0 = ArityOfFunctor(f);
pt0 = ap2;
pt0_end = ap2 + d0;
}
/* just continue the loop */
}
/* Do we still have compound terms to visit */
if (to_visit > (CELL **)to_visit_base) {
#ifdef RATIONAL_TREES
to_visit -= 3;
pt0 = to_visit[0];
pt0_end = to_visit[1];
*pt0 = (CELL)to_visit[2];
#else
to_visit -= 2;
pt0 = to_visit[0];
pt0_end = to_visit[1];
#endif
goto loop;
}
/* the term is ground */
Yap_ReleasePreAllocCodeSpace((ADDR)to_visit);
return FALSE;
var_found:
/* the term is non-ground */
Yap_ReleasePreAllocCodeSpace((ADDR)to_visit);
#ifdef RATIONAL_TREES
while (to_visit > (CELL **)to_visit_base) {
to_visit -= 3;
pt0 = to_visit[0];
pt0_end = to_visit[1];
*pt0 = (CELL)to_visit[2];
}
#endif
/* the system will take care of TR for me, no need to worry here! */
return TRUE;
aux_overflow:
/* unwind stack */
Yap_ReleasePreAllocCodeSpace((ADDR)to_visit);
#ifdef RATIONAL_TREES
while (to_visit > (CELL **)to_visit_base) {
to_visit -= 3;
pt0 = to_visit[0];
*pt0 = (CELL)to_visit[2];
}
#endif
return -1;
}
static int
non_ground(Term t, Term *Var USES_REGS)
{
int out = -1;
while (out < 0) {
t = Deref(t);
if (IsVarTerm(t)) {
/* we found a variable */
*Var = t;
return TRUE;
}
if (IsPrimitiveTerm(t)) {
return FALSE;
} else if (IsPairTerm(t)) {
out = non_ground_complex(RepPair(t)-1, RepPair(t)+1, Var PASS_REGS);
if (out >= 0)
return out;
} else {
Functor f = FunctorOfTerm(t);
if (IsExtensionFunctor(f)) {
return FALSE;
}
out = non_ground_complex(RepAppl(t),
RepAppl(t)+ArityOfFunctor(FunctorOfTerm(t)),
Var PASS_REGS);
if (out >= 0)
return out;
}
if (!Yap_ExpandPreAllocCodeSpace(0, NULL, TRUE)) {
Yap_Error(OUT_OF_AUXSPACE_ERROR, ARG1, "overflow in ground");
return FALSE;
}
}
return FALSE;
}
#endif
/* check whether the two terms unify and return what variables should
be bound before the terms are exactly equal */
static Int p_can_unify( USES_REGS1 )
{
#ifdef COROUTINING
Term r = TermNil;
if (!can_unify(ARG1, ARG2, &r PASS_REGS))
return FALSE;
return Yap_unify(ARG3, r);
#else
return FALSE;
#endif
}
/* if the term is not ground return a variable in the term */
static Int p_non_ground( USES_REGS1 )
{
#ifdef COROUTINING
2008-11-26 09:56:18 +00:00
Term r = TermNil;
if (!non_ground(ARG1, &r PASS_REGS))
return(FALSE);
return (Yap_unify(ARG2, r));
#else
return(FALSE);
#endif
}
/* if the term is not ground return a variable in the term */
static Int p_coroutining( USES_REGS1 )
{
#ifdef COROUTINING
return(TRUE);
#else
return(FALSE);
#endif
}
#if COROUTINING
static Term
ListOfWokenGoals( USES_REGS1 ) {
2011-05-04 10:11:41 +01:00
return Yap_ReadTimedVar(LOCAL_WokenGoals);
}
Term
Yap_ListOfWokenGoals(void) {
CACHE_REGS
return ListOfWokenGoals( PASS_REGS1 );
}
#endif
/* return a list of awoken goals */
static Int p_awoken_goals( USES_REGS1 )
{
#ifdef COROUTINING
2011-05-04 10:11:41 +01:00
Term WGs = Yap_ReadTimedVar(LOCAL_WokenGoals);
if (WGs == TermNil) {
return(FALSE);
}
WGs = ListOfWokenGoals( PASS_REGS1 );
2011-05-04 10:11:41 +01:00
Yap_UpdateTimedVar(LOCAL_WokenGoals, TermNil);
return(Yap_unify(ARG1,WGs));
#else
return(FALSE);
#endif
}
static Int
p_yap_has_rational_trees( USES_REGS1 )
{
#if RATIONAL_TREES
return TRUE;
#else
return FALSE;
#endif
}
static Int
p_yap_has_coroutining( USES_REGS1 )
{
#if COROUTINING
return TRUE;
#else
return FALSE;
#endif
}
void
Yap_InitCoroutPreds( void )
{
#ifdef COROUTINING
Atom at;
PredEntry *pred;
at = AtomWakeUpGoal;
pred = RepPredProp(PredPropByFunc(Yap_MkFunctor(at, 2),0));
WakeUpCode = pred;
#endif
Yap_InitAttVarPreds();
2012-10-19 18:10:48 +01:00
Yap_InitCPred("$yap_has_rational_trees", 0, p_yap_has_rational_trees, SafePredFlag);
Yap_InitCPred("$yap_has_coroutining", 0, p_yap_has_coroutining, SafePredFlag);
Yap_InitCPred("$can_unify", 3, p_can_unify, SafePredFlag);
Yap_InitCPred("$non_ground", 2, p_non_ground, SafePredFlag);
Yap_InitCPred("$coroutining", 0, p_coroutining, SafePredFlag);
Yap_InitCPred("$awoken_goals", 1, p_awoken_goals, SafePredFlag);
}