📄 pattern.c
字号:
tempNode3->withinMultifieldSlot = CLIPS_TRUE; } } /*=======================================*/ /* Calculate the running total of single */ /* and multifield constraints. */ /*=======================================*/ if ((tempNode1->type == SF_VARIABLE) || (tempNode1->type == SF_WILDCARD)) { runningSingleFields++; } else { runningMultiFields++; } } } /*******************************************************************//* ConjuctiveRestrictionParse: Parses a single constraint field in *//* a pattern that is not a single field wildcard, multifield *//* wildcard, or multifield variable. The field may consist of a *//* number of subfields tied together using the & connective *//* constraint and/or the | connective constraint. *//* *//* <connected-constraint> *//* ::= <single-constraint> | *//* <single-constraint> & <connected-constraint> | *//* <single-constraint> | <connected-constraint> *//*******************************************************************/static struct lhsParseNode *ConjuctiveRestrictionParse(readSource,theToken,error) char *readSource; struct token *theToken; int *error; { struct lhsParseNode *bindNode; struct lhsParseNode *theNode, *nextOr, *nextAnd; int connectorType; /*=====================================*/ /* Get the first node and determine if */ /* it is a binding variable. */ /*=====================================*/ theNode = LiteralRestrictionParse(readSource,theToken,error); if (*error == CLIPS_TRUE) { return(NULL); } GetToken(readSource,theToken); if (((theNode->type == SF_VARIABLE) || (theNode->type == MF_VARIABLE)) && (theNode->negated == CLIPS_FALSE) && (theToken->type != OR_CONSTRAINT)) { theNode->bindingVariable = CLIPS_TRUE; bindNode = theNode; nextOr = NULL; nextAnd = NULL; } else { bindNode = GetLHSParseNode(); if (theNode->type == MF_VARIABLE) bindNode->type = MF_WILDCARD; else bindNode->type = SF_WILDCARD; bindNode->negated = CLIPS_FALSE; bindNode->bottom = theNode; nextOr = theNode; nextAnd = theNode; } /*===================================*/ /* Process the connected constraints */ /* within the constraint */ /*===================================*/ while ((theToken->type == OR_CONSTRAINT) || (theToken->type == AND_CONSTRAINT)) { /*==========================*/ /* Get the next constraint. */ /*==========================*/ connectorType = theToken->type; GetToken(readSource,theToken); theNode = LiteralRestrictionParse(readSource,theToken,error); if (*error == CLIPS_TRUE) { ReturnLHSParseNodes(bindNode); return(NULL); } /*=======================================*/ /* Attach the new constraint to the list */ /* of constraints for this field. */ /*=======================================*/ if (connectorType == OR_CONSTRAINT) { if (nextOr == NULL) { bindNode->bottom = theNode; } else { nextOr->bottom = theNode; } nextOr = theNode; nextAnd = theNode; } else if (connectorType == AND_CONSTRAINT) { if (nextAnd == NULL) { bindNode->bottom = theNode; nextOr = theNode; } else { nextAnd->right = theNode; } nextAnd = theNode; } else { CLIPSSystemError("RULEPSR",1); ExitCLIPS(4); } /*==================================================*/ /* Determine if any more restrictions are connected */ /* to the current list of restrictions. */ /*==================================================*/ GetToken(readSource,theToken); } /*==========================================*/ /* Check for illegal mixing of single and */ /* multifield values within the constraint. */ /*==========================================*/ if (CheckForVariableMixing(bindNode)) { *error = CLIPS_TRUE; ReturnLHSParseNodes(bindNode); return(NULL); } /*========================*/ /* Return the constraint. */ /*========================*/ return(bindNode); } /*****************************************************//* CheckForVariableMixing: Checks a field constraint *//* to determine if single and multifield variables *//* are illegally mixed within it. *//*****************************************************/static int CheckForVariableMixing(theRestriction) struct lhsParseNode *theRestriction; { struct lhsParseNode *tempRestriction; CONSTRAINT_RECORD *theConstraint; int multifield = CLIPS_FALSE; int singlefield = CLIPS_FALSE; int constant = CLIPS_FALSE; int singleReturnValue = CLIPS_FALSE; int multiReturnValue = CLIPS_FALSE; /*================================================*/ /* If the constraint contains a binding variable, */ /* determine whether it is a single field or */ /* multifield variable. */ /*================================================*/ if (theRestriction->type == SF_VARIABLE) singlefield = CLIPS_TRUE; else if (theRestriction->type == MF_VARIABLE) multifield = CLIPS_TRUE; /*===========================================*/ /* Loop through each of the or (|) connected */ /* constraints within the constraint. */ /*===========================================*/ for (theRestriction = theRestriction->bottom; theRestriction != NULL; theRestriction = theRestriction->bottom) { /*============================================*/ /* Loop through each of the and (&) connected */ /* constraints within the or (|) constraint. */ /*============================================*/ for (tempRestriction = theRestriction; tempRestriction != NULL; tempRestriction = tempRestriction->right) { /*=====================================================*/ /* Determine if the constraint contains a single field */ /* variable, multifield variable, constant (a single */ /* field), a return value constraint of a function */ /* returning a single field value, or a return value */ /* constraint of a function returning a multifield */ /* value. */ /*=====================================================*/ if (tempRestriction->type == SF_VARIABLE) singlefield = CLIPS_TRUE; else if (tempRestriction->type == MF_VARIABLE) multifield = CLIPS_TRUE; else if (ConstantType(tempRestriction->type)) constant = CLIPS_TRUE; else if (tempRestriction->type == RETURN_VALUE_CONSTRAINT) { theConstraint = FunctionCallToConstraintRecord(tempRestriction->expression->value); if (theConstraint->anyAllowed) { /* Do nothing. */ } else if (theConstraint->multifieldsAllowed) multiReturnValue = CLIPS_TRUE; else singleReturnValue = CLIPS_TRUE; RemoveConstraint(theConstraint); } } } /*================================================================*/ /* Using a single field value (a single field variable, constant, */ /* or function returning a single field value) together with a */ /* multifield value (a multifield variable or function returning */ /* a multifield value) is illegal. Return TRUE if this occurs. */ /*================================================================*/ if ((singlefield || constant || singleReturnValue) && (multifield || multiReturnValue)) { PrintErrorID("PATTERN",2,CLIPS_TRUE); PrintCLIPS(WERROR,"Single and multifield constraints cannot be mixed in a field constraint\n"); return(CLIPS_TRUE); } /*=======================================*/ /* Otherwise return FALSE to indicate no */ /* illegal variable mixing was detected. */ /*=======================================*/ return(CLIPS_FALSE); }/***********************************************************//* LiteralRestrictionParse: Parses a single constraint. *//* The constraint may be a literal constraint, a *//* predicate constraint, a return value constraint, or a *//* variable constraint. The constraints may also be *//* negated using the ~ connective constraint. *//* *//* <single-constraint> ::= <term> | ~<term> *//* *//* <term> ::= <constant> | *//* <single-field-variable> | *//* <multi-field-variable> | *//* :<function-call> | *//* =<function-call> *//***********************************************************/static struct lhsParseNode *LiteralRestrictionParse(readSource,theToken,error) char *readSource; struct token *theToken; int *error; { struct lhsParseNode *topNode; struct expr *theExpression; /*============================================*/ /* Create a node to represent the constraint. */ /*============================================*/ topNode = GetLHSParseNode(); /*=================================================*/ /* Determine if the constraint has a '~' preceding */ /* it. If it does, then the field is negated */ /* (e.g. ~red means "not the constant red." */ /*=================================================*/ if (theToken->type == NOT_CONSTRAINT) { GetToken(readSource,theToken); topNode->negated = CLIPS_TRUE; } else { topNode->negated = CLIPS_FALSE; } /*===========================================*/ /* Determine if the constraint is one of the */ /* recognized types. These are ?variables, */ /* symbols, strings, numbers, :(expression), */ /* and =(expression). */ /*===========================================*/ topNode->type = theToken->type; /*============================================*/ /* Any symbol is valid, but an = signifies a */ /* return value constraint and an : signifies */ /* a predicate constraint. */ /*============================================*/ if (theToken->type == SYMBOL) { /*==============================*/ /* If the symbol is an =, parse */ /* a return value constraint. */ /*==============================*/ if (strcmp(ValueToString(theToken->value),"=") == 0) { theExpression = Function0Parse(readSource); if (theExpression == NULL) { *error = CLIPS_TRUE; ReturnLHSParseNodes(topNode); return(NULL); } topNode->type = RETURN_VALUE_CONSTRAINT; topNode->expression = ExpressionToLHSParseNodes(theExpression); ReturnExpression(theExpression); } /*=============================*/ /* If the symbol is a :, parse */ /* a predicate constraint. */ /*=============================*/ else if (strcmp(ValueToString(theToken->value),":") == 0) { theExpression = Function0Parse(readSource); if (theExpression == NULL) { *error = CLIPS_TRUE; ReturnLHSParseNodes(topNode); return(NULL); } topNode->type = PREDICATE_CONSTRAINT; topNode->expression = ExpressionToLHSParseNodes(theExpression); ReturnExpression(theExpression); } /*==============================================*/ /* Otherwise, treat the constraint as a symbol. */ /*==============================================*/ else { topNode->value = theToken->value; } } /*=====================================================*/ /* Single and multifield variables and float, integer, */ /* string, and instance name constants are also valid. */ /*=====================================================*/ else if ((theToken->type == SF_VARIABLE) || (theToken->type == MF_VARIABLE) || (theToken->type == FLOAT) || (theToken->type == INTEGER) || (theToken->type == STRING) || (theToken->type == INSTANCE_NAME)) { topNode->value = theToken->value; } /*===========================*/ /* Anything else is invalid. */ /*===========================*/ else { SyntaxErrorMessage("defrule"); *error = CLIPS_TRUE; ReturnLHSParseNodes(topNode); return(NULL); } /*===============================*/ /* Return the parsed constraint. */ /*===============================*/ return(topNode); }#endif /* (! RUN_TIME) && (! BLOAD_ONLY) */#endif /* DEFRULE_CONSTRUCT */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -