static void ExtractAnds( void *theEnv, EXEC_STATUS, struct lhsParseNode *andField, int testInPatternNetwork, struct expr **patternNetTest, struct expr **joinNetTest, struct expr **nandTest, struct expr **constantSelector, struct expr **constantValue, int nandField) { struct expr *newPNTest, *newJNTest, *newNandTest, *newConstantSelector, *newConstantValue; /*=================================================*/ /* Before starting, the subfield has no pattern or */ /* join network expressions associated with it. */ /*=================================================*/ *patternNetTest = NULL; *joinNetTest = NULL; *nandTest = NULL; *constantSelector = NULL; *constantValue = NULL; /*=========================================*/ /* Loop through each of the subfields tied */ /* together by the & constraint. */ /*=========================================*/ for (; andField != NULL; andField = andField->right) { /*======================================*/ /* Extract the pattern and join network */ /* expressions from the subfield. */ /*======================================*/ ExtractFieldTest(theEnv,execStatus,andField,testInPatternNetwork,&newPNTest,&newJNTest,&newNandTest,&newConstantSelector,&newConstantValue,nandField); /*=================================================*/ /* Add the new expressions to the list of pattern */ /* and join network expressions being constructed. */ /*=================================================*/ *patternNetTest = CombineExpressions(theEnv,execStatus,*patternNetTest,newPNTest); *joinNetTest = CombineExpressions(theEnv,execStatus,*joinNetTest,newJNTest); *nandTest = CombineExpressions(theEnv,execStatus,*nandTest,newNandTest); *constantSelector = CombineExpressions(theEnv,execStatus,*constantSelector,newConstantSelector); *constantValue = CombineExpressions(theEnv,execStatus,*constantValue,newConstantValue); } }
/**************************************************** NAME : GenObjectLengthTest DESCRIPTION : Generates a test on the cardinality of a slot matching an object pattern INPUTS : The first lhsParseNode for a slot in an object pattern RETURNS : Nothing useful SIDE EFFECTS : The lhsParseNode network test is modified to include the length test NOTES : None ****************************************************/ globle void GenObjectLengthTest( void *theEnv, struct lhsParseNode *theNode) { struct ObjectMatchLength hack; EXPRESSION *theTest; if ((theNode->singleFieldsAfter == 0) && (theNode->type != SF_VARIABLE) && (theNode->type != SF_WILDCARD)) return; ClearBitString((void *) &hack,(int) sizeof(struct ObjectMatchLength)); if ((theNode->type != MF_VARIABLE) && (theNode->type != MF_WILDCARD) && (theNode->multiFieldsAfter == 0)) hack.exactly = 1; else hack.exactly = 0; if ((theNode->type == SF_VARIABLE) || (theNode->type == SF_WILDCARD)) hack.minLength = 1 + theNode->singleFieldsAfter; else hack.minLength = theNode->singleFieldsAfter; theTest = GenConstant(theEnv,OBJ_SLOT_LENGTH,EnvAddBitMap(theEnv,(void *) &hack, (int) sizeof(struct ObjectMatchLength))); if (theNode->constantSelector != NULL) { theNode->constantSelector->nextArg = CopyExpression(theEnv,theTest); } theNode->networkTest = CombineExpressions(theEnv,theTest,theNode->networkTest); }
static void AttachTestCEsToPatternCEs( void *theEnv, struct lhsParseNode *theLHS) { struct lhsParseNode *lastNode, *tempNode; if (theLHS == NULL) return; /*=============================================================*/ /* Attach test CEs that can be attached directly to a pattern. */ /*=============================================================*/ lastNode = theLHS; theLHS = lastNode->bottom; while (theLHS != NULL) { if ((theLHS->type != TEST_CE) || (lastNode->beginNandDepth != lastNode->endNandDepth) || (lastNode->beginNandDepth != theLHS->beginNandDepth)) { lastNode = theLHS; theLHS = theLHS->bottom; continue; } if (lastNode->negated) { lastNode->secondaryNetworkTest = CombineExpressions(theEnv,lastNode->secondaryNetworkTest,theLHS->networkTest); } else { lastNode->networkTest = CombineExpressions(theEnv,lastNode->networkTest,theLHS->networkTest); } theLHS->networkTest = NULL; tempNode = theLHS->bottom; theLHS->bottom = NULL; lastNode->bottom = tempNode; lastNode->endNandDepth = theLHS->endNandDepth; ReturnLHSParseNodes(theEnv,theLHS); theLHS = tempNode; } }
/**************************************************** NAME : GenObjectZeroLengthTest DESCRIPTION : Generates a test on the cardinality of a slot matching an object pattern INPUTS : The first lhsParseNode for a slot in an object pattern RETURNS : Nothing useful SIDE EFFECTS : The lhsParseNode network test is modified to include the length test NOTES : None ****************************************************/ globle void GenObjectZeroLengthTest( struct lhsParseNode *theNode) { struct ObjectMatchLength hack; EXPRESSION *theTest; ClearBitString((void *) &hack,(int) sizeof(struct ObjectMatchLength)); hack.exactly = 1; hack.minLength = 0; theTest = GenConstant(OBJ_SLOT_LENGTH,AddBitMap((void *) &hack, (int) sizeof(struct ObjectMatchLength))); theNode->networkTest = CombineExpressions(theTest,theNode->networkTest); }
globle void AddNandUnification( void *theEnv, struct lhsParseNode *nodeList, struct nandFrame *theNandFrames) { struct nandFrame *theFrame; struct expr *tempExpression; /*====================================================*/ /* If the reference is to a prior variable within the */ /* same nand group, then there's no need to create an */ /* external network test. */ /*====================================================*/ if (nodeList->beginNandDepth == nodeList->referringNode->beginNandDepth) { return; } /*=========================================*/ /* Don't generate an external network test */ /* if one has already been generated. */ /*=========================================*/ if (nodeList->referringNode->marked) { return; } /*======================================================*/ /* Find the frame to which the test should be attached. */ /*======================================================*/ for (theFrame = theNandFrames; theFrame != NULL; theFrame = theFrame->next) { if (theFrame->depth >= nodeList->referringNode->beginNandDepth) { nodeList->referringNode->marked = TRUE; tempExpression = GenJNVariableComparison(theEnv,nodeList->referringNode,nodeList->referringNode,TRUE); theFrame->nandCE->externalNetworkTest = CombineExpressions(theEnv,theFrame->nandCE->externalNetworkTest,tempExpression); tempExpression = (*nodeList->referringNode->patternType->genGetJNValueFunction)(theEnv,nodeList->referringNode,LHS); theFrame->nandCE->externalRightHash = AppendExpressions(theFrame->nandCE->externalRightHash,tempExpression); tempExpression = (*nodeList->referringNode->patternType->genGetJNValueFunction)(theEnv,nodeList->referringNode,LHS); theFrame->nandCE->externalLeftHash = AppendExpressions(theFrame->nandCE->externalLeftHash,tempExpression); } } }
static void AttachTestCEsToPatternCEs( void *theEnv, struct lhsParseNode *theLHS) { struct lhsParseNode *lastNode, *tempNode; if (theLHS == NULL) return; /*=============================================================*/ /* Attach test CEs that can be attached directly to a pattern. */ /*=============================================================*/ lastNode = theLHS; theLHS = lastNode->bottom; while (theLHS != NULL) { if ((theLHS->type != TEST_CE) || (lastNode->beginNandDepth != lastNode->endNandDepth) || (lastNode->beginNandDepth != theLHS->beginNandDepth)) { lastNode = theLHS; theLHS = theLHS->bottom; continue; } if (lastNode->negated) { lastNode->secondaryNetworkTest = CombineExpressions(theEnv,lastNode->secondaryNetworkTest,theLHS->networkTest); } else { lastNode->networkTest = CombineExpressions(theEnv,lastNode->networkTest,theLHS->networkTest); } /*==============================================================*/ /* If an exists with multiple conditions has just a pattern and */ /* a test, it should be treated as a single pattern and use the */ /* simpler exists logic rather than the logic used for multiple */ /* patterns with an exists CE. */ /*==============================================================*/ if (lastNode->existsNand) { lastNode->existsNand = FALSE; lastNode->exists = TRUE; lastNode->negated = TRUE; lastNode->beginNandDepth = theLHS->endNandDepth; } theLHS->networkTest = NULL; tempNode = theLHS->bottom; theLHS->bottom = NULL; lastNode->bottom = tempNode; lastNode->endNandDepth = theLHS->endNandDepth; ReturnLHSParseNodes(theEnv,theLHS); theLHS = tempNode; } }
static struct lhsParseNode *RemoveUnneededSlots( void *theEnv, struct lhsParseNode *thePattern) { struct lhsParseNode *tempPattern = thePattern; struct lhsParseNode *lastPattern = NULL, *head = thePattern; struct expr *theTest; while (tempPattern != NULL) { /*=============================================================*/ /* A single field slot that has no pattern network expression */ /* associated with it can be removed (i.e. any value contained */ /* in this slot will satisfy the pattern being matched). */ /*=============================================================*/ if (((tempPattern->type == SF_WILDCARD) || (tempPattern->type == SF_VARIABLE)) && (tempPattern->networkTest == NULL)) { if (lastPattern != NULL) lastPattern->right = tempPattern->right; else head = tempPattern->right; tempPattern->right = NULL; ReturnLHSParseNodes(theEnv,tempPattern); if (lastPattern != NULL) tempPattern = lastPattern->right; else tempPattern = head; } /*=======================================================*/ /* A multifield variable or wildcard within a multifield */ /* slot can be removed if there are no other multifield */ /* variables or wildcards contained in the same slot */ /* (and the multifield has no expressions which must be */ /* evaluated in the fact pattern network). */ /*=======================================================*/ else if (((tempPattern->type == MF_WILDCARD) || (tempPattern->type == MF_VARIABLE)) && (tempPattern->multifieldSlot == FALSE) && (tempPattern->networkTest == NULL) && (tempPattern->multiFieldsBefore == 0) && (tempPattern->multiFieldsAfter == 0)) { if (lastPattern != NULL) lastPattern->right = tempPattern->right; else head = tempPattern->right; tempPattern->right = NULL; ReturnLHSParseNodes(theEnv,tempPattern); if (lastPattern != NULL) tempPattern = lastPattern->right; else tempPattern = head; } /*==================================================================*/ /* A multifield wildcard or variable contained in a multifield slot */ /* that contains no other multifield wildcards or variables, but */ /* does have an expression that must be evaluated, can be changed */ /* to a single field pattern node with the same expression. */ /*==================================================================*/ else if (((tempPattern->type == MF_WILDCARD) || (tempPattern->type == MF_VARIABLE)) && (tempPattern->multifieldSlot == FALSE) && (tempPattern->networkTest != NULL) && (tempPattern->multiFieldsBefore == 0) && (tempPattern->multiFieldsAfter == 0)) { tempPattern->type = SF_WILDCARD; lastPattern = tempPattern; tempPattern = tempPattern->right; } /*=========================================================*/ /* If we're dealing with a multifield slot with no slot */ /* restrictions, then treat the multfield slot as a single */ /* field slot, but attach a test which verifies that the */ /* slot contains a zero length multifield value. */ /*=========================================================*/ else if ((tempPattern->type == MF_WILDCARD) && (tempPattern->multifieldSlot == TRUE) && (tempPattern->bottom == NULL)) { tempPattern->type = SF_WILDCARD; tempPattern->networkTest = FactGenCheckZeroLength(theEnv,tempPattern->slotNumber); tempPattern->multifieldSlot = FALSE; lastPattern = tempPattern; tempPattern = tempPattern->right; } /*===================================================*/ /* Recursively call RemoveUnneededSlots for the slot */ /* restrictions contained within a multifield slot. */ /*===================================================*/ else if ((tempPattern->type == MF_WILDCARD) && (tempPattern->multifieldSlot == TRUE)) { /*=======================================================*/ /* Add an expression to the first pattern restriction in */ /* the multifield slot that determines whether or not */ /* the fact's slot value contains the minimum number of */ /* required fields to satisfy the pattern restrictions */ /* for this slot. The length check is place before any */ /* other tests, so that preceeding checks do not have to */ /* determine if there are enough fields in the slot to */ /* safely retrieve a value. */ /*=======================================================*/ theTest = FactGenCheckLength(theEnv,tempPattern->bottom); theTest = CombineExpressions(theEnv,theTest,tempPattern->bottom->networkTest); tempPattern->bottom->networkTest = theTest; /*=========================================================*/ /* Remove any unneeded pattern restrictions from the slot. */ /*=========================================================*/ tempPattern->bottom = RemoveUnneededSlots(theEnv,tempPattern->bottom); /*===========================================================*/ /* If the slot no longer contains any restrictions, then the */ /* multifield slot can be completely removed. In any case, */ /* move on to the next slot to be examined for removal. */ /*===========================================================*/ if (tempPattern->bottom == NULL) { if (lastPattern != NULL) lastPattern->right = tempPattern->right; else head = tempPattern->right; tempPattern->right = NULL; ReturnLHSParseNodes(theEnv,tempPattern); if (lastPattern != NULL) tempPattern = lastPattern->right; else tempPattern = head; } else { lastPattern = tempPattern; tempPattern = tempPattern->right; } } /*=======================================================*/ /* If none of the other tests for removing slots or slot */ /* restrictions apply, then move on to the next slot or */ /* slot restriction to be tested. */ /*=======================================================*/ else { lastPattern = tempPattern; tempPattern = tempPattern->right; } } /*======================================*/ /* Return the pattern with unused slots */ /* and slot restrictions removed. */ /*======================================*/ return(head); }
globle void FieldConversion( void *theEnv, struct lhsParseNode *theField, struct lhsParseNode *thePattern, struct nandFrame *theNandFrames) { int testInPatternNetwork = TRUE; struct lhsParseNode *patternPtr; struct expr *headOfPNExpression, *headOfJNExpression; struct expr *lastPNExpression, *lastJNExpression; struct expr *tempExpression; struct expr *patternNetTest = NULL; struct expr *joinNetTest = NULL; struct expr *constantSelector = NULL; struct expr *constantValue = NULL; /*==================================================*/ /* Consider a NULL pointer to be an internal error. */ /*==================================================*/ if (theField == NULL) { SystemError(theEnv,"ANALYSIS",3); EnvExitRouter(theEnv,EXIT_FAILURE); } /*========================================================*/ /* Determine if constant testing must be performed in the */ /* join network. Only possible when a field contains an */ /* or ('|') and references are made to variables outside */ /* the pattern. */ /*========================================================*/ if (theField->bottom != NULL) { if (theField->bottom->bottom != NULL) { testInPatternNetwork = AllVariablesInPattern(theField->bottom,theField->pattern); } } /*=============================================================*/ /* Extract pattern and join network expressions. Loop through */ /* the or'ed constraints of the field, extracting pattern and */ /* join network expressions and adding them to a running list. */ /*=============================================================*/ headOfPNExpression = lastPNExpression = NULL; headOfJNExpression = lastJNExpression = NULL; for (patternPtr = theField->bottom; patternPtr != NULL; patternPtr = patternPtr->bottom) { /*=============================================*/ /* Extract pattern and join network tests from */ /* the or'ed constraint being examined. */ /*=============================================*/ ExtractAnds(theEnv,patternPtr,testInPatternNetwork,&patternNetTest,&joinNetTest, &constantSelector,&constantValue,theNandFrames); /*=============================================================*/ /* Constant hashing is only used in the pattern network if the */ /* field doesn't contain an or'ed constraint. For example, the */ /* constaint "red | blue" can not use hashing. */ /*=============================================================*/ if (constantSelector != NULL) { if ((patternPtr == theField->bottom) && (patternPtr->bottom == NULL)) { theField->constantSelector = constantSelector; theField->constantValue = constantValue; } else { ReturnExpression(theEnv,constantSelector); ReturnExpression(theEnv,constantValue); ReturnExpression(theEnv,theField->constantSelector); ReturnExpression(theEnv,theField->constantValue); theField->constantSelector = NULL; theField->constantValue = NULL; } } /*=====================================================*/ /* Add the new pattern network expressions to the list */ /* of pattern network expressions being constructed. */ /*=====================================================*/ if (patternNetTest != NULL) { if (lastPNExpression == NULL) { headOfPNExpression = patternNetTest; } else { lastPNExpression->nextArg = patternNetTest; } lastPNExpression = patternNetTest; } /*==================================================*/ /* Add the new join network expressions to the list */ /* of join network expressions being constructed. */ /*==================================================*/ if (joinNetTest != NULL) { if (lastJNExpression == NULL) { headOfJNExpression = joinNetTest; } else { lastJNExpression->nextArg = joinNetTest; } lastJNExpression = joinNetTest; } } /*==========================================================*/ /* If there was more than one expression generated from the */ /* or'ed field constraints for the pattern network, then */ /* enclose the expressions within an "or" function call. */ /*==========================================================*/ if ((headOfPNExpression != NULL) ? (headOfPNExpression->nextArg != NULL) : FALSE) { tempExpression = GenConstant(theEnv,FCALL,ExpressionData(theEnv)->PTR_OR); tempExpression->argList = headOfPNExpression; headOfPNExpression = tempExpression; } /*==========================================================*/ /* If there was more than one expression generated from the */ /* or'ed field constraints for the join network, then */ /* enclose the expressions within an "or" function call. */ /*==========================================================*/ if ((headOfJNExpression != NULL) ? (headOfJNExpression->nextArg != NULL) : FALSE) { tempExpression = GenConstant(theEnv,FCALL,ExpressionData(theEnv)->PTR_OR); tempExpression->argList = headOfJNExpression; headOfJNExpression = tempExpression; } /*===============================================================*/ /* If the field constraint binds a variable that was previously */ /* bound somewhere in the LHS of the rule, then generate an */ /* expression to compare this binding occurrence of the variable */ /* to the previous binding occurrence. */ /*===============================================================*/ if (((theField->type == MF_VARIABLE) || (theField->type == SF_VARIABLE)) && (theField->referringNode != NULL)) { /*================================================================*/ /* If the previous variable reference is within the same pattern, */ /* then the variable comparison can occur in the pattern network. */ /*================================================================*/ if (theField->referringNode->pattern == theField->pattern) { tempExpression = GenPNVariableComparison(theEnv,theField,theField->referringNode); headOfPNExpression = CombineExpressions(theEnv,tempExpression,headOfPNExpression); } /*====================================*/ /* Otherwise, the variable comparison */ /* must occur in the join network. */ /*====================================*/ else if (theField->referringNode->pattern > 0) { AddNandUnification(theEnv,theField,theNandFrames); /*====================================*/ /* Generate an expression to test the */ /* variable in a non-nand join. */ /*====================================*/ tempExpression = GenJNVariableComparison(theEnv,theField,theField->referringNode,FALSE); headOfJNExpression = CombineExpressions(theEnv,tempExpression,headOfJNExpression); /*==========================*/ /* Generate the hash index. */ /*==========================*/ if (theField->patternType->genGetPNValueFunction != NULL) { tempExpression = (*theField->patternType->genGetPNValueFunction)(theEnv,theField); thePattern->rightHash = AppendExpressions(tempExpression,thePattern->rightHash); } if (theField->referringNode->patternType->genGetJNValueFunction) { tempExpression = (*theField->referringNode->patternType->genGetJNValueFunction)(theEnv,theField->referringNode,LHS); thePattern->leftHash = AppendExpressions(tempExpression,thePattern->leftHash); } } } /*======================================================*/ /* Attach the pattern network expressions to the field. */ /*======================================================*/ theField->networkTest = headOfPNExpression; /*=====================================================*/ /* Attach the join network expressions to the pattern. */ /*=====================================================*/ thePattern->networkTest = CombineExpressions(theEnv,thePattern->networkTest,headOfJNExpression); }
static int TestCEAnalysis( void *theEnv, struct lhsParseNode *patternPtr, struct lhsParseNode *theExpression, int secondary, int *errorFlag, struct nandFrame *theNandFrames) { struct lhsParseNode *rv, *theList, *tempList, *tempRight; if (theExpression == NULL) return FALSE; /*=====================================================*/ /* Verify that all variables were referenced properly. */ /*=====================================================*/ rv = CheckExpression(theEnv,theExpression,NULL,(int) patternPtr->whichCE,NULL,0); /*====================================================================*/ /* Temporarily disconnect the right nodes. If this is a pattern node */ /* with an attached test CE, we only want to propagate to following */ /* patterns, not to nodes of this pattern which preceded the test CE. */ /*====================================================================*/ tempRight = patternPtr->right; patternPtr->right = NULL; /*=========================================================*/ /* Determine the type and value constraints implied by the */ /* expression and propagate these constraints to other */ /* variables in the LHS. For example, the expression */ /* (+ ?x 1) implies that ?x is a number. */ /*=========================================================*/ theList = GetExpressionVarConstraints(theEnv,theExpression); for (tempList = theList; tempList != NULL; tempList = tempList->right) { if (PropagateVariableDriver(theEnv,patternPtr,patternPtr,NULL,SF_VARIABLE, (SYMBOL_HN *) tempList->value,tempList,FALSE,TEST_CE)) { ReturnLHSParseNodes(theEnv,theList); patternPtr->right = tempRight; return(TRUE); } } ReturnLHSParseNodes(theEnv,theList); /*============================*/ /* Reconnect the right nodes. */ /*============================*/ patternPtr->right = tempRight; /*========================================================*/ /* If the variables in the expression were all referenced */ /* properly, then create the expression to use in the */ /* join network. */ /*========================================================*/ if (rv != NULL) { *errorFlag = TRUE; } else if (secondary) { patternPtr->secondaryNetworkTest = CombineExpressions(theEnv,patternPtr->secondaryNetworkTest,GetvarReplace(theEnv,theExpression,FALSE,theNandFrames)); } else { patternPtr->networkTest = CombineExpressions(theEnv,patternPtr->networkTest,GetvarReplace(theEnv,theExpression,FALSE,theNandFrames)); } return FALSE; }