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