/************************************************************** NAME : NewSlot DESCRIPTION : Allocates and initalizes a new slot structure INPUTS : The symbolic name of the new slot RETURNS : The address of the new slot SIDE EFFECTS : None NOTES : Also adds symbols of the form get-<name> and put-<name> for slot accessors **************************************************************/ static SlotDescriptor *NewSlot( Environment *theEnv, CLIPSLexeme *name) { SlotDescriptor *slot; slot = get_struct(theEnv,slotDescriptor); slot->dynamicDefault = 1; slot->defaultSpecified = 0; slot->noDefault = 0; #if DEFRULE_CONSTRUCT slot->reactive = 1; #endif slot->noInherit = 0; slot->noWrite = 0; slot->initializeOnly = 0; slot->shared = 0; slot->multiple = 0; slot->composite = 0; slot->sharedCount = 0; slot->publicVisibility = 0; slot->createReadAccessor = false; slot->createWriteAccessor = false; slot->overrideMessageSpecified = 0; slot->cls = NULL; slot->defaultValue = NULL; slot->constraint = GetConstraintRecord(theEnv); slot->slotName = AddSlotName(theEnv,name,0,false); slot->overrideMessage = slot->slotName->putHandlerName; IncrementLexemeCount(slot->overrideMessage); return(slot); }
/************************************************************** NAME : NewSlot DESCRIPTION : Allocates and initalizes a new slot structure INPUTS : The symbolic name of the new slot RETURNS : The address of the new slot SIDE EFFECTS : None NOTES : Also adds symbols of the form get-<name> and put-<name> for slot accessors **************************************************************/ static SLOT_DESC *NewSlot( void *theEnv, EXEC_STATUS, SYMBOL_HN *name) { SLOT_DESC *slot; slot = get_struct(theEnv,execStatus,slotDescriptor); slot->dynamicDefault = 1; slot->defaultSpecified = 0; slot->noDefault = 0; #if DEFRULE_CONSTRUCT slot->reactive = 1; #endif slot->noInherit = 0; slot->noWrite = 0; slot->initializeOnly = 0; slot->shared = 0; slot->multiple = 0; slot->composite = 0; slot->sharedCount = 0; slot->publicVisibility = 0; slot->createReadAccessor = FALSE; slot->createWriteAccessor = FALSE; slot->overrideMessageSpecified = 0; slot->cls = NULL; slot->defaultValue = NULL; slot->constraint = GetConstraintRecord(theEnv,execStatus); slot->slotName = AddSlotName(theEnv,execStatus,name,0,FALSE); slot->overrideMessage = slot->slotName->putHandlerName; IncrementSymbolCount(slot->overrideMessage); return(slot); }
CONSTRAINT_RECORD *ArgumentTypeToConstraintRecord2( void *theEnv, unsigned bitTypes) { CONSTRAINT_RECORD *rv; rv = GetConstraintRecord(theEnv); rv->anyAllowed = false; if (bitTypes & VOID_TYPE) { rv->voidAllowed = true; } if (bitTypes & FLOAT_TYPE) { rv->floatsAllowed = true; } if (bitTypes & INTEGER_TYPE) { rv->integersAllowed = true; } if (bitTypes & SYMBOL_TYPE) { rv->symbolsAllowed = true; } if (bitTypes & STRING_TYPE) { rv->stringsAllowed = true; } if (bitTypes & MULTIFIELD_TYPE) { rv->multifieldsAllowed = true; } if (bitTypes & EXTERNAL_ADDRESS_TYPE) { rv->externalAddressesAllowed = true; } if (bitTypes & FACT_ADDRESS_TYPE) { rv->factAddressesAllowed = true; } if (bitTypes & INSTANCE_ADDRESS_TYPE) { rv->instanceAddressesAllowed = true; } if (bitTypes & INSTANCE_NAME_TYPE) { rv->instanceNamesAllowed = true; } if (bitTypes & BOOLEAN_TYPE) { rv->symbolsAllowed = true; } if (bitTypes == ANY_TYPE) { rv->anyAllowed = true; } return(rv); }
struct lhsParseNode *RestrictionParse( char *readSource, struct token *theToken, int multifieldSlot, struct symbolHashNode *theSlot, int slotNumber, CONSTRAINT_RECORD *theConstraints, int position) { struct lhsParseNode *topNode = NULL, *lastNode = NULL, *nextNode; int numberOfSingleFields = 0; int numberOfMultifields = 0; int startPosition = position; int error = FALSE; CONSTRAINT_RECORD *tempConstraints; /*==================================================*/ /* Keep parsing fields until a right parenthesis is */ /* encountered. This will either indicate the end */ /* of an instance or deftemplate slot or the end of */ /* an ordered fact. */ /*==================================================*/ while (theToken->type != RPAREN) { /*========================================*/ /* Look for either a single or multifield */ /* wildcard or a conjuctive restriction. */ /*========================================*/ if ((theToken->type == SF_WILDCARD) || (theToken->type == MF_WILDCARD)) { nextNode = GetLHSParseNode(); nextNode->type = theToken->type; nextNode->negated = FALSE; GetToken(readSource,theToken); } else { nextNode = ConjuctiveRestrictionParse(readSource,theToken,&error); if (nextNode == NULL) { ReturnLHSParseNodes(topNode); return(NULL); } } /*========================================================*/ /* Fix up the pretty print representation of a multifield */ /* slot so that the fields don't run together. */ /*========================================================*/ if ((theToken->type != RPAREN) && (multifieldSlot == TRUE)) { PPBackup(); SavePPBuffer(" "); SavePPBuffer(theToken->printForm); } /*========================================*/ /* Keep track of the number of single and */ /* multifield restrictions encountered. */ /*========================================*/ if ((nextNode->type == SF_WILDCARD) || (nextNode->type == SF_VARIABLE)) { numberOfSingleFields++; } else { numberOfMultifields++; } /*===================================*/ /* Assign the slot name and indices. */ /*===================================*/ nextNode->slot = theSlot; nextNode->slotNumber = slotNumber; nextNode->index = position++; /*==============================================*/ /* If we're not dealing with a multifield slot, */ /* attach the constraints directly to the node */ /* and return. */ /*==============================================*/ if (! multifieldSlot) { if (theConstraints == NULL) { if (nextNode->type == SF_VARIABLE) { nextNode->constraints = GetConstraintRecord(); } else nextNode->constraints = NULL; } else nextNode->constraints = theConstraints; return(nextNode); } /*====================================================*/ /* Attach the restriction to the list of restrictions */ /* already parsed for this slot or ordered fact. */ /*====================================================*/ if (lastNode == NULL) topNode = nextNode; else lastNode->right = nextNode; lastNode = nextNode; } /*=====================================================*/ /* Once we're through parsing, check to make sure that */ /* a single field slot was given a restriction. If the */ /* following test fails, then we know we're dealing */ /* with a multifield slot. */ /*=====================================================*/ if ((topNode == NULL) && (! multifieldSlot)) { SyntaxErrorMessage("defrule"); return(NULL); } /*===============================================*/ /* Loop through each of the restrictions in the */ /* list of restrictions for the multifield slot. */ /*===============================================*/ for (nextNode = topNode; nextNode != NULL; nextNode = nextNode->right) { /*===================================================*/ /* Assign a constraint record to each constraint. If */ /* the slot has an explicit constraint, then copy */ /* this and store it with the constraint. Otherwise, */ /* create a constraint record for a single field */ /* constraint and skip the constraint modifications */ /* for a multifield constraint. */ /*===================================================*/ if (theConstraints == NULL) { if (nextNode->type == SF_VARIABLE) { nextNode->constraints = GetConstraintRecord(); } else { continue; } } else { nextNode->constraints = CopyConstraintRecord(theConstraints); } /*==========================================*/ /* Remove the min and max field constraints */ /* for the entire slot from the constraint */ /* record for this single constraint. */ /*==========================================*/ ReturnExpression(nextNode->constraints->minFields); ReturnExpression(nextNode->constraints->maxFields); nextNode->constraints->minFields = GenConstant(SYMBOL,NegativeInfinity); nextNode->constraints->maxFields = GenConstant(SYMBOL,PositiveInfinity); nextNode->derivedConstraints = TRUE; /*====================================================*/ /* If we're not dealing with a multifield constraint, */ /* then no further modifications are needed to the */ /* min and max constraints for this constraint. */ /*====================================================*/ if ((nextNode->type != MF_WILDCARD) && (nextNode->type != MF_VARIABLE)) { continue; } /*==========================================================*/ /* Create a separate constraint record to keep track of the */ /* cardinality information for this multifield constraint. */ /*==========================================================*/ tempConstraints = GetConstraintRecord(); SetConstraintType(MULTIFIELD,tempConstraints); tempConstraints->singlefieldsAllowed = FALSE; tempConstraints->multifield = nextNode->constraints; nextNode->constraints = tempConstraints; /*=====================================================*/ /* Adjust the min and max field values for this single */ /* multifield constraint based on the min and max */ /* fields for the entire slot and the number of single */ /* field values contained in the slot. */ /*=====================================================*/ if (theConstraints->maxFields->value != PositiveInfinity) { ReturnExpression(tempConstraints->maxFields); tempConstraints->maxFields = GenConstant(INTEGER,AddLong(ValueToLong(theConstraints->maxFields->value) - numberOfSingleFields)); } if ((numberOfMultifields == 1) && (theConstraints->minFields->value != NegativeInfinity)) { ReturnExpression(tempConstraints->minFields); tempConstraints->minFields = GenConstant(INTEGER,AddLong(ValueToLong(theConstraints->minFields->value) - numberOfSingleFields)); } } /*================================================*/ /* If a multifield slot is being parsed, place a */ /* node on top of the list of constraints parsed. */ /*================================================*/ if (multifieldSlot) { nextNode = GetLHSParseNode(); nextNode->type = MF_WILDCARD; nextNode->multifieldSlot = TRUE; nextNode->bottom = topNode; nextNode->slot = theSlot; nextNode->slotNumber = slotNumber; nextNode->index = startPosition; nextNode->constraints = theConstraints; topNode = nextNode; TallyFieldTypes(topNode->bottom); } /*=================================*/ /* Return the list of constraints. */ /*=================================*/ return(topNode); }
globle CONSTRAINT_RECORD *ArgumentTypeToConstraintRecord( void *theEnv, EXEC_STATUS, int theRestriction) { CONSTRAINT_RECORD *rv; rv = GetConstraintRecord(theEnv,execStatus); rv->anyAllowed = FALSE; switch (theRestriction) { case 'a': rv->externalAddressesAllowed = TRUE; break; case 'e': rv->symbolsAllowed = TRUE; rv->instanceNamesAllowed = TRUE; rv->instanceAddressesAllowed = TRUE; break; case 'd': case 'f': rv->floatsAllowed = TRUE; break; case 'g': rv->integersAllowed = TRUE; rv->floatsAllowed = TRUE; rv->symbolsAllowed = TRUE; break; case 'h': rv->factAddressesAllowed = TRUE; rv->integersAllowed = TRUE; rv->symbolsAllowed = TRUE; rv->instanceNamesAllowed = TRUE; rv->instanceAddressesAllowed = TRUE; break; case 'i': case 'l': rv->integersAllowed = TRUE; break; case 'j': rv->symbolsAllowed = TRUE; rv->stringsAllowed = TRUE; rv->instanceNamesAllowed = TRUE; break; case 'k': rv->symbolsAllowed = TRUE; rv->stringsAllowed = TRUE; break; case 'm': rv->singlefieldsAllowed = FALSE; rv->multifieldsAllowed = TRUE; break; case 'n': rv->floatsAllowed = TRUE; rv->integersAllowed = TRUE; break; case 'o': rv->instanceNamesAllowed = TRUE; break; case 'p': rv->instanceNamesAllowed = TRUE; rv->symbolsAllowed = TRUE; break; case 'q': rv->symbolsAllowed = TRUE; rv->stringsAllowed = TRUE; rv->multifieldsAllowed = TRUE; break; case 's': rv->stringsAllowed = TRUE; break; case 'w': rv->symbolsAllowed = TRUE; break; case 'x': rv->instanceAddressesAllowed = TRUE; break; case 'y': rv->factAddressesAllowed = TRUE; break; case 'z': rv->symbolsAllowed = TRUE; rv->factAddressesAllowed = TRUE; rv->integersAllowed = TRUE; break; case 'u': rv->anyAllowed = TRUE; rv->multifieldsAllowed = TRUE; break; case 'v': rv->voidAllowed = TRUE; break; } return(rv); }
globle CONSTRAINT_RECORD *FunctionCallToConstraintRecord( void *theEnv, EXEC_STATUS, void *theFunction) { CONSTRAINT_RECORD *rv; rv = GetConstraintRecord(theEnv,execStatus); rv->anyAllowed = FALSE; switch ((char) ValueFunctionType(theFunction)) { case 'a': rv->externalAddressesAllowed = TRUE; break; case 'f': case 'd': rv->floatsAllowed = TRUE; break; case 'i': case 'g': case 'l': rv->integersAllowed = TRUE; break; case 'j': rv->instanceNamesAllowed = TRUE; rv->symbolsAllowed = TRUE; rv->stringsAllowed = TRUE; break; case 'k': rv->symbolsAllowed = TRUE; rv->stringsAllowed = TRUE; break; case 'm': rv->singlefieldsAllowed = FALSE; rv->multifieldsAllowed = TRUE; break; case 'n': rv->floatsAllowed = TRUE; rv->integersAllowed = TRUE; break; case 'o': rv->instanceNamesAllowed = TRUE; break; case 's': rv->stringsAllowed = TRUE; break; case 'u': rv->anyAllowed = TRUE; rv->multifieldsAllowed = TRUE; break; case 'w': case 'c': case 'b': rv->symbolsAllowed = TRUE; break; case 'x': rv->instanceAddressesAllowed = TRUE; break; case 'v': rv->voidAllowed = TRUE; break; } return(rv); }
globle CONSTRAINT_RECORD *ExpressionToConstraintRecord( void *theEnv, EXEC_STATUS, struct expr *theExpression) { CONSTRAINT_RECORD *rv; /*================================================*/ /* A NULL expression is converted to a constraint */ /* record with no values allowed. */ /*================================================*/ if (theExpression == NULL) { rv = GetConstraintRecord(theEnv,execStatus); rv->anyAllowed = FALSE; return(rv); } /*=============================================================*/ /* Convert variables and function calls to constraint records. */ /*=============================================================*/ if ((theExpression->type == SF_VARIABLE) || (theExpression->type == MF_VARIABLE) || #if DEFGENERIC_CONSTRUCT (theExpression->type == GCALL) || #endif #if DEFFUNCTION_CONSTRUCT (theExpression->type == PCALL) || #endif (theExpression->type == GBL_VARIABLE) || (theExpression->type == MF_GBL_VARIABLE)) { rv = GetConstraintRecord(theEnv,execStatus); rv->multifieldsAllowed = TRUE; return(rv); } else if (theExpression->type == FCALL) { return(FunctionCallToConstraintRecord(theEnv,execStatus,theExpression->value)); } /*============================================*/ /* Convert a constant to a constraint record. */ /*============================================*/ rv = GetConstraintRecord(theEnv,execStatus); rv->anyAllowed = FALSE; if (theExpression->type == FLOAT) { rv->floatRestriction = TRUE; rv->floatsAllowed = TRUE; } else if (theExpression->type == INTEGER) { rv->integerRestriction = TRUE; rv->integersAllowed = TRUE; } else if (theExpression->type == SYMBOL) { rv->symbolRestriction = TRUE; rv->symbolsAllowed = TRUE; } else if (theExpression->type == STRING) { rv->stringRestriction = TRUE; rv->stringsAllowed = TRUE; } else if (theExpression->type == INSTANCE_NAME) { rv->instanceNameRestriction = TRUE; rv->instanceNamesAllowed = TRUE; } else if (theExpression->type == INSTANCE_ADDRESS) { rv->instanceAddressesAllowed = TRUE; } if (rv->floatsAllowed || rv->integersAllowed || rv->symbolsAllowed || rv->stringsAllowed || rv->instanceNamesAllowed) { rv->restrictionList = GenConstant(theEnv,execStatus,theExpression->type,theExpression->value); } return(rv); }
static BOOLEAN CheckArgumentForConstraintError( struct expr *expressionList, struct expr *lastOne, int i, struct FunctionDefinition *theFunction, struct lhsParseNode *theLHS) { int theRestriction; CONSTRAINT_RECORD *constraint1, *constraint2, *constraint3, *constraint4; struct lhsParseNode *theVariable; struct expr *tmpPtr; int rv = FALSE; /*=============================================================*/ /* Skip anything that isn't a variable or isn't an argument to */ /* a user defined function (i.e. deffunctions and generic have */ /* no constraint information so they aren't checked). */ /*=============================================================*/ if ((expressionList->type != SF_VARIABLE) || (theFunction == NULL)) { return (rv); } /*===========================================*/ /* Get the restrictions for the argument and */ /* convert them to a constraint record. */ /*===========================================*/ theRestriction = GetNthRestriction(theFunction,i); constraint1 = ArgumentTypeToConstraintRecord(theRestriction); /*================================================*/ /* Look for the constraint record associated with */ /* binding the variable in the LHS of the rule. */ /*================================================*/ theVariable = FindVariable((SYMBOL_HN *) expressionList->value,theLHS); if (theVariable != NULL) { if (theVariable->type == MF_VARIABLE) { constraint2 = GetConstraintRecord(); SetConstraintType(MULTIFIELD,constraint2); } else if (theVariable->constraints == NULL) { constraint2 = GetConstraintRecord(); } else { constraint2 = CopyConstraintRecord(theVariable->constraints); } } else { constraint2 = NULL; } /*================================================*/ /* Look for the constraint record associated with */ /* binding the variable on the RHS of the rule. */ /*================================================*/ constraint3 = FindBindConstraints((SYMBOL_HN *) expressionList->value); /*====================================================*/ /* Union the LHS and RHS variable binding constraints */ /* (the variable must satisfy one or the other). */ /*====================================================*/ constraint3 = UnionConstraints(constraint3,constraint2); /*====================================================*/ /* Intersect the LHS/RHS variable binding constraints */ /* with the function argument restriction constraints */ /* (the variable must satisfy both). */ /*====================================================*/ constraint4 = IntersectConstraints(constraint3,constraint1); /*====================================*/ /* Check for unmatchable constraints. */ /*====================================*/ if (UnmatchableConstraint(constraint4) && GetStaticConstraintChecking()) { PrintErrorID("RULECSTR",3,TRUE); PrintRouter(WERROR,"Previous variable bindings of ?"); PrintRouter(WERROR,ValueToString((SYMBOL_HN *) expressionList->value)); PrintRouter(WERROR," caused the type restrictions"); PrintRouter(WERROR,"\nfor argument #"); PrintLongInteger(WERROR,(long int) i); PrintRouter(WERROR," of the expression "); tmpPtr = lastOne->nextArg; lastOne->nextArg = NULL; PrintExpression(WERROR,lastOne); lastOne->nextArg = tmpPtr; PrintRouter(WERROR,"\nfound in the rule's RHS to be violated.\n"); rv = TRUE; } /*===========================================*/ /* Free the temporarily created constraints. */ /*===========================================*/ RemoveConstraint(constraint1); RemoveConstraint(constraint2); RemoveConstraint(constraint3); RemoveConstraint(constraint4); /*========================================*/ /* Return TRUE if unmatchable constraints */ /* were detected, otherwise FALSE. */ /*========================================*/ return(rv); }
static BOOLEAN MultifieldCardinalityViolation( struct lhsParseNode *theNode) { struct lhsParseNode *tmpNode; struct expr *tmpMax; long minFields = 0; long maxFields = 0; int posInfinity = FALSE; CONSTRAINT_RECORD *newConstraint, *tempConstraint; /*================================*/ /* A single field slot can't have */ /* a cardinality violation. */ /*================================*/ if (theNode->multifieldSlot == FALSE) return(FALSE); /*=============================================*/ /* Determine the minimum and maximum number of */ /* fields the slot could contain based on the */ /* slot constraints found in the pattern. */ /*=============================================*/ for (tmpNode = theNode->bottom; tmpNode != NULL; tmpNode = tmpNode->right) { /*====================================================*/ /* A single field variable increases both the minimum */ /* and maximum number of fields by one. */ /*====================================================*/ if ((tmpNode->type == SF_VARIABLE) || (tmpNode->type == SF_WILDCARD)) { minFields++; maxFields++; } /*=================================================*/ /* Otherwise a multifield wildcard or variable has */ /* been encountered. If it is constrained then use */ /* minimum and maximum number of fields constraint */ /* associated with this LHS node. */ /*=================================================*/ else if (tmpNode->constraints != NULL) { /*=======================================*/ /* The lowest minimum of all the min/max */ /* pairs will be the first in the list. */ /*=======================================*/ if (tmpNode->constraints->minFields->value != NegativeInfinity) { minFields += ValueToLong(tmpNode->constraints->minFields->value); } /*=========================================*/ /* The greatest maximum of all the min/max */ /* pairs will be the last in the list. */ /*=========================================*/ tmpMax = tmpNode->constraints->maxFields; while (tmpMax->nextArg != NULL) tmpMax = tmpMax->nextArg; if (tmpMax->value == PositiveInfinity) { posInfinity = TRUE; } else { maxFields += ValueToLong(tmpMax->value); } } /*================================================*/ /* Otherwise an unconstrained multifield wildcard */ /* or variable increases the maximum number of */ /* fields to positive infinity. */ /*================================================*/ else { posInfinity = TRUE; } } /*==================================================================*/ /* Create a constraint record for the cardinality of the sum of the */ /* cardinalities of the restrictions inside the multifield slot. */ /*==================================================================*/ if (theNode->constraints == NULL) tempConstraint = GetConstraintRecord(); else tempConstraint = CopyConstraintRecord(theNode->constraints); ReturnExpression(tempConstraint->minFields); ReturnExpression(tempConstraint->maxFields); tempConstraint->minFields = GenConstant(INTEGER,AddLong((long) minFields)); if (posInfinity) tempConstraint->maxFields = GenConstant(SYMBOL,PositiveInfinity); else tempConstraint->maxFields = GenConstant(INTEGER,AddLong((long) maxFields)); /*================================================================*/ /* Determine the final cardinality for the multifield slot by */ /* intersecting the cardinality sum of the restrictions within */ /* the multifield slot with the original cardinality of the slot. */ /*================================================================*/ newConstraint = IntersectConstraints(theNode->constraints,tempConstraint); if (theNode->derivedConstraints) RemoveConstraint(theNode->constraints); RemoveConstraint(tempConstraint); theNode->constraints = newConstraint; theNode->derivedConstraints = TRUE; /*===================================================================*/ /* Determine if the final cardinality for the slot can be satisfied. */ /*===================================================================*/ if (GetStaticConstraintChecking() == FALSE) return(FALSE); if (UnmatchableConstraint(newConstraint)) return(TRUE); return(FALSE); }
static struct templateSlot *DefinedSlots( void *theEnv, char *readSource, SYMBOL_HN *slotName, int multifieldSlot, struct token *inputToken) { struct templateSlot *newSlot; struct expr *defaultList; int defaultFound = FALSE; int noneSpecified, deriveSpecified; CONSTRAINT_PARSE_RECORD parsedConstraints; /*===========================*/ /* Build the slot container. */ /*===========================*/ newSlot = get_struct(theEnv,templateSlot); newSlot->slotName = slotName; newSlot->defaultList = NULL; newSlot->constraints = GetConstraintRecord(theEnv); if (multifieldSlot) { newSlot->constraints->multifieldsAllowed = TRUE; } newSlot->multislot = multifieldSlot; newSlot->noDefault = FALSE; newSlot->defaultPresent = FALSE; newSlot->defaultDynamic = FALSE; newSlot->next = NULL; /*========================================*/ /* Parse the primitive slot if it exists. */ /*========================================*/ InitializeConstraintParseRecord(&parsedConstraints); GetToken(theEnv,readSource,inputToken); while (inputToken->type != RPAREN) { PPBackup(theEnv); SavePPBuffer(theEnv," "); SavePPBuffer(theEnv,inputToken->printForm); /*================================================*/ /* Slot attributes begin with a left parenthesis. */ /*================================================*/ if (inputToken->type != LPAREN) { SyntaxErrorMessage(theEnv,"deftemplate"); ReturnSlots(theEnv,newSlot); DeftemplateData(theEnv)->DeftemplateError = TRUE; return(NULL); } /*=============================================*/ /* The name of the attribute must be a symbol. */ /*=============================================*/ GetToken(theEnv,readSource,inputToken); if (inputToken->type != SYMBOL) { SyntaxErrorMessage(theEnv,"deftemplate"); ReturnSlots(theEnv,newSlot); DeftemplateData(theEnv)->DeftemplateError = TRUE; return(NULL); } /*================================================================*/ /* Determine if the attribute is one of the standard constraints. */ /*================================================================*/ if (StandardConstraint(ValueToString(inputToken->value))) { if (ParseStandardConstraint(theEnv,readSource,(ValueToString(inputToken->value)), newSlot->constraints,&parsedConstraints, multifieldSlot) == FALSE) { DeftemplateData(theEnv)->DeftemplateError = TRUE; ReturnSlots(theEnv,newSlot); return(NULL); } } /*=================================================*/ /* else if the attribute is the default attribute, */ /* then get the default list for this slot. */ /*=================================================*/ else if ((strcmp(ValueToString(inputToken->value),"default") == 0) || (strcmp(ValueToString(inputToken->value),"default-dynamic") == 0)) { /*======================================================*/ /* Check to see if the default has already been parsed. */ /*======================================================*/ if (defaultFound) { AlreadyParsedErrorMessage(theEnv,"default attribute",NULL); DeftemplateData(theEnv)->DeftemplateError = TRUE; ReturnSlots(theEnv,newSlot); return(NULL); } newSlot->noDefault = FALSE; /*=====================================================*/ /* Determine whether the default is dynamic or static. */ /*=====================================================*/ if (strcmp(ValueToString(inputToken->value),"default") == 0) { newSlot->defaultPresent = TRUE; newSlot->defaultDynamic = FALSE; } else { newSlot->defaultPresent = FALSE; newSlot->defaultDynamic = TRUE; } /*===================================*/ /* Parse the list of default values. */ /*===================================*/ defaultList = ParseDefault(theEnv,readSource,multifieldSlot,(int) newSlot->defaultDynamic, TRUE,&noneSpecified,&deriveSpecified,&DeftemplateData(theEnv)->DeftemplateError); if (DeftemplateData(theEnv)->DeftemplateError == TRUE) { ReturnSlots(theEnv,newSlot); return(NULL); } /*==================================*/ /* Store the default with the slot. */ /*==================================*/ defaultFound = TRUE; if (deriveSpecified) newSlot->defaultPresent = FALSE; else if (noneSpecified) { newSlot->noDefault = TRUE; newSlot->defaultPresent = FALSE; } newSlot->defaultList = defaultList; } /*============================================*/ /* Otherwise the attribute is an invalid one. */ /*============================================*/ else { SyntaxErrorMessage(theEnv,"slot attributes"); ReturnSlots(theEnv,newSlot); DeftemplateData(theEnv)->DeftemplateError = TRUE; return(NULL); } /*===================================*/ /* Begin parsing the next attribute. */ /*===================================*/ GetToken(theEnv,readSource,inputToken); } /*============================*/ /* Return the attribute list. */ /*============================*/ return(newSlot); }
globle struct constraintRecord *IntersectConstraints( void *theEnv, CONSTRAINT_RECORD *c1, CONSTRAINT_RECORD *c2) { struct constraintRecord *rv; int c1Changed = FALSE, c2Changed = FALSE; /*=================================================*/ /* If both constraint records are NULL,then create */ /* a constraint record that allows any value. */ /*=================================================*/ if ((c1 == NULL) && (c2 == NULL)) { rv = GetConstraintRecord(theEnv); rv->multifieldsAllowed = TRUE; return(rv); } /*=================================================*/ /* If one of the constraint records is NULL, then */ /* the intersection is the other constraint record */ /* (a NULL value means no constraints). */ /*=================================================*/ if (c1 == NULL) return(CopyConstraintRecord(theEnv,c2)); if (c2 == NULL) return(CopyConstraintRecord(theEnv,c1)); /*=================================*/ /* Create a new constraint record. */ /*=================================*/ rv = GetConstraintRecord(theEnv); /*==============================*/ /* Intersect the allowed types. */ /*==============================*/ if ((c1->multifieldsAllowed != c2->multifieldsAllowed) && (c1->singlefieldsAllowed != c2->singlefieldsAllowed)) { rv->anyAllowed = FALSE; return(rv); } if (c1->multifieldsAllowed && c2->multifieldsAllowed) { rv->multifieldsAllowed = TRUE; } else { rv->multifieldsAllowed = FALSE; } if (c1->singlefieldsAllowed && c2->singlefieldsAllowed) { rv->singlefieldsAllowed = TRUE; } else { rv->singlefieldsAllowed = FALSE; } if (c1->anyAllowed && c2->anyAllowed) rv->anyAllowed = TRUE; else { if (c1->anyAllowed) { c1Changed = TRUE; SetAnyAllowedFlags(c1,FALSE); } else if (c2->anyAllowed) { c2Changed = TRUE; SetAnyAllowedFlags(c2,FALSE); } rv->anyAllowed = FALSE; rv->symbolsAllowed = (c1->symbolsAllowed && c2->symbolsAllowed); rv->stringsAllowed = (c1->stringsAllowed && c2->stringsAllowed); rv->floatsAllowed = (c1->floatsAllowed && c2->floatsAllowed); rv->integersAllowed = (c1->integersAllowed && c2->integersAllowed); rv->instanceNamesAllowed = (c1->instanceNamesAllowed && c2->instanceNamesAllowed); rv->instanceAddressesAllowed = (c1->instanceAddressesAllowed && c2->instanceAddressesAllowed); rv->externalAddressesAllowed = (c1->externalAddressesAllowed && c2->externalAddressesAllowed); rv->voidAllowed = (c1->voidAllowed && c2->voidAllowed); rv->multifieldsAllowed = (c1->multifieldsAllowed && c2->multifieldsAllowed); rv->factAddressesAllowed = (c1->factAddressesAllowed && c2->factAddressesAllowed); #if FUZZY_DEFTEMPLATES rv->fuzzyValuesAllowed = (c1->fuzzyValuesAllowed && c2->fuzzyValuesAllowed); #endif if (c1Changed) SetAnyAllowedFlags(c1,TRUE); if (c2Changed) SetAnyAllowedFlags(c2,TRUE); } /*=====================================*/ /* Intersect the allowed-values flags. */ /*=====================================*/ if (c1->anyRestriction || c2->anyRestriction) rv->anyRestriction = TRUE; else { rv->anyRestriction = FALSE; rv->symbolRestriction = (c1->symbolRestriction || c2->symbolRestriction); rv->stringRestriction = (c1->stringRestriction || c2->stringRestriction); rv->floatRestriction = (c1->floatRestriction || c2->floatRestriction); rv->integerRestriction = (c1->integerRestriction || c2->integerRestriction); rv->classRestriction = (c1->classRestriction || c2->classRestriction); rv->instanceNameRestriction = (c1->instanceNameRestriction || c2->instanceNameRestriction); #if FUZZY_DEFTEMPLATES rv->fuzzyValueRestriction = (c1->fuzzyValueRestriction || c2->fuzzyValueRestriction); #endif } /*==================================================*/ /* Intersect the allowed values list, allowed class */ /* list, min and max values, and the range values. */ /*==================================================*/ IntersectAllowedValueExpressions(theEnv,c1,c2,rv); IntersectAllowedClassExpressions(theEnv,c1,c2,rv); IntersectNumericExpressions(theEnv,c1,c2,rv,TRUE); IntersectNumericExpressions(theEnv,c1,c2,rv,FALSE); /*==========================================*/ /* Update the allowed-values flags based on */ /* the previous intersection for allowed, */ /* min and max, and range values. */ /*==========================================*/ UpdateRestrictionFlags(rv); /*============================================*/ /* If multifields are allowed, then intersect */ /* the constraint record for them. */ /*============================================*/ if (rv->multifieldsAllowed) { rv->multifield = IntersectConstraints(theEnv,c1->multifield,c2->multifield); if (UnmatchableConstraint(rv->multifield)) { rv->multifieldsAllowed = FALSE; } } /*========================*/ /* Return the intersected */ /* constraint record. */ /*========================*/ return(rv); }
globle struct constraintRecord *UnionConstraints( void *theEnv, CONSTRAINT_RECORD *c1, CONSTRAINT_RECORD *c2) { struct constraintRecord *rv; int c1Changed = FALSE, c2Changed = FALSE; /*=================================================*/ /* If both constraint records are NULL,then create */ /* a constraint record that allows any value. */ /*=================================================*/ if ((c1 == NULL) && (c2 == NULL)) return(GetConstraintRecord(theEnv)); /*=====================================================*/ /* If one of the constraint records is NULL, then the */ /* union is the other constraint record. Note that */ /* this is different from the way that intersections */ /* were handled (a NULL constraint record implied that */ /* any value was legal which in turn would imply that */ /* the union would allow any value as well). */ /*=====================================================*/ if (c1 == NULL) return(CopyConstraintRecord(theEnv,c2)); if (c2 == NULL) return(CopyConstraintRecord(theEnv,c1)); /*=================================*/ /* Create a new constraint record. */ /*=================================*/ rv = GetConstraintRecord(theEnv); /*==========================*/ /* Union the allowed types. */ /*==========================*/ if (c1->multifieldsAllowed || c2->multifieldsAllowed) { rv->multifieldsAllowed = TRUE; } if (c1->singlefieldsAllowed || c2->singlefieldsAllowed) { rv->singlefieldsAllowed = TRUE; } if (c1->anyAllowed || c2->anyAllowed) rv->anyAllowed = TRUE; else { rv->anyAllowed = FALSE; rv->symbolsAllowed = (c1->symbolsAllowed || c2->symbolsAllowed); rv->stringsAllowed = (c1->stringsAllowed || c2->stringsAllowed); rv->floatsAllowed = (c1->floatsAllowed || c2->floatsAllowed); rv->integersAllowed = (c1->integersAllowed || c2->integersAllowed); rv->instanceNamesAllowed = (c1->instanceNamesAllowed || c2->instanceNamesAllowed); rv->instanceAddressesAllowed = (c1->instanceAddressesAllowed || c2->instanceAddressesAllowed); rv->externalAddressesAllowed = (c1->externalAddressesAllowed || c2->externalAddressesAllowed); rv->voidAllowed = (c1->voidAllowed || c2->voidAllowed); rv->factAddressesAllowed = (c1->factAddressesAllowed || c2->factAddressesAllowed); #if FUZZY_DEFTEMPLATES rv->fuzzyValuesAllowed = (c1->fuzzyValuesAllowed || c2->factAddressesAllowed); #endif } /*=================================*/ /* Union the allowed-values flags. */ /*=================================*/ if (c1->anyRestriction && c2->anyRestriction) rv->anyRestriction = TRUE; else { if (c1->anyRestriction) { c1Changed = TRUE; SetAnyRestrictionFlags(c1,FALSE); } else if (c2->anyRestriction) { c2Changed = TRUE; SetAnyRestrictionFlags(c2,FALSE); } rv->anyRestriction = FALSE; rv->symbolRestriction = (c1->symbolRestriction && c2->symbolRestriction); rv->stringRestriction = (c1->stringRestriction && c2->stringRestriction); rv->floatRestriction = (c1->floatRestriction && c2->floatRestriction); rv->integerRestriction = (c1->integerRestriction && c2->integerRestriction); rv->classRestriction = (c1->classRestriction && c2->classRestriction); rv->instanceNameRestriction = (c1->instanceNameRestriction && c2->instanceNameRestriction); #if FUZZY_DEFTEMPLATES rv->fuzzyValueRestriction = (c1->fuzzyValueRestriction && c2->fuzzyValueRestriction); #endif if (c1Changed) SetAnyRestrictionFlags(c1,FALSE); else if (c2Changed) SetAnyRestrictionFlags(c2,FALSE); } /*========================================*/ /* Union the allowed values list, the min */ /* and max values, and the range values. */ /*========================================*/ UnionAllowedValueExpressions(theEnv,c1,c2,rv); UnionAllowedClassExpressions(theEnv,c1,c2,rv); UnionNumericExpressions(theEnv,c1,c2,rv,TRUE); UnionNumericExpressions(theEnv,c1,c2,rv,FALSE); /*========================================*/ /* If multifields are allowed, then union */ /* the constraint record for them. */ /*========================================*/ if (rv->multifieldsAllowed) { rv->multifield = UnionConstraints(theEnv,c1->multifield,c2->multifield); } /*====================*/ /* Return the unioned */ /* constraint record. */ /*====================*/ return(rv); }
static int ProcessVariable( void *theEnv, struct lhsParseNode *thePattern, struct lhsParseNode *multifieldHeader, struct lhsParseNode *patternHead, int patternHeadType, struct nandFrame *theNandFrames) { int theType; struct symbolHashNode *theVariable; struct constraintRecord *theConstraints; /*=============================================================*/ /* If a pattern address is being propagated, then treat it as */ /* a single field pattern variable and create a constraint */ /* which indicates that is must be a fact or instance address. */ /* This code will have to be modified for new data types which */ /* can match patterns. */ /*=============================================================*/ if (thePattern->type == PATTERN_CE) { theType = SF_VARIABLE; theVariable = (struct symbolHashNode *) thePattern->value; if (thePattern->derivedConstraints) RemoveConstraint(theEnv,thePattern->constraints); theConstraints = GetConstraintRecord(theEnv); thePattern->constraints = theConstraints; thePattern->constraints->anyAllowed = FALSE; thePattern->constraints->instanceAddressesAllowed = TRUE; thePattern->constraints->factAddressesAllowed = TRUE; thePattern->derivedConstraints = 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(theEnv,thePattern->bottom,theType,theVariable, thePattern,patternHead->beginNandDepth, TRUE,FALSE); if (ProcessField(theEnv,thePattern,multifieldHeader,patternHead,patternHeadType,theNandFrames)) { return(TRUE); } } /*=================================================================*/ /* Propagate the constraints to other fields, slots, and patterns. */ /*=================================================================*/ return(PropagateVariableDriver(theEnv,patternHead,thePattern,multifieldHeader,theType, theVariable,thePattern,TRUE,patternHeadType)); }
CONSTRAINT_RECORD *FunctionCallToConstraintRecord( void *theEnv, void *theFunction) { CONSTRAINT_RECORD *rv; if (ValueFunctionType(theFunction) == 'z') { return ArgumentTypeToConstraintRecord2(theEnv,UnknownFunctionType(theFunction)); } rv = GetConstraintRecord(theEnv); rv->anyAllowed = false; switch ((char) ValueFunctionType(theFunction)) { case 'a': rv->externalAddressesAllowed = true; break; case 'f': case 'd': rv->floatsAllowed = true; break; case 'i': case 'g': case 'l': rv->integersAllowed = true; break; case 'j': rv->instanceNamesAllowed = true; rv->symbolsAllowed = true; rv->stringsAllowed = true; break; case 'k': rv->symbolsAllowed = true; rv->stringsAllowed = true; break; case 'm': rv->singlefieldsAllowed = false; rv->multifieldsAllowed = true; break; case 'n': rv->floatsAllowed = true; rv->integersAllowed = true; break; case 'o': rv->instanceNamesAllowed = true; break; case 's': rv->stringsAllowed = true; break; case 'u': rv->anyAllowed = true; rv->multifieldsAllowed = true; break; case 'w': case 'c': case 'b': rv->symbolsAllowed = true; break; case 'x': rv->instanceAddressesAllowed = true; break; case 'y': rv->factAddressesAllowed = true; break; case 'v': rv->voidAllowed = true; break; } return(rv); }