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