📄 drive.c
字号:
/*******************************************************/
/* "C" Language Integrated Production System */
/* */
/* CLIPS Version 6.24 05/17/06 */
/* */
/* DRIVE MODULE */
/*******************************************************/
/*************************************************************/
/* Purpose: Handles join network activity associated with */
/* with the addition of a data entity such as a fact or */
/* instance. */
/* */
/* Principal Programmer(s): */
/* Gary D. Riley */
/* */
/* Contributing Programmer(s): */
/* */
/* Revision History: */
/* 6.23: Correction for FalseSymbol/TrueSymbol. DR0859 */
/* */
/* 6.24: Removed INCREMENTAL_RESET and */
/* LOGICAL_DEPENDENCIES compilation flags. */
/* */
/* Renamed BOOLEAN macro type to intBool. */
/* */
/* Rule with exists CE has incorrect activation. */
/* DR0867 */
/* */
/*************************************************************/
#define _DRIVE_SOURCE_
#include <stdio.h>
#define _STDIO_INCLUDED_
#include <stdlib.h>
#include "setup.h"
#if DEFRULE_CONSTRUCT
#include "agenda.h"
#include "constant.h"
#include "engine.h"
#include "envrnmnt.h"
#include "memalloc.h"
#include "prntutil.h"
#include "reteutil.h"
#include "retract.h"
#include "router.h"
#include "lgcldpnd.h"
#include "incrrset.h"
#include "drive.h"
/***************************************/
/* LOCAL INTERNAL FUNCTION DEFINITIONS */
/***************************************/
static void PPDrive(void *,struct partialMatch *,struct partialMatch *,struct joinNode *);
static void PNRDrive(void *,struct joinNode *,struct partialMatch *,
struct partialMatch *);
static void EmptyDrive(void *,struct joinNode *,struct partialMatch *);
static void JoinNetErrorMessage(void *,struct joinNode *);
/************************************************/
/* NetworkAssert: Primary routine for filtering */
/* a partial match through the join network. */
/************************************************/
globle void NetworkAssert(
void *theEnv,
struct partialMatch *binds,
struct joinNode *join,
int enterDirection)
{
struct partialMatch *lhsBinds = NULL, *rhsBinds = NULL;
struct partialMatch *comparePMs = NULL, *newBinds;
int exprResult;
/*=========================================================*/
/* If an incremental reset is being performed and the join */
/* is not part of the network to be reset, then return. */
/*=========================================================*/
#if (! BLOAD_ONLY) && (! RUN_TIME)
if (EngineData(theEnv)->IncrementalResetInProgress && (join->initialize == FALSE)) return;
#endif
/*=========================================================*/
/* If the associated LHS pattern is a not CE or the join */
/* is a nand join, then we need an additional field in the */
/* partial match to keep track of the pseudo fact if one */
/* is created. The partial match is automatically stored */
/* in the beta memory and the counterf slot is used to */
/* determine if it is an actual partial match. If counterf */
/* is TRUE, there are one or more fact or instances */
/* keeping the not or nand join from being satisfied. */
/*=========================================================*/
if ((enterDirection == LHS) &&
((join->patternIsNegated) || (join->joinFromTheRight)))
{
newBinds = AddSingleMatch(theEnv,binds,NULL,
(join->ruleToActivate == NULL) ? 0 : 1,
(int) join->logicalJoin);
newBinds->notOriginf = TRUE;
newBinds->counterf = TRUE;
binds = newBinds;
binds->next = join->beta;
join->beta = binds;
}
/*==================================================*/
/* Use a special routine if this is the first join. */
/*==================================================*/
if (join->firstJoin)
{
EmptyDrive(theEnv,join,binds);
return;
}
/*==================================================*/
/* Initialize some variables used to indicate which */
/* side is being compared to the new partial match. */
/*==================================================*/
if (enterDirection == LHS)
{
if (join->joinFromTheRight)
{ comparePMs = ((struct joinNode *) join->rightSideEntryStructure)->beta;}
else
{ comparePMs = ((struct patternNodeHeader *) join->rightSideEntryStructure)->alphaMemory; }
lhsBinds = binds;
}
else if (enterDirection == RHS)
{
if (join->patternIsNegated || join->joinFromTheRight)
{ comparePMs = join->beta; }
else
{ comparePMs = join->lastLevel->beta; }
rhsBinds = binds;
}
else
{
SystemError(theEnv,"DRIVE",1);
EnvExitRouter(theEnv,EXIT_FAILURE);
}
/*===================================================*/
/* Compare each set of binds on the opposite side of */
/* the join with the set of binds that entered this */
/* join. If the binds don't mismatch, then perform */
/* the appropriate action for the logic of the join. */
/*===================================================*/
while (comparePMs != NULL)
{
/*===========================================================*/
/* Initialize some variables pointing to the partial matches */
/* in the LHS and RHS of the join. In addition, check for */
/* certain conditions under which the partial match can be */
/* skipped since it's not a "real" partial match. */
/*===========================================================*/
if (enterDirection == RHS)
{
lhsBinds = comparePMs;
/*=====================================================*/
/* The partial matches entering from the LHS of a join */
/* are stored in the beta memory of the previous join */
/* (unless the current join is a join from the right */
/* or is attached to a not CE). If the previous join */
/* is a join from the right or associated with a not */
/* CE, then some of its partial matches in its beta */
/* memory will not be "real" partial matches. That is, */
/* there may be a partial match in the alpha memory */
/* that prevents the partial match from satisfying the */
/* join's conditions. If this is the case, then the */
/* counterf flag in the partial match will be set to */
/* TRUE and in this case, we move on to the next */
/* partial match to be checked. */
/*=====================================================*/
if (lhsBinds->counterf &&
(join->patternIsNegated == FALSE) &&
(join->joinFromTheRight == FALSE))
{
comparePMs = comparePMs->next;
continue;
}
/*==================================================*/
/* If the join is associated with a not CE or has a */
/* join from the right, then the LHS partial match */
/* currently being checked may already have a */
/* partial match from the alpha memory preventing */
/* it from being satisfied. If this is the case, */
/* then move on to the next partial match in the */
/* beta memory of the join. */
/*==================================================*/
if ((join->patternIsNegated || join->joinFromTheRight) &&
(lhsBinds->counterf))
{
comparePMs = comparePMs->next;
continue;
}
}
else
{ rhsBinds = comparePMs; }
/*========================================================*/
/* If the join has no expression associated with it, then */
/* the new partial match derived from the LHS and RHS */
/* partial matches is valid. In the event that the join */
/* is a join from the right, it must also be checked that */
/* the RHS partial match is the same partial match that */
/* the LHS partial match was generated from. Each LHS */
/* partial match in a join from the right corresponds */
/* uniquely to a partial match from the RHS of the join. */
/* To determine whether the LHS partial match is the one */
/* associated with the RHS partial match, we compare the */
/* the entity addresses found in the partial matches to */
/* make sure they're equal. */
/*========================================================*/
if (join->networkTest == NULL)
{
exprResult = TRUE;
if (join->joinFromTheRight)
{
int i;
for (i = 0; i < (int) (lhsBinds->bcount - 1); i++)
{
if (lhsBinds->binds[i].gm.theMatch != rhsBinds->binds[i].gm.theMatch)
{
exprResult = FALSE;
break;
}
}
}
}
/*=========================================================*/
/* If the join has an expression associated with it, then */
/* evaluate the expression to determine if the new partial */
/* match derived from the LHS and RHS partial matches is */
/* valid (i.e. variable bindings are consistent and */
/* predicate expressions evaluate to TRUE). */
/*=========================================================*/
else
{
exprResult = EvaluateJoinExpression(theEnv,join->networkTest,lhsBinds,rhsBinds,join);
if (EvaluationData(theEnv)->EvaluationError)
{
if (join->patternIsNegated) exprResult = TRUE;
SetEvaluationError(theEnv,FALSE);
}
}
/*====================================================*/
/* If the join expression evaluated to TRUE (i.e. */
/* there were no conflicts between variable bindings, */
/* all tests were satisfied, etc.), then perform the */
/* appropriate action given the logic of this join. */
/*====================================================*/
if (exprResult != FALSE)
{
/*==============================================*/
/* Use the PPDrive routine when the join isn't */
/* associated with a not CE and it doesn't have */
/* a join from the right. */
/*==============================================*/
if ((join->patternIsNegated == FALSE) &&
(join->joinFromTheRight == FALSE))
{ PPDrive(theEnv,lhsBinds,rhsBinds,join); }
/*=====================================================*/
/* Use the PNRDrive routine when the new partial match */
/* enters from the RHS of the join and the join either */
/* is associated with a not CE or has a join from the */
/* right. */
/*=====================================================*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -