static Defrule *ProcessRuleLHS( Environment *theEnv, struct lhsParseNode *theLHS, struct expr *actions, CLIPSLexeme *ruleName, bool *error) { struct lhsParseNode *tempNode = NULL; Defrule *topDisjunct = NULL, *currentDisjunct, *lastDisjunct = NULL; struct expr *newActions, *packPtr; int logicalJoin; unsigned short localVarCnt; unsigned short complexity; struct joinNode *lastJoin; bool emptyLHS; /*================================================*/ /* Initially set the parsing error flag to false. */ /*================================================*/ *error = false; /*===========================================================*/ /* The top level of the construct representing the LHS of a */ /* rule is assumed to be an OR. If the implied OR is at the */ /* top level of the pattern construct, then remove it. */ /*===========================================================*/ if (theLHS == NULL) { emptyLHS = true; } else { emptyLHS = false; if (theLHS->pnType == OR_CE_NODE) theLHS = theLHS->right; } /*=========================================*/ /* Loop through each disjunct of the rule. */ /*=========================================*/ localVarCnt = CountParsedBindNames(theEnv); while ((theLHS != NULL) || (emptyLHS == true)) { /*===================================*/ /* Analyze the LHS of this disjunct. */ /*===================================*/ if (emptyLHS) { tempNode = NULL; } else { if (theLHS->pnType == AND_CE_NODE) tempNode = theLHS->right; else if (theLHS->pnType == PATTERN_CE_NODE) tempNode = theLHS; } if (VariableAnalysis(theEnv,tempNode)) { *error = true; ReturnDefrule(theEnv,topDisjunct); return NULL; } /*=========================================*/ /* Perform entity dependent post analysis. */ /*=========================================*/ if (PostPatternAnalysis(theEnv,tempNode)) { *error = true; ReturnDefrule(theEnv,topDisjunct); return NULL; } /*========================================================*/ /* Print out developer information if it's being watched. */ /*========================================================*/ #if DEVELOPER && DEBUGGING_FUNCTIONS if (GetWatchItem(theEnv,"rule-analysis") == 1) { DumpRuleAnalysis(theEnv,tempNode); } #endif /*======================================================*/ /* Check to see if there are any RHS constraint errors. */ /*======================================================*/ if (CheckRHSForConstraintErrors(theEnv,actions,tempNode)) { *error = true; ReturnDefrule(theEnv,topDisjunct); return NULL; } /*=================================================*/ /* Replace variable references in the RHS with the */ /* appropriate variable retrieval functions. */ /*=================================================*/ newActions = CopyExpression(theEnv,actions); if (ReplaceProcVars(theEnv,"RHS of defrule",newActions,NULL,NULL, ReplaceRHSVariable,tempNode)) { *error = true; ReturnDefrule(theEnv,topDisjunct); ReturnExpression(theEnv,newActions); return NULL; } /*===================================================*/ /* Remove any test CEs from the LHS and attach their */ /* expression to the closest preceeding non-negated */ /* join at the same not/and depth. */ /*===================================================*/ AttachTestCEsToPatternCEs(theEnv,tempNode); /*========================================*/ /* Check to see that logical CEs are used */ /* appropriately in the LHS of the rule. */ /*========================================*/ if ((logicalJoin = LogicalAnalysis(theEnv,tempNode)) < 0) { *error = true; ReturnDefrule(theEnv,topDisjunct); ReturnExpression(theEnv,newActions); return NULL; } /*==================================*/ /* We're finished for this disjunct */ /* if we're only checking syntax. */ /*==================================*/ if (ConstructData(theEnv)->CheckSyntaxMode) { ReturnExpression(theEnv,newActions); if (emptyLHS) { emptyLHS = false; } else { theLHS = theLHS->bottom; } continue; } /*=================================*/ /* Install the disjunct's actions. */ /*=================================*/ ExpressionInstall(theEnv,newActions); packPtr = PackExpression(theEnv,newActions); ReturnExpression(theEnv,newActions); /*===============================================================*/ /* Create the pattern and join data structures for the new rule. */ /*===============================================================*/ lastJoin = ConstructJoins(theEnv,logicalJoin,tempNode,1,NULL,true,true); /*===================================================================*/ /* Determine the rule's complexity for use with conflict resolution. */ /*===================================================================*/ complexity = RuleComplexity(theEnv,tempNode); /*=====================================================*/ /* Create the defrule data structure for this disjunct */ /* and put it in the list of disjuncts for this rule. */ /*=====================================================*/ currentDisjunct = CreateNewDisjunct(theEnv,ruleName,localVarCnt,packPtr,complexity, (unsigned) logicalJoin,lastJoin); /*============================================================*/ /* Place the disjunct in the list of disjuncts for this rule. */ /* If the disjunct is the first disjunct, then increment the */ /* reference counts for the dynamic salience (the expression */ /* for the dynamic salience is only stored with the first */ /* disjuncts and the other disjuncts refer back to the first */ /* disjunct for their dynamic salience value. */ /*============================================================*/ if (topDisjunct == NULL) { topDisjunct = currentDisjunct; ExpressionInstall(theEnv,topDisjunct->dynamicSalience); } else lastDisjunct->disjunct = currentDisjunct; /*===========================================*/ /* Move on to the next disjunct of the rule. */ /*===========================================*/ lastDisjunct = currentDisjunct; if (emptyLHS) { emptyLHS = false; } else { theLHS = theLHS->bottom; } } return(topDisjunct); }
globle struct joinNode *ConstructJoins( void *theEnv, int logicalJoin, struct lhsParseNode *theLHS, int startDepth) { struct joinNode *lastJoin = NULL; struct patternNodeHeader *lastPattern; unsigned firstJoin = TRUE; int tryToReuse = TRUE; struct joinNode *listOfJoins = NULL; struct joinNode *oldJoin; int joinNumber = 1; int isLogical, isExists; struct joinNode *lastRightJoin; int lastIteration = FALSE; int rhsType; struct expr *leftHash, *rightHash; void *rhsStruct; struct lhsParseNode *nextLHS; struct expr *networkTest, *secondaryNetworkTest, *secondaryExternalTest; int joinFromTheRight; struct joinLink *theLinks; intBool useLinks; /*===================================================*/ /* Remove any test CEs from the LHS and attach their */ /* expression to the closest preceeding non-negated */ /* join at the same not/and depth. */ /*===================================================*/ if (startDepth == 1) { AttachTestCEsToPatternCEs(theEnv,theLHS); } if (theLHS == NULL) { lastJoin = FindShareableJoin(DefruleData(theEnv)->RightPrimeJoins,NULL,TRUE,NULL,TRUE, FALSE,FALSE,FALSE,NULL,NULL,NULL,NULL); if (lastJoin == NULL) { lastJoin = CreateNewJoin(theEnv,NULL,NULL,NULL,NULL,FALSE,FALSE,FALSE,NULL,NULL); } } /*=====================================================*/ /* Process each pattern CE in the rule. At this point, */ /* there should be no and/or/not/test CEs in the LHS. */ /*=====================================================*/ while (theLHS != NULL) { /*======================================================*/ /* Find the beginning of the next group of patterns. If */ /* the current pattern is not the beginning of a "join */ /* from the right" group of patterns, then the next */ /* pattern is the next pattern. Otherwise skip over all */ /* the patterns that belong to the group of subjoins. */ /*======================================================*/ nextLHS = theLHS->bottom; secondaryExternalTest = NULL; if (theLHS->endNandDepth > startDepth) { while ((nextLHS != NULL) && (nextLHS->endNandDepth > startDepth)) { nextLHS = nextLHS->bottom; } /*====================================================*/ /* Variable nextLHS is now pointing to the end of the */ /* not/and group beginning with variable theLHS. If */ /* the end depth of the group is less than the depth */ /* of the current enclosing not/and group, then this */ /* is the last iteration for the enclosing group. */ /*====================================================*/ if (nextLHS != NULL) { if (nextLHS->endNandDepth < startDepth) { lastIteration = TRUE; } } if (nextLHS != NULL) { nextLHS = nextLHS->bottom; } if ((nextLHS != NULL) && (nextLHS->type == TEST_CE)) { secondaryExternalTest = nextLHS->networkTest; nextLHS = nextLHS->bottom; } } /*=======================================*/ /* Is this the last pattern to be added? */ /*=======================================*/ if (nextLHS == NULL) { lastIteration = TRUE; } else if (theLHS->endNandDepth < startDepth) { lastIteration = TRUE; } else if ((nextLHS->type == TEST_CE) && (theLHS->beginNandDepth > startDepth) && (nextLHS->endNandDepth < startDepth)) { lastIteration = TRUE; } /*===============================================*/ /* If the pattern is a join from the right, then */ /* construct the subgroup of patterns and use */ /* that as the RHS of the join to be added. */ /*===============================================*/ if (theLHS->beginNandDepth > startDepth) { joinFromTheRight = TRUE; isExists = theLHS->existsNand; lastRightJoin = ConstructJoins(theEnv,logicalJoin,theLHS,startDepth+1); rhsStruct = lastRightJoin; rhsType = 0; lastPattern = NULL; networkTest = theLHS->externalNetworkTest; /* TBD */ secondaryNetworkTest = secondaryExternalTest; leftHash = theLHS->externalLeftHash; rightHash = theLHS->externalRightHash; } /*=======================================================*/ /* Otherwise, add the pattern to the appropriate pattern */ /* network and use the pattern node containing the alpha */ /* memory as the RHS of the join to be added. */ /*=======================================================*/ else if (theLHS->right == NULL) { joinFromTheRight = FALSE; rhsType = 0; lastPattern = NULL; rhsStruct = NULL; lastRightJoin = NULL; isExists = theLHS->exists; networkTest = theLHS->networkTest; secondaryNetworkTest = theLHS->secondaryNetworkTest; leftHash = NULL; rightHash = NULL; } else { joinFromTheRight = FALSE; rhsType = theLHS->patternType->positionInArray; lastPattern = (*theLHS->patternType->addPatternFunction)(theEnv,theLHS); rhsStruct = lastPattern; lastRightJoin = NULL; isExists = theLHS->exists; networkTest = theLHS->networkTest; secondaryNetworkTest = theLHS->secondaryNetworkTest; leftHash = theLHS->leftHash; rightHash = theLHS->rightHash; } /*======================================================*/ /* Determine if the join being added is a logical join. */ /*======================================================*/ if ((startDepth == 1) && (joinNumber == logicalJoin)) isLogical = TRUE; else isLogical = FALSE; /*===============================================*/ /* Get the list of joins which could potentially */ /* be reused in place of the join being added. */ /*===============================================*/ useLinks = TRUE; if (firstJoin == TRUE) { if (theLHS->right == NULL) { theLinks = DefruleData(theEnv)->RightPrimeJoins; } else if (lastPattern != NULL) { listOfJoins = lastPattern->entryJoin; theLinks = NULL; useLinks = FALSE; } else { theLinks = lastRightJoin->nextLinks; } } else { theLinks = lastJoin->nextLinks; } /*=======================================================*/ /* Determine if the next join to be added can be shared. */ /*=======================================================*/ if ((tryToReuse == TRUE) && ((oldJoin = FindShareableJoin(theLinks,listOfJoins,useLinks,rhsStruct,firstJoin, theLHS->negated,isExists,isLogical, networkTest,secondaryNetworkTest, leftHash,rightHash)) != NULL) ) { #if DEBUGGING_FUNCTIONS if ((EnvGetWatchItem(theEnv,(char*)"compilations") == TRUE) && GetPrintWhileLoading(theEnv)) { EnvPrintRouter(theEnv,WDIALOG,(char*)"=j"); } #endif lastJoin = oldJoin; } else { tryToReuse = FALSE; if (! joinFromTheRight) { lastJoin = CreateNewJoin(theEnv,networkTest,secondaryNetworkTest,lastJoin, lastPattern,FALSE,(int) theLHS->negated, isExists, leftHash,rightHash); lastJoin->rhsType = rhsType; } else { lastJoin = CreateNewJoin(theEnv,networkTest,secondaryNetworkTest,lastJoin, lastRightJoin,TRUE,(int) theLHS->negated, isExists, leftHash,rightHash); lastJoin->rhsType = rhsType; } } /*============================================*/ /* If we've reached the end of the subgroup, */ /* then return the last join of the subgroup. */ /*============================================*/ if (lastIteration) { break; } /*=======================================*/ /* Move on to the next join to be added. */ /*=======================================*/ theLHS = nextLHS; joinNumber++; firstJoin = FALSE; } /*=================================================*/ /* Add the final join which stores the activations */ /* of the rule. This join is never shared. */ /*=================================================*/ if (startDepth == 1) { lastJoin = CreateNewJoin(theEnv,NULL,NULL,lastJoin,NULL, FALSE,FALSE,FALSE,NULL,NULL); } /*===================================================*/ /* If compilations are being watched, put a carriage */ /* return after all of the =j's and +j's */ /*===================================================*/ #if DEBUGGING_FUNCTIONS if ((startDepth == 1) && (EnvGetWatchItem(theEnv,(char*)"compilations") == TRUE) && GetPrintWhileLoading(theEnv)) { EnvPrintRouter(theEnv,WDIALOG,(char*)"\n"); } #endif /*=============================*/ /* Return the last join added. */ /*=============================*/ return(lastJoin); }
static struct defrule *ProcessRuleLHS( void *theEnv, struct lhsParseNode *theLHS, struct expr *actions, SYMBOL_HN *ruleName, int *error) { struct lhsParseNode *tempNode = NULL; struct defrule *topDisjunct = NULL, *currentDisjunct, *lastDisjunct = NULL; struct expr *newActions, *packPtr; int logicalJoin; int localVarCnt; int complexity; struct joinNode *lastJoin; intBool emptyLHS; /*================================================*/ /* Initially set the parsing error flag to FALSE. */ /*================================================*/ *error = FALSE; /*===========================================================*/ /* The top level of the construct representing the LHS of a */ /* rule is assumed to be an OR. If the implied OR is at the */ /* top level of the pattern construct, then remove it. */ /*===========================================================*/ if (theLHS == NULL) { emptyLHS = TRUE; } else { emptyLHS = FALSE; if (theLHS->type == OR_CE) theLHS = theLHS->right; } /*=========================================*/ /* Loop through each disjunct of the rule. */ /*=========================================*/ localVarCnt = CountParsedBindNames(theEnv); while ((theLHS != NULL) || (emptyLHS == TRUE)) { #if FUZZY_DEFTEMPLATES unsigned int LHSRuleType; /* LHSRuleType is set to FUZZY_LHS or CRISP_LHS */ unsigned int numFuzzySlots; int patternNum; #endif /*===================================*/ /* Analyze the LHS of this disjunct. */ /*===================================*/ if (emptyLHS) { tempNode = NULL; } else { if (theLHS->type == AND_CE) tempNode = theLHS->right; else if (theLHS->type == PATTERN_CE) tempNode = theLHS; } if (VariableAnalysis(theEnv,tempNode)) { *error = TRUE; ReturnDefrule(theEnv,topDisjunct); return(NULL); } /*=========================================*/ /* Perform entity dependent post analysis. */ /*=========================================*/ if (PostPatternAnalysis(theEnv,tempNode)) { *error = TRUE; ReturnDefrule(theEnv,topDisjunct); return(NULL); } #if FUZZY_DEFTEMPLATES /* calculate the number of fuzzy value slots in patterns with the rule disjunct and also determine LHS type of the rule -- if number of fuzzy slots in non-NOT patterns >0 then FUZZY LHS [if pattern is (not (xxx (fuzzySlot ...) ...)) then they don't count when considering the LHS type] */ if (emptyLHS) { tempNode = NULL; } else { if (theLHS->type == AND_CE) tempNode = theLHS->right; else if (theLHS->type == PATTERN_CE) tempNode = theLHS; } { int numFuzzySlotsInNonNotPatterns = 0; numFuzzySlots = FuzzySlotAnalysis(theEnv,tempNode, &numFuzzySlotsInNonNotPatterns); if (numFuzzySlotsInNonNotPatterns > 0) LHSRuleType = FUZZY_LHS; else LHSRuleType = CRISP_LHS; } #endif /*========================================================*/ /* Print out developer information if it's being watched. */ /*========================================================*/ #if DEVELOPER && DEBUGGING_FUNCTIONS if (EnvGetWatchItem(theEnv,"rule-analysis")) { DumpRuleAnalysis(theEnv,tempNode); } #endif /*======================================================*/ /* Check to see if there are any RHS constraint errors. */ /*======================================================*/ if (CheckRHSForConstraintErrors(theEnv,actions,tempNode)) { *error = TRUE; ReturnDefrule(theEnv,topDisjunct); return(NULL); } /*=================================================*/ /* Replace variable references in the RHS with the */ /* appropriate variable retrieval functions. */ /*=================================================*/ newActions = CopyExpression(theEnv,actions); if (ReplaceProcVars(theEnv,"RHS of defrule",newActions,NULL,NULL, ReplaceRHSVariable,(void *) tempNode)) { *error = TRUE; ReturnDefrule(theEnv,topDisjunct); ReturnExpression(theEnv,newActions); return(NULL); } /*===================================================*/ /* Remove any test CEs from the LHS and attach their */ /* expression to the closest preceeding non-negated */ /* join at the same not/and depth. */ /*===================================================*/ AttachTestCEsToPatternCEs(theEnv,tempNode); /*========================================*/ /* Check to see that logical CEs are used */ /* appropriately in the LHS of the rule. */ /*========================================*/ if ((logicalJoin = LogicalAnalysis(theEnv,tempNode)) < 0) { *error = TRUE; ReturnDefrule(theEnv,topDisjunct); ReturnExpression(theEnv,newActions); return(NULL); } /*==================================*/ /* We're finished for this disjunct */ /* if we're only checking syntax. */ /*==================================*/ if (ConstructData(theEnv)->CheckSyntaxMode) { ReturnExpression(theEnv,newActions); if (emptyLHS) { emptyLHS = FALSE; } else { theLHS = theLHS->bottom; } continue; } /*=================================*/ /* Install the disjunct's actions. */ /*=================================*/ ExpressionInstall(theEnv,newActions); packPtr = PackExpression(theEnv,newActions); ReturnExpression(theEnv,newActions); /*===============================================================*/ /* Create the pattern and join data structures for the new rule. */ /*===============================================================*/ lastJoin = ConstructJoins(theEnv,logicalJoin,tempNode,1,NULL,TRUE,TRUE); /*===================================================================*/ /* Determine the rule's complexity for use with conflict resolution. */ /*===================================================================*/ complexity = RuleComplexity(theEnv,tempNode); /*=====================================================*/ /* Create the defrule data structure for this disjunct */ /* and put it in the list of disjuncts for this rule. */ /*=====================================================*/ #if FUZZY_DEFTEMPLATES /* if not a FUZZY LHS then no need to allocate space to store ptrs to fuzzy slots of the patterns on the LHS since there won't be any -- numFuzzySlots will be 0. */ currentDisjunct = CreateNewDisjunct(theEnv,ruleName,localVarCnt,packPtr,complexity, logicalJoin,lastJoin,numFuzzySlots); /* set the type of LHS of Rule disjunct and also save fuzzy slot locator info for any fuzzy patterns */ currentDisjunct->lhsRuleType = LHSRuleType; if (numFuzzySlots > 0) { struct lhsParseNode *lhsPNPtr, *lhsSlotPtr; int i; /* get ptr to a pattern CE */ if (theLHS->type == AND_CE) lhsPNPtr = theLHS->right; else if (theLHS->type == PATTERN_CE) lhsPNPtr = theLHS; else lhsPNPtr = NULL; patternNum = 0; /* indexed from 0 */ i = 0; while (lhsPNPtr != NULL) { if (lhsPNPtr->type == PATTERN_CE) { lhsSlotPtr = lhsPNPtr->right; while (lhsSlotPtr != NULL) { /*==========================================================*/ /* If fuzzy template slot then save ptr to fuzzy value */ /* */ /* NOTE: when the pattern was added to the pattern net, the */ /* pattern node for the template name was removed (see */ /* PlaceFactPattern) and the pattern node of the FUZZY_VALUE*/ /* was changed a networkTest link in the SF_VARIABLE or */ /* SF_WILDCARD node as an SCALL_PN_FUZZY_VALUE expression. */ /* We need to search for that fuzzy value to put it in the */ /* rule (pattern_fv_arrayPtr points to an array of */ /* structures that holds the pattern number, slot number and*/ /* fuzzy value HN ptrs connected to the patterns of LHS). */ /*==========================================================*/ if (lhsSlotPtr->type == SF_WILDCARD || lhsSlotPtr->type == SF_VARIABLE) { FUZZY_VALUE_HN *fv_ptr; struct fzSlotLocator * fzSL_ptr; fv_ptr = findFuzzyValueInNetworktest(lhsSlotPtr->networkTest); if (fv_ptr != NULL) { fzSL_ptr = currentDisjunct->pattern_fv_arrayPtr + i; fzSL_ptr->patternNum = patternNum; fzSL_ptr->slotNum = (lhsSlotPtr->slotNumber)-1; fzSL_ptr->fvhnPtr = fv_ptr; i++; } } /*=====================================================*/ /* Move on to the next slot in the pattern. */ /*=====================================================*/ lhsSlotPtr = lhsSlotPtr->right; } } /*=====================================================*/ /* Move on to the next pattern in the LHS of the rule. */ /*=====================================================*/ lhsPNPtr = lhsPNPtr->bottom; patternNum++; } /* i should == numFuzzySlots OR something internal is screwed up -- OR this algorithm has a problem. */ if (i != numFuzzySlots) { EnvPrintRouter(theEnv,WERROR,"Internal ERROR *** Fuzzy structures -- routine ProcessRuleLHS\n"); EnvExitRouter(theEnv,EXIT_FAILURE); } } #else currentDisjunct = CreateNewDisjunct(theEnv,ruleName,localVarCnt,packPtr,complexity, (unsigned) logicalJoin,lastJoin); #endif /*============================================================*/ /* Place the disjunct in the list of disjuncts for this rule. */ /* If the disjunct is the first disjunct, then increment the */ /* reference counts for the dynamic salience (the expression */ /* for the dynamic salience is only stored with the first */ /* disjuncts and the other disjuncts refer back to the first */ /* disjunct for their dynamic salience value. */ /*============================================================*/ if (topDisjunct == NULL) { topDisjunct = currentDisjunct; ExpressionInstall(theEnv,topDisjunct->dynamicSalience); #if CERTAINTY_FACTORS ExpressionInstall(theEnv,topDisjunct->dynamicCF); #endif } else lastDisjunct->disjunct = currentDisjunct; /*===========================================*/ /* Move on to the next disjunct of the rule. */ /*===========================================*/ lastDisjunct = currentDisjunct; if (emptyLHS) { emptyLHS = FALSE; } else { theLHS = theLHS->bottom; } } return(topDisjunct); }