📄 analysis.c
字号:
theVariable = (struct symbolHashNode *) thePattern->value; if (thePattern->derivedConstraints) RemoveConstraint(thePattern->constraints); theConstraints = GetConstraintRecord(); thePattern->constraints = theConstraints; thePattern->constraints->anyAllowed = CLIPS_FALSE; thePattern->constraints->instanceAddressesAllowed = CLIPS_TRUE; thePattern->constraints->factAddressesAllowed = CLIPS_TRUE; thePattern->derivedConstraints = CLIPS_TRUE; } /*===================================================*/ /* Otherwise a pattern variable is being propagated. */ /*===================================================*/ else { theType = thePattern->type; theVariable = (struct symbolHashNode *) thePattern->value; } /*===================================================*/ /* Propagate the variable location to any additional */ /* fields associated with the binding variable. */ /*===================================================*/ if (thePattern->type != PATTERN_CE) { PropagateVariableToNodes(thePattern->bottom,theType,theVariable, thePattern,patternHead->beginNandDepth, CLIPS_TRUE,CLIPS_FALSE); if (ProcessField(thePattern,multifieldHeader,patternHead)) { return(CLIPS_TRUE); } } /*=================================================================*/ /* Propagate the constraints to other fields, slots, and patterns. */ /*=================================================================*/ return(PropagateVariableDriver(patternHead,thePattern,multifieldHeader,theType, theVariable,thePattern,CLIPS_TRUE)); } /*******************************************//* PropagateVariableDriver: Driver routine *//* for propagating variable references. *//*******************************************/static int PropagateVariableDriver(patternHead,theNode,multifieldHeader, theType,variableName,theReference,assignReference) struct lhsParseNode *patternHead, *theNode, *multifieldHeader; int theType; struct symbolHashNode *variableName; struct lhsParseNode *theReference; int assignReference; { /*===================================================*/ /* Propagate the variable location to any additional */ /* constraints associated with the binding variable. */ /*===================================================*/ if (multifieldHeader != NULL) { if (PropagateVariableToNodes(multifieldHeader->right,theType,variableName, theReference,patternHead->beginNandDepth,assignReference,CLIPS_FALSE)) { VariableMixingErrorMessage(variableName); return(CLIPS_TRUE); } } /*========================================================*/ /* Propagate the variable location to fields/slots in the */ /* same pattern which appear after the binding variable. */ /*========================================================*/ if (PropagateVariableToNodes(theNode->right,theType,variableName,theReference, patternHead->beginNandDepth,assignReference,CLIPS_FALSE)) { VariableMixingErrorMessage(variableName); return(CLIPS_TRUE); } /*======================================================*/ /* Propagate values to other patterns if the pattern in */ /* which the variable is found is not a "not" CE or the */ /* last pattern within a nand CE. */ /*======================================================*/ if (((patternHead->type == PATTERN_CE) || (patternHead->type == TEST_CE)) && (patternHead->negated == CLIPS_FALSE) && (patternHead->beginNandDepth <= patternHead->endNandDepth)) { int ignoreVariableMixing; /*============================================================*/ /* If the variables are propagated from a test CE, then don't */ /* check for mixing of single and multifield variables (since */ /* previously bound multifield variables typically have the $ */ /* removed when passed as an argument to a function unless */ /* sequence expansion is desired). */ /*============================================================*/ if (patternHead->type == TEST_CE) ignoreVariableMixing = CLIPS_TRUE; else ignoreVariableMixing = CLIPS_FALSE; /*==========================*/ /* Propagate the reference. */ /*==========================*/ if (PropagateVariableToNodes(patternHead->bottom,theType,variableName,theReference, patternHead->beginNandDepth,assignReference, ignoreVariableMixing)) { VariableMixingErrorMessage(variableName); return(CLIPS_TRUE); } } /*==============================================*/ /* Return FALSE to indicate that no errors were */ /* generated by the variable propagation. */ /*==============================================*/ return(CLIPS_FALSE); } /********************************************************//* ProcessField: Processes a field or slot of a pattern *//* which does not contain a binding variable. *//********************************************************/static int ProcessField(thePattern,multifieldHeader,patternHead) struct lhsParseNode *thePattern, *multifieldHeader, *patternHead; { struct lhsParseNode *theList, *tempList; /*====================================================*/ /* Nothing needs to be done for the node representing */ /* the entire pattern. Return FALSE to indicate that */ /* no errors were generated. */ /*====================================================*/ if (thePattern->type == PATTERN_CE) return(CLIPS_FALSE); /*====================================================================*/ /* Derive a set of constraints based on values found in the slot or */ /* field. For example, if a slot can only contain the values 1, 2, or */ /* 3, the field constraint ~2 would generate a constraint record that */ /* only allows the value 1 or 3. Once generated, the constraints are */ /* propagated to other slots and fields. */ /*====================================================================*/ theList = DeriveVariableConstraints(thePattern); for (tempList = theList; tempList != NULL; tempList = tempList->right) { if (PropagateVariableDriver(patternHead,thePattern,multifieldHeader,tempList->type, tempList->value,tempList,CLIPS_FALSE)) { ReturnLHSParseNodes(theList); return(CLIPS_TRUE); } } ReturnLHSParseNodes(theList); /*===========================================================*/ /* Check for "variable referenced, but not previously bound" */ /* errors. Return TRUE if this type of error is detected. */ /*===========================================================*/ if (UnboundVariablesInPattern(thePattern,(int) patternHead->whichCE)) { return(CLIPS_TRUE); } /*==================================================*/ /* Check for constraint errors for this slot/field. */ /* If the slot/field has unmatchable constraints */ /* then return TRUE to indicate a semantic error. */ /*==================================================*/ if (ProcessConnectedConstraints(thePattern,multifieldHeader,patternHead)) { return(CLIPS_TRUE); } /*==============================================================*/ /* Convert the slot/field constraint to a series of expressions */ /* that will be used in the pattern and join networks. */ /*==============================================================*/ FieldConversion(thePattern,patternHead); /*=========================================================*/ /* Return FALSE to indicate that no errors were generated. */ /*=========================================================*/ return(CLIPS_FALSE); } /*************************************************************//* PropagateVariableToNodes: Propagates variable references *//* to all other variables within the semantic scope of the *//* bound variable. That is, a variable reference cannot be *//* beyond an enclosing not/and CE combination. The *//* restriction of propagating variables beyond an enclosing *//* not CE is handled within the GetVariables function. *//*************************************************************/static int PropagateVariableToNodes(theNode,theType,variableName, theReference,startDepth, assignReference,ignoreVariableTypes) struct lhsParseNode *theNode; int theType; struct symbolHashNode *variableName; struct lhsParseNode *theReference; int startDepth; int assignReference; int ignoreVariableTypes; { struct constraintRecord *tempConstraints; /*===========================================*/ /* Traverse the nodes using the bottom link. */ /*===========================================*/ while (theNode != NULL) { /*==================================================*/ /* If the field/slot contains a predicate or return */ /* value constraint, then propagate the variable to */ /* the expression associated with that constraint. */ /*==================================================*/ if (theNode->expression != NULL) { PropagateVariableToNodes(theNode->expression,theType,variableName, theReference,startDepth,assignReference,CLIPS_TRUE); } /*======================================================*/ /* If the field/slot is a single or multifield variable */ /* with the same name as the propagated variable, */ /* then propagate the variable location to this node. */ /*======================================================*/ else if (((theNode->type == SF_VARIABLE) || (theNode->type == MF_VARIABLE)) && (theNode->value == (VOID *) variableName)) { /*======================================================*/ /* Check for mixing of single and multifield variables. */ /*======================================================*/ if (ignoreVariableTypes == CLIPS_FALSE) { if (((theType == SF_VARIABLE) && (theNode->type == MF_VARIABLE)) || ((theType == MF_VARIABLE) && (theNode->type == SF_VARIABLE))) { return(CLIPS_TRUE); } } /*======================================================*/ /* Intersect the propagated variable's constraints with */ /* the current constraints for this field/slot. */ /*======================================================*/ if ((theReference->constraints != NULL) && (! theNode->negated)) { tempConstraints = theNode->constraints; theNode->constraints = IntersectConstraints(theReference->constraints, tempConstraints); if (theNode->derivedConstraints) { RemoveConstraint(tempConstraints); } theNode->derivedConstraints = CLIPS_TRUE; } /*=====================================================*/ /* Don't propagate the variable if it originates from */ /* a different type of pattern object and the variable */ /* reference has already been resolved. */ /*=====================================================*/ if (assignReference) { if (theNode->referringNode == NULL) { theNode->referringNode = theReference; } else if (theReference->pattern == theNode->pattern) { theNode->referringNode = theReference; } else if (theReference->patternType == theNode->patternType) { theNode->referringNode = theReference; } } } /*========================================================*/ /* If the field/slot is the node representing the entire */ /* pattern, then propagate the variable location to the */ /* fact address associated with the pattern (if it is the */ /* same variable name). */ /*========================================================*/ else if ((theNode->type == PATTERN_CE) && (theNode->value == (VOID *) variableName) && (assignReference == CLIPS_TRUE)) { if (theType == MF_VARIABLE) return(CLIPS_TRUE); theNode->referringNode = theReference; } /*=====================================================*/ /* Propagate the variable to other fields contained */ /* within the same & field constraint or same pattern. */ /*=====================================================*/ if (theNode->right != NULL) { if (PropagateVariableToNodes(theNode->right,theType,variableName, theReference,startDepth,assignReference,ignoreVariableTypes)) { return(CLIPS_TRUE); } } /*============================================================*/ /* Propagate the variable to other patterns within the same */ /* semantic scope (if dealing with the node for an entire */ /* pattern) or to the next | field constraint within a field. */ /*============================================================*/ if ((theNode->type == PATTERN_CE) || (theNode->type == TEST_CE)) { if (theNode->endNandDepth < startDepth) theNode = NULL; else theNode = theNode->bottom; } else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -