📄 engine.c
字号:
/*******************************************************/
/* "C" Language Integrated Production System */
/* */
/* CLIPS Version 6.24 05/17/06 */
/* */
/* ENGINE MODULE */
/*******************************************************/
/*************************************************************/
/* Purpose: Provides functionality primarily associated with */
/* the run and focus commands. */
/* */
/* Principal Programmer(s): */
/* Gary D. Riley */
/* */
/* Contributing Programmer(s): */
/* Bebe Ly */
/* Brian L. Donnell */
/* */
/* Revision History: */
/* 6.23: Correction for FalseSymbol/TrueSymbol. DR0859 */
/* */
/* Corrected compilation errors for files */
/* generated by constructs-to-c. DR0861 */
/* */
/* 6.24: Removed DYNAMIC_SALIENCE, INCREMENTAL_RESET, */
/* and LOGICAL_DEPENDENCIES compilation flags. */
/* */
/* Renamed BOOLEAN macro type to intBool. */
/* */
/* Added access functions to the HaltRules flag. */
/* */
/* Added EnvGetNextFocus, EnvGetFocusChanged, and */
/* EnvSetFocusChanged functions. */
/* */
/*************************************************************/
#define _ENGINE_SOURCE_
#include <stdio.h>
#define _STDIO_INCLUDED_
#include <string.h>
#include "setup.h"
#if DEFRULE_CONSTRUCT
#include "agenda.h"
#include "argacces.h"
#include "constant.h"
#include "envrnmnt.h"
#include "factmngr.h"
#include "inscom.h"
#include "memalloc.h"
#include "modulutl.h"
#include "prccode.h"
#include "prcdrfun.h"
#include "proflfun.h"
#include "reteutil.h"
#include "retract.h"
#include "router.h"
#include "ruledlt.h"
#include "sysdep.h"
#include "utility.h"
#include "watch.h"
#include "engine.h"
/***************************************/
/* LOCAL INTERNAL FUNCTION DEFINITIONS */
/***************************************/
static struct activation *NextActivationToFire(void *);
static struct defmodule *RemoveFocus(void *,struct defmodule *);
static void DeallocateEngineData(void *);
/*****************************************************************************/
/* InitializeEngine: Initializes the activations and statistics watch items. */
/*****************************************************************************/
globle void InitializeEngine(
void *theEnv)
{
AllocateEnvironmentData(theEnv,ENGINE_DATA,sizeof(struct engineData),DeallocateEngineData);
EngineData(theEnv)->IncrementalResetFlag = TRUE;
#if DEBUGGING_FUNCTIONS
AddWatchItem(theEnv,"statistics",0,&EngineData(theEnv)->WatchStatistics,20,NULL,NULL);
AddWatchItem(theEnv,"focus",0,&EngineData(theEnv)->WatchFocus,0,NULL,NULL);
#endif
}
/*************************************************/
/* DeallocateEngineData: Deallocates environment */
/* data for engine functionality. */
/*************************************************/
static void DeallocateEngineData(
void *theEnv)
{
struct focus *tmpPtr, *nextPtr;
DeallocateCallList(theEnv,EngineData(theEnv)->ListOfRunFunctions);
tmpPtr = EngineData(theEnv)->CurrentFocus;
while (tmpPtr != NULL)
{
nextPtr = tmpPtr->next;
rtn_struct(theEnv,focus,tmpPtr);
tmpPtr = nextPtr;
}
}
/*************************************************/
/* EnvRun: C access routine for the run command. */
/*************************************************/
globle long int EnvRun(
void *theEnv,
long int runLimit)
{
long int rulesFired = 0;
DATA_OBJECT result;
struct callFunctionItem *theRunFunction;
#if DEBUGGING_FUNCTIONS
unsigned long maxActivations = 0, sumActivations = 0;
#if DEFTEMPLATE_CONSTRUCT
unsigned long maxFacts = 0, sumFacts = 0;
#endif
#if OBJECT_SYSTEM
unsigned long maxInstances = 0, sumInstances = 0;
#endif
double endTime, startTime = 0.0;
unsigned long tempValue;
#endif
unsigned int i;
struct patternEntity *theMatchingItem;
struct partialMatch *theBasis;
ACTIVATION *theActivation;
char *ruleFiring;
#if PROFILING_FUNCTIONS
struct profileFrameInfo profileFrame;
#endif
/*=====================================================*/
/* Make sure the run command is not already executing. */
/*=====================================================*/
if (EngineData(theEnv)->AlreadyRunning) return(0);
EngineData(theEnv)->AlreadyRunning = TRUE;
/*================================*/
/* Set up statistics information. */
/*================================*/
#if DEBUGGING_FUNCTIONS
if (EngineData(theEnv)->WatchStatistics)
{
#if DEFTEMPLATE_CONSTRUCT
maxFacts = GetNumberOfFacts(theEnv);
sumFacts = maxFacts;
#endif
#if OBJECT_SYSTEM
maxInstances = GetGlobalNumberOfInstances(theEnv);
sumInstances = maxInstances;
#endif
maxActivations = GetNumberOfActivations(theEnv);
sumActivations = maxActivations;
startTime = gentime();
}
#endif
/*=============================*/
/* Set up execution variables. */
/*=============================*/
if (EvaluationData(theEnv)->CurrentEvaluationDepth == 0) SetHaltExecution(theEnv,FALSE);
EngineData(theEnv)->HaltRules = FALSE;
/*=====================================================*/
/* Fire rules until the agenda is empty, the run limit */
/* has been reached, or a rule execution error occurs. */
/*=====================================================*/
theActivation = NextActivationToFire(theEnv);
while ((theActivation != NULL) &&
(runLimit != 0) &&
(EvaluationData(theEnv)->HaltExecution == FALSE) &&
(EngineData(theEnv)->HaltRules == FALSE))
{
/*===========================================*/
/* Detach the activation from the agenda and */
/* determine which rule is firing. */
/*===========================================*/
DetachActivation(theEnv,theActivation);
ruleFiring = EnvGetActivationName(theEnv,theActivation);
theBasis = (struct partialMatch *) GetActivationBasis(theActivation);
EngineData(theEnv)->ExecutingRule = (struct defrule *) GetActivationRule(theActivation);
/*=============================================*/
/* Update the number of rules that have fired. */
/*=============================================*/
rulesFired++;
if (runLimit > 0) { runLimit--; }
/*==================================*/
/* If rules are being watched, then */
/* print an information message. */
/*==================================*/
#if DEBUGGING_FUNCTIONS
if (EngineData(theEnv)->ExecutingRule->watchFiring)
{
char printSpace[60];
sprintf(printSpace,"FIRE %4ld ",rulesFired);
EnvPrintRouter(theEnv,WTRACE,printSpace);
EnvPrintRouter(theEnv,WTRACE,ruleFiring);
EnvPrintRouter(theEnv,WTRACE,": ");
PrintPartialMatch(theEnv,WTRACE,theBasis);
EnvPrintRouter(theEnv,WTRACE,"\n");
}
#endif
/*=================================================*/
/* Remove the link between the activation and the */
/* completed match for the rule. Set the busy flag */
/* for the completed match to TRUE (so the match */
/* upon which our RHS variables are dependent is */
/* not deleted while our rule is firing). Set up */
/* the global pointers to the completed match for */
/* routines which do variable extractions. */
/*=================================================*/
theBasis->binds[theBasis->bcount].gm.theValue = NULL;
theBasis->busy = TRUE;
EngineData(theEnv)->GlobalLHSBinds = theBasis;
EngineData(theEnv)->GlobalRHSBinds = NULL;
/*===================================================================*/
/* Increment the count for each of the facts/objects associated with */
/* the rule activation so that the facts/objects cannot be deleted */
/* by garbage collection while the rule is executing. */
/*===================================================================*/
for (i = 0; i < theBasis->bcount; i++)
{
theMatchingItem = theBasis->binds[i].gm.theMatch->matchingItem;
if (theMatchingItem != NULL)
{ (*theMatchingItem->theInfo->incrementBasisCount)(theEnv,theMatchingItem); }
}
/*====================================================*/
/* Execute the rule's right hand side actions. If the */
/* rule has logical CEs, set up the pointer to the */
/* rules logical join so the assert command will */
/* attach the appropriate dependencies to the facts. */
/*====================================================*/
EngineData(theEnv)->TheLogicalJoin = EngineData(theEnv)->ExecutingRule->logicalJoin;
EvaluationData(theEnv)->CurrentEvaluationDepth++;
SetEvaluationError(theEnv,FALSE);
EngineData(theEnv)->ExecutingRule->executing = TRUE;
#if PROFILING_FUNCTIONS
StartProfile(theEnv,&profileFrame,
&EngineData(theEnv)->ExecutingRule->header.usrData,
ProfileFunctionData(theEnv)->ProfileConstructs);
#endif
EvaluateProcActions(theEnv,EngineData(theEnv)->ExecutingRule->header.whichModule->theModule,
EngineData(theEnv)->ExecutingRule->actions,EngineData(theEnv)->ExecutingRule->localVarCnt,
&result,NULL);
#if PROFILING_FUNCTIONS
EndProfile(theEnv,&profileFrame);
#endif
EngineData(theEnv)->ExecutingRule->executing = FALSE;
SetEvaluationError(theEnv,FALSE);
EvaluationData(theEnv)->CurrentEvaluationDepth--;
EngineData(theEnv)->TheLogicalJoin = NULL;
/*=====================================================*/
/* If rule execution was halted, then print a message. */
/*=====================================================*/
#if DEBUGGING_FUNCTIONS
if ((EvaluationData(theEnv)->HaltExecution) || (EngineData(theEnv)->HaltRules && EngineData(theEnv)->ExecutingRule->watchFiring))
#else
if ((EvaluationData(theEnv)->HaltExecution) || (EngineData(theEnv)->HaltRules))
#endif
{
PrintErrorID(theEnv,"PRCCODE",4,FALSE);
EnvPrintRouter(theEnv,WERROR,"Execution halted during the actions of defrule ");
EnvPrintRouter(theEnv,WERROR,ruleFiring);
EnvPrintRouter(theEnv,WERROR,".\n");
}
/*===================================================================*/
/* Decrement the count for each of the facts/objects associated with */
/* the rule activation. If the last match for the activation */
/* is from a not CE, then we need to make sure that the last */
/* match is an actual match for the CE and not a counter. */
/*===================================================================*/
theBasis->busy = FALSE;
for (i = 0; i < (theBasis->bcount - 1); i++)
{
theMatchingItem = theBasis->binds[i].gm.theMatch->matchingItem;
if (theMatchingItem != NULL)
{ (*theMatchingItem->theInfo->decrementBasisCount)(theEnv,theMatchingItem); }
}
i = (unsigned) (theBasis->bcount - 1);
if (theBasis->counterf == FALSE)
{
theMatchingItem = theBasis->binds[i].gm.theMatch->matchingItem;
if (theMatchingItem != NULL)
{ (*theMatchingItem->theInfo->decrementBasisCount)(theEnv,theMatchingItem); }
}
/*========================================*/
/* Return the agenda node to free memory. */
/*========================================*/
RemoveActivation(theEnv,theActivation,FALSE,FALSE);
/*======================================*/
/* Get rid of partial matches discarded */
/* while executing the rule's RHS. */
/*======================================*/
FlushGarbagePartialMatches(theEnv);
/*==================================*/
/* Get rid of other garbage created */
/* while executing the rule's RHS. */
/*==================================*/
PeriodicCleanup(theEnv,FALSE,TRUE);
/*==========================*/
/* Keep up with statistics. */
/*==========================*/
#if DEBUGGING_FUNCTIONS
if (EngineData(theEnv)->WatchStatistics)
{
#if DEFTEMPLATE_CONSTRUCT
tempValue = GetNumberOfFacts(theEnv);
if (tempValue > maxFacts) maxFacts = tempValue;
sumFacts += tempValue;
#endif
#if OBJECT_SYSTEM
tempValue = GetGlobalNumberOfInstances(theEnv);
if (tempValue > maxInstances) maxInstances = tempValue;
sumInstances += tempValue;
#endif
tempValue = GetNumberOfActivations(theEnv);
if (tempValue > maxActivations) maxActivations = tempValue;
sumActivations += tempValue;
}
#endif
/*==================================*/
/* Update saliences if appropriate. */
/*==================================*/
if (EnvGetSalienceEvaluation(theEnv) == EVERY_CYCLE) EnvRefreshAgenda(theEnv,NULL);
/*========================================*/
/* Execute the list of functions that are */
/* to be called after each rule firing. */
/*========================================*/
for (theRunFunction = EngineData(theEnv)->ListOfRunFunctions;
theRunFunction != NULL;
theRunFunction = theRunFunction->next)
{
if (theRunFunction->environmentAware)
{ (*theRunFunction->func)(theEnv); }
else
{ ((void (*)(void))(*theRunFunction->func))(); }
}
/*========================================*/
/* If a return was issued on the RHS of a */
/* rule, then remove *that* rule's module */
/* from the focus stack */
/*========================================*/
if (ProcedureFunctionData(theEnv)->ReturnFlag == TRUE)
{ RemoveFocus(theEnv,EngineData(theEnv)->ExecutingRule->header.whichModule->theModule); }
ProcedureFunctionData(theEnv)->ReturnFlag = FALSE;
/*========================================*/
/* Determine the next activation to fire. */
/*========================================*/
theActivation = (struct activation *) NextActivationToFire(theEnv);
/*==============================*/
/* Check for a rule breakpoint. */
/*==============================*/
if (theActivation != NULL)
{
if (((struct defrule *) GetActivationRule(theActivation))->afterBreakpoint)
{
EngineData(theEnv)->HaltRules = TRUE;
EnvPrintRouter(theEnv,WDIALOG,"Breaking on rule ");
EnvPrintRouter(theEnv,WDIALOG,EnvGetActivationName(theEnv,theActivation));
EnvPrintRouter(theEnv,WDIALOG,".\n");
}
}
}
/*=====================================================*/
/* Make sure run functions are executed at least once. */
/*=====================================================*/
if (rulesFired == 0)
{
for (theRunFunction = EngineData(theEnv)->ListOfRunFunctions;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -