/*******************************************************/ /* "C" Language Integrated Production System */ /* */ /* CLIPS Version 6.20 01/31/02 */ /* */ /* CONSTRAINT UTILITY MODULE */ /*******************************************************/ /*************************************************************/ /* Purpose: Utility routines for manipulating, initializing, */ /* creating, copying, and comparing constraint records. */ /* */ /* Principal Programmer(s): */ /* Gary D. Riley */ /* */ /* Contributing Programmer(s): */ /* Brian Donnell */ /* */ /* Revision History: */ /* */ /*************************************************************/ #define _CSTRNUTL_SOURCE_ #include #define _STDIO_INCLUDED_ #include #include "setup.h" #include "constant.h" #include "envrnmnt.h" #include "memalloc.h" #include "router.h" #include "extnfunc.h" #include "scanner.h" #include "multifld.h" #include "argacces.h" #include "cstrnutl.h" /************************************************/ /* GetConstraintRecord: Creates and initializes */ /* the values of a constraint record. */ /************************************************/ globle struct constraintRecord *GetConstraintRecord( void *theEnv) { CONSTRAINT_RECORD *constraints; unsigned i; constraints = get_struct(theEnv,constraintRecord); for (i = 0 ; i < sizeof(CONSTRAINT_RECORD) ; i++) { ((char *) constraints)[i] = '\0'; } SetAnyAllowedFlags(constraints,TRUE); constraints->multifieldsAllowed = FALSE; constraints->singlefieldsAllowed = TRUE; constraints->anyRestriction = FALSE; constraints->symbolRestriction = FALSE; constraints->stringRestriction = FALSE; constraints->floatRestriction = FALSE; constraints->integerRestriction = FALSE; constraints->instanceNameRestriction = FALSE; constraints->restrictionList = NULL; constraints->minValue = GenConstant(theEnv,SYMBOL,SymbolData(theEnv)->NegativeInfinity); constraints->maxValue = GenConstant(theEnv,SYMBOL,SymbolData(theEnv)->PositiveInfinity); constraints->minFields = GenConstant(theEnv,INTEGER,SymbolData(theEnv)->Zero); constraints->maxFields = GenConstant(theEnv,SYMBOL,SymbolData(theEnv)->PositiveInfinity); constraints->bucket = -1; constraints->count = 0; constraints->multifield = NULL; constraints->next = NULL; return(constraints); } /********************************************************/ /* SetAnyAllowedFlags: Sets the allowed type flags of a */ /* constraint record to allow all types. If passed an */ /* argument of TRUE, just the "any allowed" flag is */ /* set to TRUE. If passed an argument of FALSE, then */ /* all of the individual type flags are set to TRUE. */ /********************************************************/ globle void SetAnyAllowedFlags( CONSTRAINT_RECORD *theConstraint, int justOne) { int flag1, flag2; if (justOne) { flag1 = TRUE; flag2 = FALSE; } else { flag1 = FALSE; flag2 = TRUE; } theConstraint->anyAllowed = flag1; theConstraint->symbolsAllowed = flag2; theConstraint->stringsAllowed = flag2; theConstraint->floatsAllowed = flag2; theConstraint->integersAllowed = flag2; theConstraint->instanceNamesAllowed = flag2; theConstraint->instanceAddressesAllowed = flag2; theConstraint->externalAddressesAllowed = flag2; theConstraint->voidAllowed = flag2; theConstraint->factAddressesAllowed = flag2; } /*****************************************************/ /* CopyConstraintRecord: Copies a constraint record. */ /*****************************************************/ globle struct constraintRecord *CopyConstraintRecord( void *theEnv, CONSTRAINT_RECORD *sourceConstraint) { CONSTRAINT_RECORD *theConstraint; if (sourceConstraint == NULL) return(NULL); theConstraint = get_struct(theEnv,constraintRecord); theConstraint->anyAllowed = sourceConstraint->anyAllowed; theConstraint->symbolsAllowed = sourceConstraint->symbolsAllowed; theConstraint->stringsAllowed = sourceConstraint->stringsAllowed; theConstraint->floatsAllowed = sourceConstraint->floatsAllowed; theConstraint->integersAllowed = sourceConstraint->integersAllowed; theConstraint->instanceNamesAllowed = sourceConstraint->instanceNamesAllowed; theConstraint->instanceAddressesAllowed = sourceConstraint->instanceAddressesAllowed; theConstraint->externalAddressesAllowed = sourceConstraint->externalAddressesAllowed; theConstraint->voidAllowed = sourceConstraint->voidAllowed; theConstraint->multifieldsAllowed = sourceConstraint->multifieldsAllowed; theConstraint->singlefieldsAllowed = sourceConstraint->singlefieldsAllowed; theConstraint->factAddressesAllowed = sourceConstraint->factAddressesAllowed; theConstraint->anyRestriction = sourceConstraint->anyRestriction; theConstraint->symbolRestriction = sourceConstraint->symbolRestriction; theConstraint->stringRestriction = sourceConstraint->stringRestriction; theConstraint->floatRestriction = sourceConstraint->floatRestriction; theConstraint->integerRestriction = sourceConstraint->integerRestriction; theConstraint->instanceNameRestriction = sourceConstraint->instanceNameRestriction; theConstraint->restrictionList = CopyExpression(theEnv,sourceConstraint->restrictionList); theConstraint->minValue = CopyExpression(theEnv,sourceConstraint->minValue); theConstraint->maxValue = CopyExpression(theEnv,sourceConstraint->maxValue); theConstraint->minFields = CopyExpression(theEnv,sourceConstraint->minFields); theConstraint->maxFields = CopyExpression(theEnv,sourceConstraint->maxFields); theConstraint->bucket = -1; theConstraint->count = 0; theConstraint->multifield = CopyConstraintRecord(theEnv,sourceConstraint->multifield); theConstraint->next = NULL; return(theConstraint); } #if (! RUN_TIME) && (! BLOAD_ONLY) /**************************************************************/ /* SetAnyRestrictionFlags: Sets the restriction type flags of */ /* a constraint record to indicate there are restriction on */ /* all types. If passed an argument of TRUE, just the */ /* "any restriction" flag is set to TRUE. If passed an */ /* argument of FALSE, then all of the individual type */ /* restriction flags are set to TRUE. */ /**************************************************************/ globle void SetAnyRestrictionFlags( CONSTRAINT_RECORD *theConstraint, int justOne) { int flag1, flag2; if (justOne) { flag1 = TRUE; flag2 = FALSE; } else { flag1 = FALSE; flag2 = TRUE; } theConstraint->anyRestriction = flag1; theConstraint->symbolRestriction = flag2; theConstraint->stringRestriction = flag2; theConstraint->floatRestriction = flag2; theConstraint->integerRestriction = flag2; theConstraint->instanceNameRestriction = flag2; } /*****************************************************/ /* SetConstraintType: Given a constraint type and a */ /* constraint, sets the allowed type flags for the */ /* specified type in the constraint to TRUE. */ /*****************************************************/ globle int SetConstraintType( int theType, CONSTRAINT_RECORD *constraints) { int rv = TRUE; switch(theType) { case UNKNOWN_VALUE: rv = constraints->anyAllowed; constraints->anyAllowed = TRUE; break; case SYMBOL: rv = constraints->symbolsAllowed; constraints->symbolsAllowed = TRUE; break; case STRING: rv = constraints->stringsAllowed; constraints->stringsAllowed = TRUE; break; case SYMBOL_OR_STRING: rv = (constraints->stringsAllowed | constraints->symbolsAllowed); constraints->symbolsAllowed = TRUE; constraints->stringsAllowed = TRUE; break; case INTEGER: rv = constraints->integersAllowed; constraints->integersAllowed = TRUE; break; case FLOAT: rv = constraints->floatsAllowed; constraints->floatsAllowed = TRUE; break; case INTEGER_OR_FLOAT: rv = (constraints->integersAllowed | constraints->floatsAllowed); constraints->integersAllowed = TRUE; constraints->floatsAllowed = TRUE; break; case INSTANCE_ADDRESS: rv = constraints->instanceAddressesAllowed; constraints->instanceAddressesAllowed = TRUE; break; case INSTANCE_NAME: rv = constraints->instanceNamesAllowed; constraints->instanceNamesAllowed = TRUE; break; case INSTANCE_OR_INSTANCE_NAME: rv = (constraints->instanceNamesAllowed | constraints->instanceAddressesAllowed); constraints->instanceNamesAllowed = TRUE; constraints->instanceAddressesAllowed = TRUE; break; case EXTERNAL_ADDRESS: rv = constraints->externalAddressesAllowed; constraints->externalAddressesAllowed = TRUE; break; case RVOID: rv = constraints->voidAllowed; constraints->voidAllowed = TRUE; break; case FACT_ADDRESS: rv = constraints->factAddressesAllowed; constraints->factAddressesAllowed = TRUE; break; case MULTIFIELD: rv = constraints->multifieldsAllowed; constraints->multifieldsAllowed = TRUE; break; } if (theType != UNKNOWN_VALUE) constraints->anyAllowed = FALSE; return(rv); } #endif /* (! RUN_TIME) && (! BLOAD_ONLY) */ /*************************************************************/ /* CompareNumbers: Given two numbers (which can be integers, */ /* floats, or the symbols for positive/negative infinity) */ /* returns the relationship between the numbers (greater */ /* than, less than or equal). */ /*************************************************************/ globle int CompareNumbers( void *theEnv, int type1, void *vptr1, int type2, void *vptr2) { /*============================================*/ /* Handle the situation in which the values */ /* are exactly equal (same type, same value). */ /*============================================*/ if (vptr1 == vptr2) return(EQUAL); /*=======================================*/ /* Handle the special cases for positive */ /* and negative infinity. */ /*=======================================*/ if (vptr1 == SymbolData(theEnv)->PositiveInfinity) return(GREATER_THAN); if (vptr1 == SymbolData(theEnv)->NegativeInfinity) return(LESS_THAN); if (vptr2 == SymbolData(theEnv)->PositiveInfinity) return(LESS_THAN); if (vptr2 == SymbolData(theEnv)->NegativeInfinity) return(GREATER_THAN); /*=======================*/ /* Compare two integers. */ /*=======================*/ if ((type1 == INTEGER) && (type2 == INTEGER)) { if (ValueToLong(vptr1) < ValueToLong(vptr2)) { return(LESS_THAN); } else if (ValueToLong(vptr1) > ValueToLong(vptr2)) { return(GREATER_THAN); } return(EQUAL); } /*=====================*/ /* Compare two floats. */ /*=====================*/ if ((type1 == FLOAT) && (type2 == FLOAT)) { if (ValueToDouble(vptr1) < ValueToDouble(vptr2)) { return(LESS_THAN); } else if (ValueToDouble(vptr1) > ValueToDouble(vptr2)) { return(GREATER_THAN); } return(EQUAL); } /*================================*/ /* Compare an integer to a float. */ /*================================*/ if ((type1 == INTEGER) && (type2 == FLOAT)) { if (((double) ValueToLong(vptr1)) < ValueToDouble(vptr2)) { return(LESS_THAN); } else if (((double) ValueToLong(vptr1)) > ValueToDouble(vptr2)) { return(GREATER_THAN); } return(EQUAL); } /*================================*/ /* Compare a float to an integer. */ /*================================*/ if ((type1 == FLOAT) && (type2 == INTEGER)) { if (ValueToDouble(vptr1) < ((double) ValueToLong(vptr2))) { return(LESS_THAN); } else if (ValueToDouble(vptr1) > ((double) ValueToLong(vptr2))) { return(GREATER_THAN); } return(EQUAL); } /*===================================*/ /* One of the arguments was invalid. */ /* Return -1 to indicate an error. */ /*===================================*/ return(-1); } /****************************************************************/ /* ExpressionToConstraintRecord: Converts an expression into a */ /* constraint record. For example, an expression representing */ /* the symbol BLUE would be converted to a record with */ /* allowed types SYMBOL and allow-values BLUE. */ /****************************************************************/ globle CONSTRAINT_RECORD *ExpressionToConstraintRecord( void *theEnv, 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); 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); rv->multifieldsAllowed = TRUE; return(rv); } else if (theExpression->type == FCALL) { return(FunctionCallToConstraintRecord(theEnv,theExpression->value)); } /*============================================*/ /* Convert a constant to a constraint record. */ /*============================================*/ rv = GetConstraintRecord(theEnv); 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,theExpression->type,theExpression->value); } return(rv); } /*******************************************************/ /* FunctionCallToConstraintRecord: Converts a function */ /* call to a constraint record. For example, the + */ /* function when converted would be a constraint */ /* record with allowed types INTEGER and FLOAT. */ /*******************************************************/ globle CONSTRAINT_RECORD *FunctionCallToConstraintRecord( void *theEnv, void *theFunction) { CONSTRAINT_RECORD *rv; 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 '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); } /*******************************************************/ /* ArgumentTypeToConstraintRecord: Converts one of the */ /* function argument types (used by DefineFunction2) */ /* to a constraint record. */ /*******************************************************/ globle CONSTRAINT_RECORD *ArgumentTypeToConstraintRecord( void *theEnv, int theRestriction) { CONSTRAINT_RECORD *rv; rv = GetConstraintRecord(theEnv); 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); }