1 /*******************************************************/
2 /* "C" Language Integrated Production System */
3 /* */
4 /* CLIPS Version 6.30 01/25/15 */
5 /* */
6 /* DEFRULE MODULE */
7 /*******************************************************/
8
9 /*************************************************************/
10 /* Purpose: Defines basic defrule primitive functions such */
11 /* as allocating and deallocating, traversing, and finding */
12 /* defrule data structures. */
13 /* */
14 /* Principal Programmer(s): */
15 /* Gary D. Riley */
16 /* */
17 /* Contributing Programmer(s): */
18 /* Brian L. Dantes */
19 /* */
20 /* Revision History: */
21 /* */
22 /* 6.24: Removed DYNAMIC_SALIENCE and */
23 /* LOGICAL_DEPENDENCIES compilation flags. */
24 /* */
25 /* Removed CONFLICT_RESOLUTION_STRATEGIES */
26 /* compilation flag. */
27 /* */
28 /* Renamed BOOLEAN macro type to intBool. */
29 /* */
30 /* Corrected code to remove run-time program */
31 /* compiler warnings. */
32 /* */
33 /* 6.30: Removed conditional code for unsupported */
34 /* compilers/operating systems (IBM_MCW, */
35 /* MAC_MCW, and IBM_TBC). */
36 /* */
37 /* Added support for hashed memories. */
38 /* */
39 /* Added additional developer statistics to help */
40 /* analyze join network performance. */
41 /* */
42 /* Added salience groups to improve performance */
43 /* with large numbers of activations of different */
44 /* saliences. */
45 /* */
46 /* Added EnvGetDisjunctCount and */
47 /* EnvGetNthDisjunct functions. */
48 /* */
49 /* Added const qualifiers to remove C++ */
50 /* deprecation warnings. */
51 /* */
52 /* Converted API macros to function calls. */
53 /* */
54 /* Changed find construct functionality so that */
55 /* imported modules are search when locating a */
56 /* named construct. */
57 /* */
58 /*************************************************************/
59
60 #define _RULEDEF_SOURCE_
61
62 #include "setup.h"
63
64 #if DEFRULE_CONSTRUCT
65
66 #include <stdio.h>
67 #define _STDIO_INCLUDED_
68
69 #include "agenda.h"
70 #include "drive.h"
71 #include "engine.h"
72 #include "envrnmnt.h"
73 #include "memalloc.h"
74 #include "pattern.h"
75 #include "retract.h"
76 #include "reteutil.h"
77 #include "rulebsc.h"
78 #include "rulecom.h"
79 #include "rulepsr.h"
80 #include "ruledlt.h"
81
82 #if BLOAD || BLOAD_AND_BSAVE || BLOAD_ONLY
83 #include "bload.h"
84 #include "rulebin.h"
85 #endif
86
87 #if CONSTRUCT_COMPILER && (! RUN_TIME)
88 #include "rulecmp.h"
89 #endif
90
91 #include "ruledef.h"
92
93 /***************************************/
94 /* LOCAL INTERNAL FUNCTION DEFINITIONS */
95 /***************************************/
96
97 static void *AllocateModule(void *);
98 static void ReturnModule(void *,void *);
99 static void InitializeDefruleModules(void *);
100 static void DeallocateDefruleData(void *);
101 static void DestroyDefruleAction(void *,struct constructHeader *,void *);
102 #if RUN_TIME
103 static void AddBetaMemoriesToRule(void *,struct joinNode *);
104 #endif
105
106 /**********************************************************/
107 /* InitializeDefrules: Initializes the defrule construct. */
108 /**********************************************************/
InitializeDefrules(void * theEnv)109 globle void InitializeDefrules(
110 void *theEnv)
111 {
112 unsigned long i;
113 AllocateEnvironmentData(theEnv,DEFRULE_DATA,sizeof(struct defruleData),DeallocateDefruleData);
114
115 InitializeEngine(theEnv);
116 InitializeAgenda(theEnv);
117 InitializePatterns(theEnv);
118 InitializeDefruleModules(theEnv);
119
120 AddReservedPatternSymbol(theEnv,"and",NULL);
121 AddReservedPatternSymbol(theEnv,"not",NULL);
122 AddReservedPatternSymbol(theEnv,"or",NULL);
123 AddReservedPatternSymbol(theEnv,"test",NULL);
124 AddReservedPatternSymbol(theEnv,"logical",NULL);
125 AddReservedPatternSymbol(theEnv,"exists",NULL);
126 AddReservedPatternSymbol(theEnv,"forall",NULL);
127
128 DefruleBasicCommands(theEnv);
129
130 DefruleCommands(theEnv);
131
132 DefruleData(theEnv)->DefruleConstruct =
133 AddConstruct(theEnv,"defrule","defrules",
134 ParseDefrule,EnvFindDefrule,
135 GetConstructNamePointer,GetConstructPPForm,
136 GetConstructModuleItem,EnvGetNextDefrule,SetNextConstruct,
137 EnvIsDefruleDeletable,EnvUndefrule,ReturnDefrule);
138
139 DefruleData(theEnv)->AlphaMemoryTable = (ALPHA_MEMORY_HASH **)
140 gm3(theEnv,sizeof (ALPHA_MEMORY_HASH *) * ALPHA_MEMORY_HASH_SIZE);
141
142 for (i = 0; i < ALPHA_MEMORY_HASH_SIZE; i++) DefruleData(theEnv)->AlphaMemoryTable[i] = NULL;
143
144 DefruleData(theEnv)->BetaMemoryResizingFlag = TRUE;
145
146 DefruleData(theEnv)->RightPrimeJoins = NULL;
147 DefruleData(theEnv)->LeftPrimeJoins = NULL;
148 }
149
150 /**************************************************/
151 /* DeallocateDefruleData: Deallocates environment */
152 /* data for the defrule construct. */
153 /**************************************************/
DeallocateDefruleData(void * theEnv)154 static void DeallocateDefruleData(
155 void *theEnv)
156 {
157 struct defruleModule *theModuleItem;
158 void *theModule;
159 struct activation *theActivation, *tmpActivation;
160 struct salienceGroup *theGroup, *tmpGroup;
161
162 #if BLOAD || BLOAD_AND_BSAVE
163 if (Bloaded(theEnv))
164 { return; }
165 #endif
166
167 DoForAllConstructs(theEnv,DestroyDefruleAction,DefruleData(theEnv)->DefruleModuleIndex,FALSE,NULL);
168
169 for (theModule = EnvGetNextDefmodule(theEnv,NULL);
170 theModule != NULL;
171 theModule = EnvGetNextDefmodule(theEnv,theModule))
172 {
173 theModuleItem = (struct defruleModule *)
174 GetModuleItem(theEnv,(struct defmodule *) theModule,
175 DefruleData(theEnv)->DefruleModuleIndex);
176
177 theActivation = theModuleItem->agenda;
178 while (theActivation != NULL)
179 {
180 tmpActivation = theActivation->next;
181
182 rtn_struct(theEnv,activation,theActivation);
183
184 theActivation = tmpActivation;
185 }
186
187 theGroup = theModuleItem->groupings;
188 while (theGroup != NULL)
189 {
190 tmpGroup = theGroup->next;
191
192 rtn_struct(theEnv,salienceGroup,theGroup);
193
194 theGroup = tmpGroup;
195 }
196
197 #if ! RUN_TIME
198 rtn_struct(theEnv,defruleModule,theModuleItem);
199 #endif
200 }
201
202 rm3(theEnv,DefruleData(theEnv)->AlphaMemoryTable,sizeof (ALPHA_MEMORY_HASH *) * ALPHA_MEMORY_HASH_SIZE);
203 }
204
205 /********************************************************/
206 /* DestroyDefruleAction: Action used to remove defrules */
207 /* as a result of DestroyEnvironment. */
208 /********************************************************/
DestroyDefruleAction(void * theEnv,struct constructHeader * theConstruct,void * buffer)209 static void DestroyDefruleAction(
210 void *theEnv,
211 struct constructHeader *theConstruct,
212 void *buffer)
213 {
214 #if MAC_XCD
215 #pragma unused(buffer)
216 #endif
217 struct defrule *theDefrule = (struct defrule *) theConstruct;
218
219 DestroyDefrule(theEnv,theDefrule);
220 }
221
222 /*****************************************************/
223 /* InitializeDefruleModules: Initializes the defrule */
224 /* construct for use with the defmodule construct. */
225 /*****************************************************/
InitializeDefruleModules(void * theEnv)226 static void InitializeDefruleModules(
227 void *theEnv)
228 {
229 DefruleData(theEnv)->DefruleModuleIndex = RegisterModuleItem(theEnv,"defrule",
230 AllocateModule,
231 ReturnModule,
232 #if BLOAD_AND_BSAVE || BLOAD || BLOAD_ONLY
233 BloadDefruleModuleReference,
234 #else
235 NULL,
236 #endif
237 #if CONSTRUCT_COMPILER && (! RUN_TIME)
238 DefruleCModuleReference,
239 #else
240 NULL,
241 #endif
242 EnvFindDefruleInModule);
243 }
244
245 /***********************************************/
246 /* AllocateModule: Allocates a defrule module. */
247 /***********************************************/
AllocateModule(void * theEnv)248 static void *AllocateModule(
249 void *theEnv)
250 {
251 struct defruleModule *theItem;
252
253 theItem = get_struct(theEnv,defruleModule);
254 theItem->agenda = NULL;
255 theItem->groupings = NULL;
256 return((void *) theItem);
257 }
258
259 /*********************************************/
260 /* ReturnModule: Deallocates a defrule module. */
261 /*********************************************/
ReturnModule(void * theEnv,void * theItem)262 static void ReturnModule(
263 void *theEnv,
264 void *theItem)
265 {
266 FreeConstructHeaderModule(theEnv,(struct defmoduleItemHeader *) theItem,DefruleData(theEnv)->DefruleConstruct);
267 rtn_struct(theEnv,defruleModule,theItem);
268 }
269
270 /************************************************************/
271 /* GetDefruleModuleItem: Returns a pointer to the defmodule */
272 /* item for the specified defrule or defmodule. */
273 /************************************************************/
GetDefruleModuleItem(void * theEnv,struct defmodule * theModule)274 globle struct defruleModule *GetDefruleModuleItem(
275 void *theEnv,
276 struct defmodule *theModule)
277 {
278 return((struct defruleModule *) GetConstructModuleItemByIndex(theEnv,theModule,DefruleData(theEnv)->DefruleModuleIndex));
279 }
280
281 /*******************************************************************/
282 /* EnvFindDefrule: Searches for a defrule in the list of defrules. */
283 /* Returns a pointer to the defrule if found, otherwise NULL. */
284 /*******************************************************************/
EnvFindDefrule(void * theEnv,const char * defruleName)285 globle void *EnvFindDefrule(
286 void *theEnv,
287 const char *defruleName)
288 {
289 return(FindNamedConstructInModuleOrImports(theEnv,defruleName,DefruleData(theEnv)->DefruleConstruct));
290 }
291
292 /*******************************************************************/
293 /* EnvFindDefruleInModule: Searches for a defrule in the list of defrules. */
294 /* Returns a pointer to the defrule if found, otherwise NULL. */
295 /*******************************************************************/
EnvFindDefruleInModule(void * theEnv,const char * defruleName)296 globle void *EnvFindDefruleInModule(
297 void *theEnv,
298 const char *defruleName)
299 {
300 return(FindNamedConstructInModule(theEnv,defruleName,DefruleData(theEnv)->DefruleConstruct));
301 }
302
303 /************************************************************/
304 /* EnvGetNextDefrule: If passed a NULL pointer, returns the */
305 /* first defrule in the ListOfDefrules. Otherwise returns */
306 /* the next defrule following the defrule passed as an */
307 /* argument. */
308 /************************************************************/
EnvGetNextDefrule(void * theEnv,void * defrulePtr)309 globle void *EnvGetNextDefrule(
310 void *theEnv,
311 void *defrulePtr)
312 {
313 return((void *) GetNextConstructItem(theEnv,(struct constructHeader *) defrulePtr,DefruleData(theEnv)->DefruleModuleIndex));
314 }
315
316 /*******************************************************/
317 /* EnvIsDefruleDeletable: Returns TRUE if a particular */
318 /* defrule can be deleted, otherwise returns FALSE. */
319 /*******************************************************/
EnvIsDefruleDeletable(void * theEnv,void * vTheDefrule)320 globle intBool EnvIsDefruleDeletable(
321 void *theEnv,
322 void *vTheDefrule)
323 {
324 struct defrule *theDefrule;
325
326 if (! ConstructsDeletable(theEnv))
327 { return FALSE; }
328
329 for (theDefrule = (struct defrule *) vTheDefrule;
330 theDefrule != NULL;
331 theDefrule = theDefrule->disjunct)
332 { if (theDefrule->executing) return(FALSE); }
333
334 if (EngineData(theEnv)->JoinOperationInProgress) return(FALSE);
335
336 return(TRUE);
337 }
338
339 /***********************************************************/
340 /* EnvGetDisjunctCount: Returns the number of disjuncts of */
341 /* a rule (permutations caused by the use of or CEs). */
342 /***********************************************************/
EnvGetDisjunctCount(void * theEnv,void * vTheDefrule)343 globle long EnvGetDisjunctCount(
344 void *theEnv,
345 void *vTheDefrule)
346 {
347 struct defrule *theDefrule;
348 long count = 0;
349
350 for (theDefrule = (struct defrule *) vTheDefrule;
351 theDefrule != NULL;
352 theDefrule = theDefrule->disjunct)
353 { count++; }
354
355 return(count);
356 }
357
358 /**********************************************************/
359 /* EnvGetNthDisjunct: Returns the nth disjunct of a rule. */
360 /* The disjunct indices run from 1 to N rather than 0 */
361 /* to N - 1. */
362 /**********************************************************/
EnvGetNthDisjunct(void * theEnv,void * vTheDefrule,long index)363 globle void *EnvGetNthDisjunct(
364 void *theEnv,
365 void *vTheDefrule,
366 long index)
367 {
368 struct defrule *theDefrule;
369 long count = 0;
370
371 for (theDefrule = (struct defrule *) vTheDefrule;
372 theDefrule != NULL;
373 theDefrule = theDefrule->disjunct)
374 {
375 count++;
376 if (count == index)
377 { return theDefrule; }
378 }
379
380 return(NULL);
381 }
382
383 #if RUN_TIME
384
385 /******************************************/
386 /* DefruleRunTimeInitialize: Initializes */
387 /* defrule in a run-time module. */
388 /******************************************/
DefruleRunTimeInitialize(void * theEnv,struct joinLink * rightPrime,struct joinLink * leftPrime)389 globle void DefruleRunTimeInitialize(
390 void *theEnv,
391 struct joinLink *rightPrime,
392 struct joinLink *leftPrime)
393 {
394 struct defmodule *theModule;
395 struct defrule *theRule, *theDisjunct;
396
397 DefruleData(theEnv)->RightPrimeJoins = rightPrime;
398 DefruleData(theEnv)->LeftPrimeJoins = leftPrime;
399
400 SaveCurrentModule(theEnv);
401
402 for (theModule = (struct defmodule *) EnvGetNextDefmodule(theEnv,NULL);
403 theModule != NULL;
404 theModule = (struct defmodule *) EnvGetNextDefmodule(theEnv,theModule))
405 {
406 EnvSetCurrentModule(theEnv,(void *) theModule);
407 for (theRule = (struct defrule *) EnvGetNextDefrule(theEnv,NULL);
408 theRule != NULL;
409 theRule = (struct defrule *) EnvGetNextDefrule(theEnv,theRule))
410 {
411 for (theDisjunct = theRule;
412 theDisjunct != NULL;
413 theDisjunct = theDisjunct->disjunct)
414 { AddBetaMemoriesToRule(theEnv,theDisjunct->lastJoin); }
415 }
416 }
417
418 RestoreCurrentModule(theEnv);
419 }
420
421
422 /******************************************/
423 /* AddBetaMemoriesToRule: */
424 /******************************************/
AddBetaMemoriesToRule(void * theEnv,struct joinNode * theNode)425 static void AddBetaMemoriesToRule(
426 void *theEnv,
427 struct joinNode *theNode)
428 {
429 AddBetaMemoriesToJoin(theEnv,theNode);
430
431 if (theNode->lastLevel != NULL)
432 { AddBetaMemoriesToRule(theEnv,theNode->lastLevel); }
433
434 if (theNode->joinFromTheRight)
435 { AddBetaMemoriesToRule(theEnv,(struct joinNode *) theNode->rightSideEntryStructure); }
436 }
437
438 #endif /* RUN_TIME */
439
440 #if RUN_TIME || BLOAD_ONLY || BLOAD || BLOAD_AND_BSAVE
441
442 /**************************/
443 /* AddBetaMemoriesToJoin: */
444 /**************************/
AddBetaMemoriesToJoin(void * theEnv,struct joinNode * theNode)445 globle void AddBetaMemoriesToJoin(
446 void *theEnv,
447 struct joinNode *theNode)
448 {
449 if ((theNode->leftMemory != NULL) || (theNode->rightMemory != NULL))
450 { return; }
451
452 if ((! theNode->firstJoin) || theNode->patternIsExists || theNode-> patternIsNegated || theNode->joinFromTheRight)
453 {
454 if (theNode->leftHash == NULL)
455 {
456 theNode->leftMemory = get_struct(theEnv,betaMemory);
457 theNode->leftMemory->beta = (struct partialMatch **) genalloc(theEnv,sizeof(struct partialMatch *));
458 theNode->leftMemory->beta[0] = NULL;
459 theNode->leftMemory->size = 1;
460 theNode->leftMemory->count = 0;
461 theNode->leftMemory->last = NULL;
462 }
463 else
464 {
465 theNode->leftMemory = get_struct(theEnv,betaMemory);
466 theNode->leftMemory->beta = (struct partialMatch **) genalloc(theEnv,sizeof(struct partialMatch *) * INITIAL_BETA_HASH_SIZE);
467 memset(theNode->leftMemory->beta,0,sizeof(struct partialMatch *) * INITIAL_BETA_HASH_SIZE);
468 theNode->leftMemory->size = INITIAL_BETA_HASH_SIZE;
469 theNode->leftMemory->count = 0;
470 theNode->leftMemory->last = NULL;
471 }
472
473 if (theNode->firstJoin && (theNode->patternIsExists || theNode-> patternIsNegated || theNode->joinFromTheRight))
474 {
475 theNode->leftMemory->beta[0] = CreateEmptyPartialMatch(theEnv);
476 theNode->leftMemory->beta[0]->owner = theNode;
477 }
478 }
479 else
480 { theNode->leftMemory = NULL; }
481
482 if (theNode->joinFromTheRight)
483 {
484 if (theNode->leftHash == NULL)
485 {
486 theNode->rightMemory = get_struct(theEnv,betaMemory);
487 theNode->rightMemory->beta = (struct partialMatch **) genalloc(theEnv,sizeof(struct partialMatch *));
488 theNode->rightMemory->last = (struct partialMatch **) genalloc(theEnv,sizeof(struct partialMatch *));
489 theNode->rightMemory->beta[0] = NULL;
490 theNode->rightMemory->last[0] = NULL;
491 theNode->rightMemory->size = 1;
492 theNode->rightMemory->count = 0;
493 }
494 else
495 {
496 theNode->rightMemory = get_struct(theEnv,betaMemory);
497 theNode->rightMemory->beta = (struct partialMatch **) genalloc(theEnv,sizeof(struct partialMatch *) * INITIAL_BETA_HASH_SIZE);
498 theNode->rightMemory->last = (struct partialMatch **) genalloc(theEnv,sizeof(struct partialMatch *) * INITIAL_BETA_HASH_SIZE);
499 memset(theNode->rightMemory->beta,0,sizeof(struct partialMatch **) * INITIAL_BETA_HASH_SIZE);
500 memset(theNode->rightMemory->last,0,sizeof(struct partialMatch **) * INITIAL_BETA_HASH_SIZE);
501 theNode->rightMemory->size = INITIAL_BETA_HASH_SIZE;
502 theNode->rightMemory->count = 0;
503 }
504 }
505 else if (theNode->rightSideEntryStructure == NULL)
506 {
507 theNode->rightMemory = get_struct(theEnv,betaMemory);
508 theNode->rightMemory->beta = (struct partialMatch **) genalloc(theEnv,sizeof(struct partialMatch *));
509 theNode->rightMemory->last = (struct partialMatch **) genalloc(theEnv,sizeof(struct partialMatch *));
510 theNode->rightMemory->beta[0] = CreateEmptyPartialMatch(theEnv);
511 theNode->rightMemory->beta[0]->owner = theNode;
512 theNode->rightMemory->beta[0]->rhsMemory = TRUE;
513 theNode->rightMemory->last[0] = theNode->rightMemory->beta[0];
514 theNode->rightMemory->size = 1;
515 theNode->rightMemory->count = 1;
516 }
517 else
518 { theNode->rightMemory = NULL; }
519 }
520
521 #endif /* RUN_TIME || BLOAD_ONLY || BLOAD || BLOAD_AND_BSAVE */
522
523 /*##################################*/
524 /* Additional Environment Functions */
525 /*##################################*/
526
EnvDefruleModule(void * theEnv,void * theDefrule)527 globle const char *EnvDefruleModule(
528 void *theEnv,
529 void *theDefrule)
530 {
531 return GetConstructModuleName((struct constructHeader *) theDefrule);
532 }
533
EnvGetDefruleName(void * theEnv,void * theDefrule)534 globle const char *EnvGetDefruleName(
535 void *theEnv,
536 void *theDefrule)
537 {
538 return GetConstructNameString((struct constructHeader *) theDefrule);
539 }
540
EnvGetDefrulePPForm(void * theEnv,void * theDefrule)541 globle const char *EnvGetDefrulePPForm(
542 void *theEnv,
543 void *theDefrule)
544 {
545 return GetConstructPPForm(theEnv,(struct constructHeader *) theDefrule);
546 }
547
548 /*#####################################*/
549 /* ALLOW_ENVIRONMENT_GLOBALS Functions */
550 /*#####################################*/
551
552 #if ALLOW_ENVIRONMENT_GLOBALS
553
DefruleModule(void * theDefrule)554 globle const char *DefruleModule(
555 void *theDefrule)
556 {
557 return EnvDefruleModule(GetCurrentEnvironment(),theDefrule);
558 }
559
FindDefrule(const char * defruleName)560 globle void *FindDefrule(
561 const char *defruleName)
562 {
563 return EnvFindDefrule(GetCurrentEnvironment(),defruleName);
564 }
565
GetDefruleName(void * theDefrule)566 globle const char *GetDefruleName(
567 void *theDefrule)
568 {
569 return EnvGetDefruleName(GetCurrentEnvironment(),theDefrule);
570 }
571
GetDefrulePPForm(void * theDefrule)572 globle const char *GetDefrulePPForm(
573 void *theDefrule)
574 {
575 return EnvGetDefrulePPForm(GetCurrentEnvironment(),theDefrule);
576 }
577
GetNextDefrule(void * defrulePtr)578 globle void *GetNextDefrule(
579 void *defrulePtr)
580 {
581 return EnvGetNextDefrule(GetCurrentEnvironment(),defrulePtr);
582 }
583
IsDefruleDeletable(void * vTheDefrule)584 globle intBool IsDefruleDeletable(
585 void *vTheDefrule)
586 {
587 return EnvIsDefruleDeletable(GetCurrentEnvironment(),vTheDefrule);
588 }
589
590 #endif /* ALLOW_ENVIRONMENT_GLOBALS */
591
592 #endif /* DEFRULE_CONSTRUCT */
593
594
595