1    /*******************************************************/
2    /*      "C" Language Integrated Production System      */
3    /*                                                     */
4    /*             CLIPS Version 6.30  08/16/14            */
5    /*                                                     */
6    /*                 RULE DELETION MODULE                */
7    /*******************************************************/
8 
9 /*************************************************************/
10 /* Purpose: Provides routines for deleting a rule including  */
11 /*   freeing the defrule data structures and removing the    */
12 /*   appropriate joins from the join network.                */
13 /*                                                           */
14 /* Principal Programmer(s):                                  */
15 /*      Gary D. Riley                                        */
16 /*                                                           */
17 /* Contributing Programmer(s):                               */
18 /*                                                           */
19 /* Revision History:                                         */
20 /*                                                           */
21 /*      6.24: Removed DYNAMIC_SALIENCE compilation flag.     */
22 /*                                                           */
23 /*            Renamed BOOLEAN macro type to intBool.         */
24 /*                                                           */
25 /*      6.30: Removed conditional code for unsupported       */
26 /*            compilers/operating systems (IBM_MCW and       */
27 /*            MAC_MCW).                                      */
28 /*                                                           */
29 /*            Added support for hashed memories.             */
30 /*                                                           */
31 /*            Fixed linkage issue when BLOAD_ONLY compiler   */
32 /*            flag is set to 1.                              */
33 /*                                                           */
34 /*************************************************************/
35 
36 #define _RULEDLT_SOURCE_
37 
38 #include "setup.h"
39 
40 #if DEFRULE_CONSTRUCT
41 
42 #include <stdio.h>
43 #define _STDIO_INCLUDED_
44 #include <string.h>
45 
46 #include "memalloc.h"
47 #include "engine.h"
48 #include "envrnmnt.h"
49 #include "reteutil.h"
50 #include "pattern.h"
51 #include "agenda.h"
52 #include "drive.h"
53 #include "retract.h"
54 #include "constrct.h"
55 
56 #if BLOAD || BLOAD_ONLY || BLOAD_AND_BSAVE
57 #include "bload.h"
58 #endif
59 
60 #include "ruledlt.h"
61 
62 /***************************************/
63 /* LOCAL INTERNAL FUNCTION DEFINITIONS */
64 /***************************************/
65 
66 #if (! RUN_TIME) && (! BLOAD_ONLY)
67    static void                    RemoveIntranetworkLink(void *,struct joinNode *);
68 #endif
69    static void                    DetachJoins(void *,struct joinNode *,intBool);
70    static void                    DetachJoinsDriver(void *,struct defrule *,intBool);
71 
72 /**********************************************************************/
73 /* ReturnDefrule: Returns a defrule data structure and its associated */
74 /*   data structures to the memory manager. Note that the first       */
75 /*   disjunct of a rule is the only disjunct which allocates storage  */
76 /*   for the rule's dynamic salience and pretty print form (so these  */
77 /*   are only deallocated for the first disjunct).                    */
78 /**********************************************************************/
ReturnDefrule(void * theEnv,void * vWaste)79 globle void ReturnDefrule(
80   void *theEnv,
81   void *vWaste)
82   {
83 #if (! RUN_TIME) && (! BLOAD_ONLY)
84    struct defrule *waste = (struct defrule *) vWaste;
85    int first = TRUE;
86    struct defrule *nextPtr, *tmpPtr;
87 
88    if (waste == NULL) return;
89 
90    /*======================================*/
91    /* If a rule is redefined, then we want */
92    /* to save its breakpoint status.       */
93    /*======================================*/
94 
95 #if DEBUGGING_FUNCTIONS
96    DefruleData(theEnv)->DeletedRuleDebugFlags = 0;
97    if (waste->afterBreakpoint) BitwiseSet(DefruleData(theEnv)->DeletedRuleDebugFlags,0);
98    if (waste->watchActivation) BitwiseSet(DefruleData(theEnv)->DeletedRuleDebugFlags,1);
99    if (waste->watchFiring) BitwiseSet(DefruleData(theEnv)->DeletedRuleDebugFlags,2);
100 #endif
101 
102    /*================================*/
103    /* Clear the agenda of all the    */
104    /* activations added by the rule. */
105    /*================================*/
106 
107    ClearRuleFromAgenda(theEnv,waste);
108 
109    /*======================*/
110    /* Get rid of the rule. */
111    /*======================*/
112 
113    while (waste != NULL)
114      {
115       /*================================================*/
116       /* Remove the rule's joins from the join network. */
117       /*================================================*/
118 
119       DetachJoinsDriver(theEnv,waste,FALSE);
120 
121       /*=============================================*/
122       /* If this is the first disjunct, get rid of   */
123       /* the dynamic salience and pretty print form. */
124       /*=============================================*/
125 
126       if (first)
127         {
128          if (waste->dynamicSalience != NULL)
129           {
130            ExpressionDeinstall(theEnv,waste->dynamicSalience);
131            ReturnPackedExpression(theEnv,waste->dynamicSalience);
132            waste->dynamicSalience = NULL;
133           }
134          if (waste->header.ppForm != NULL)
135            {
136             rm(theEnv,(void *) waste->header.ppForm,strlen(waste->header.ppForm) + 1);
137             waste->header.ppForm = NULL;
138 
139             /*=======================================================*/
140             /* All of the rule disjuncts share the same pretty print */
141             /* form, so we want to avoid deleting it again.          */
142             /*=======================================================*/
143 
144             for (tmpPtr = waste->disjunct; tmpPtr != NULL; tmpPtr = tmpPtr->disjunct)
145               { tmpPtr->header.ppForm = NULL; }
146            }
147 
148          first = FALSE;
149         }
150 
151       /*===========================*/
152       /* Get rid of any user data. */
153       /*===========================*/
154 
155       if (waste->header.usrData != NULL)
156         { ClearUserDataList(theEnv,waste->header.usrData); }
157 
158       /*===========================================*/
159       /* Decrement the count for the defrule name. */
160       /*===========================================*/
161 
162       DecrementSymbolCount(theEnv,waste->header.name);
163 
164       /*========================================*/
165       /* Get rid of the the rule's RHS actions. */
166       /*========================================*/
167 
168       if (waste->actions != NULL)
169         {
170          ExpressionDeinstall(theEnv,waste->actions);
171          ReturnPackedExpression(theEnv,waste->actions);
172         }
173 
174       /*===============================*/
175       /* Move on to the next disjunct. */
176       /*===============================*/
177 
178       nextPtr = waste->disjunct;
179       rtn_struct(theEnv,defrule,waste);
180       waste = nextPtr;
181      }
182 
183    /*==========================*/
184    /* Free up partial matches. */
185    /*==========================*/
186 
187    if (EngineData(theEnv)->ExecutingRule == NULL) FlushGarbagePartialMatches(theEnv);
188 #endif
189   }
190 
191 /********************************************************/
192 /* DestroyDefrule: Action used to remove defrules       */
193 /*   as a result of DestroyEnvironment.                 */
194 /********************************************************/
DestroyDefrule(void * theEnv,void * vTheDefrule)195 globle void DestroyDefrule(
196   void *theEnv,
197   void *vTheDefrule)
198   {
199    struct defrule *theDefrule = (struct defrule *) vTheDefrule;
200    struct defrule *nextDisjunct;
201    int first = TRUE;
202 
203    if (theDefrule == NULL) return;
204 
205    while (theDefrule != NULL)
206      {
207       DetachJoinsDriver(theEnv,theDefrule,TRUE);
208 
209       if (first)
210         {
211 #if (! BLOAD_ONLY) && (! RUN_TIME)
212          if (theDefrule->dynamicSalience != NULL)
213            { ReturnPackedExpression(theEnv,theDefrule->dynamicSalience); }
214 
215          if (theDefrule->header.ppForm != NULL)
216            {
217             struct defrule *tmpPtr;
218 
219             rm(theEnv,(void *) theDefrule->header.ppForm,strlen(theDefrule->header.ppForm) + 1);
220 
221             /*=======================================================*/
222             /* All of the rule disjuncts share the same pretty print */
223             /* form, so we want to avoid deleting it again.          */
224             /*=======================================================*/
225 
226             for (tmpPtr = theDefrule->disjunct; tmpPtr != NULL; tmpPtr = tmpPtr->disjunct)
227               { tmpPtr->header.ppForm = NULL; }
228            }
229 #endif
230 
231          first = FALSE;
232         }
233 
234       if (theDefrule->header.usrData != NULL)
235         { ClearUserDataList(theEnv,theDefrule->header.usrData); }
236 
237 #if (! BLOAD_ONLY) && (! RUN_TIME)
238       if (theDefrule->actions != NULL)
239         { ReturnPackedExpression(theEnv,theDefrule->actions); }
240 #endif
241 
242       nextDisjunct = theDefrule->disjunct;
243 
244 #if (! BLOAD_ONLY) && (! RUN_TIME)
245       rtn_struct(theEnv,defrule,theDefrule);
246 #endif
247 
248       theDefrule = nextDisjunct;
249      }
250   }
251 
252 /**********************************************************************/
253 /* DetachJoinsDriver:                           */
254 /**********************************************************************/
DetachJoinsDriver(void * theEnv,struct defrule * theRule,intBool destroy)255 static void DetachJoinsDriver(
256   void *theEnv,
257   struct defrule *theRule,
258   intBool destroy)
259   {
260    struct joinNode *join;
261 
262    /*==================================*/
263    /* Find the last join for the rule. */
264    /*==================================*/
265 
266    join = theRule->lastJoin;
267    theRule->lastJoin = NULL;
268    if (join == NULL) return;
269 
270    /*===================================================*/
271    /* Remove the activation link from the last join. If */
272    /* there are joins below this join, then all of the  */
273    /* joins for this rule were shared with another rule */
274    /* and thus no joins can be deleted.                 */
275    /*===================================================*/
276 
277    join->ruleToActivate = NULL;
278    if (join->nextLinks != NULL) return;
279 
280    DetachJoins(theEnv,join,destroy);
281   }
282 
283 /**********************************************************************/
284 /* DetachJoins: Removes a join node and all of its parent nodes from  */
285 /*   the join network. Nodes are only removed if they are no required */
286 /*   by other rules (the same join can be shared by multiple rules).  */
287 /*   Any partial matches associated with the join are also removed.   */
288 /*   A rule's joins are typically removed by removing the bottom most */
289 /*   join used by the rule and then removing any parent joins which   */
290 /*   are not shared by other rules.                                   */
291 /**********************************************************************/
DetachJoins(void * theEnv,struct joinNode * join,intBool destroy)292 static void DetachJoins(
293   void *theEnv,
294   struct joinNode *join,
295   intBool destroy)
296   {
297    struct joinNode *prevJoin, *rightJoin;
298    struct joinLink *lastLink, *theLink;
299    int lastMark;
300 
301    /*===========================*/
302    /* Begin removing the joins. */
303    /*===========================*/
304 
305    while (join != NULL)
306      {
307       if (join->marked) return;
308 
309       /*==========================================================*/
310       /* Remember the join "above" this join (the one that enters */
311       /* from the left). If the join is entered from the right by */
312       /* another join, remember the right entering join as well.  */
313       /*==========================================================*/
314 
315       prevJoin = join->lastLevel;
316       if (join->joinFromTheRight)
317         { rightJoin = (struct joinNode *) join->rightSideEntryStructure; }
318       else
319         { rightJoin = NULL; }
320 
321       /*=================================================*/
322       /* If the join was attached to a pattern, remove   */
323       /* any structures associated with the pattern that */
324       /* are no longer needed.                           */
325       /*=================================================*/
326 
327 #if (! RUN_TIME) && (! BLOAD_ONLY)
328       if (! destroy)
329         {
330          if ((join->rightSideEntryStructure != NULL) && (join->joinFromTheRight == FALSE))
331            { RemoveIntranetworkLink(theEnv,join); }
332         }
333 #endif
334 
335       /*======================================*/
336       /* Remove any partial matches contained */
337       /* in the beta memory of the join.      */
338       /*======================================*/
339 
340       if (destroy)
341         {
342          DestroyBetaMemory(theEnv,join,LHS);
343          DestroyBetaMemory(theEnv,join,RHS);
344         }
345       else
346         {
347          FlushBetaMemory(theEnv,join,LHS);
348          FlushBetaMemory(theEnv,join,RHS);
349         }
350 
351       ReturnLeftMemory(theEnv,join);
352       ReturnRightMemory(theEnv,join);
353 
354       /*===================================*/
355       /* Remove the expressions associated */
356       /* with the join.                    */
357       /*===================================*/
358 
359 #if (! RUN_TIME) && (! BLOAD_ONLY)
360       if (! destroy)
361         {
362          RemoveHashedExpression(theEnv,join->networkTest);
363          RemoveHashedExpression(theEnv,join->secondaryNetworkTest);
364          RemoveHashedExpression(theEnv,join->leftHash);
365          RemoveHashedExpression(theEnv,join->rightHash);
366         }
367 #endif
368 
369       /*============================*/
370       /* Fix the right prime links. */
371       /*============================*/
372 
373       if (join->firstJoin && (join->rightSideEntryStructure == NULL))
374         {
375          lastLink = NULL;
376 
377          theLink = DefruleData(theEnv)->RightPrimeJoins;
378          while (theLink != NULL)
379            {
380             if (theLink->join == join)
381               {
382                if (lastLink == NULL)
383                  { DefruleData(theEnv)->RightPrimeJoins = theLink->next; }
384                else
385                  { lastLink->next = theLink->next; }
386 
387 #if (! RUN_TIME) && (! BLOAD_ONLY)
388                rtn_struct(theEnv,joinLink,theLink);
389 #endif
390 
391                theLink = NULL;
392               }
393             else
394               {
395                lastLink = theLink;
396                theLink = lastLink->next;
397               }
398            }
399         }
400 
401       /*===========================*/
402       /* Fix the left prime links. */
403       /*===========================*/
404 
405       if (join->firstJoin && (join->patternIsNegated || join->joinFromTheRight) && (! join->patternIsExists))
406         {
407          lastLink = NULL;
408          theLink = DefruleData(theEnv)->LeftPrimeJoins;
409          while (theLink != NULL)
410            {
411             if (theLink->join == join)
412               {
413                if (lastLink == NULL)
414                  { DefruleData(theEnv)->LeftPrimeJoins = theLink->next; }
415                else
416                  { lastLink->next = theLink->next; }
417 
418 #if (! RUN_TIME) && (! BLOAD_ONLY)
419                rtn_struct(theEnv,joinLink,theLink);
420 #endif
421 
422                theLink = NULL;
423               }
424             else
425               {
426                lastLink = theLink;
427                theLink = theLink->next;
428               }
429            }
430         }
431 
432       /*==================================================*/
433       /* Remove the link to the join from the join above. */
434       /*==================================================*/
435 
436       if (prevJoin != NULL)
437         {
438          lastLink = NULL;
439          theLink = prevJoin->nextLinks;
440          while (theLink != NULL)
441            {
442             if (theLink->join == join)
443               {
444                if (lastLink == NULL)
445                  { prevJoin->nextLinks = theLink->next; }
446                else
447                  { lastLink->next = theLink->next; }
448 
449 #if (! RUN_TIME) && (! BLOAD_ONLY)
450                rtn_struct(theEnv,joinLink,theLink);
451 #endif
452 
453                theLink = NULL;
454               }
455             else
456               {
457                lastLink = theLink;
458                theLink = theLink->next;
459               }
460             }
461         }
462 
463       /*==========================================*/
464       /* Remove the right join link if it exists. */
465       /*==========================================*/
466 
467       if (rightJoin != NULL)
468         {
469          lastLink = NULL;
470          theLink = rightJoin->nextLinks;
471          while (theLink != NULL)
472            {
473             if (theLink->join == join)
474               {
475                if (lastLink == NULL)
476                  { rightJoin->nextLinks = theLink->next; }
477                else
478                  { lastLink->next = theLink->next; }
479 
480 #if (! RUN_TIME) && (! BLOAD_ONLY)
481                rtn_struct(theEnv,joinLink,theLink);
482 #endif
483                theLink = NULL;
484               }
485             else
486               {
487                lastLink = theLink;
488                theLink = theLink->next;
489               }
490             }
491 
492          if ((rightJoin->nextLinks == NULL) &&
493              (rightJoin->ruleToActivate == NULL))
494            {
495             if (prevJoin != NULL)
496               {
497                lastMark = prevJoin->marked;
498                prevJoin->marked = TRUE;
499                DetachJoins(theEnv,rightJoin,destroy);
500                prevJoin->marked = lastMark;
501               }
502             else
503               { DetachJoins(theEnv,rightJoin,destroy); }
504            }
505         }
506 
507       /*==================*/
508       /* Delete the join. */
509       /*==================*/
510 
511 #if (! RUN_TIME) && (! BLOAD_ONLY)
512       rtn_struct(theEnv,joinNode,join);
513 #endif
514 
515       /*===========================================================*/
516       /* Move on to the next join to be removed. All the joins of  */
517       /* a rule can be deleted by following the right joins links  */
518       /* (when these links exist) and then following the left join */
519       /* links. This works because if join A enters join B from    */
520       /* the right, the right/left links of join A eventually lead */
521       /* to the join which enters join B from the left.            */
522       /*===========================================================*/
523 
524       if (prevJoin == NULL)
525         { return; }
526       else if (prevJoin->ruleToActivate != NULL)
527         { return; }
528       else if (prevJoin->nextLinks == NULL)
529         { join = prevJoin; }
530       else
531         { return; }
532      }
533   }
534 
535 #if (! RUN_TIME) && (! BLOAD_ONLY)
536 
537 /***********************************************************************/
538 /* RemoveIntranetworkLink: Removes the link between a join node in the */
539 /*   join network and its corresponding pattern node in the pattern    */
540 /*   network. If the pattern node is then no longer associated with    */
541 /*   any other joins, it is removed using the function DetachPattern.  */
542 /***********************************************************************/
RemoveIntranetworkLink(void * theEnv,struct joinNode * join)543 static void RemoveIntranetworkLink(
544   void *theEnv,
545   struct joinNode *join)
546   {
547    struct patternNodeHeader *patternPtr;
548    struct joinNode *joinPtr, *lastJoin;
549 
550    /*================================================*/
551    /* Determine the pattern that enters this join.   */
552    /* Determine the list of joins which this pattern */
553    /* enters from the right.                         */
554    /*================================================*/
555 
556    patternPtr = (struct patternNodeHeader *) join->rightSideEntryStructure;
557    joinPtr = patternPtr->entryJoin;
558    lastJoin = NULL;
559 
560    /*=================================================*/
561    /* Loop through the list of joins that the pattern */
562    /* enters until the join being removed is found.   */
563    /* Remove this join from the list.                 */
564    /*=================================================*/
565 
566    while (joinPtr != NULL)
567      {
568       if (joinPtr == join)
569         {
570          if (lastJoin == NULL)
571            { patternPtr->entryJoin = joinPtr->rightMatchNode; }
572          else
573            { lastJoin->rightMatchNode = joinPtr->rightMatchNode; }
574 
575          joinPtr = NULL;
576         }
577       else
578         {
579          lastJoin = joinPtr;
580          joinPtr = joinPtr->rightMatchNode;
581         }
582      }
583 
584    /*===================================================*/
585    /* If the terminal node of the pattern doesn't point */
586    /* to any joins, then start removing the pattern.    */
587    /*===================================================*/
588 
589    if (patternPtr->entryJoin == NULL)
590      { DetachPattern(theEnv,(int) join->rhsType,patternPtr); }
591   }
592 
593 #endif /* (! RUN_TIME) && (! BLOAD_ONLY) */
594 
595 #endif /* DEFRULE_CONSTRUCT */
596 
597 
598 
599