📄 cstrnops.c
字号:
/*******************************************************/
/* "C" Language Integrated Production System */
/* */
/* CLIPS Version 6.24 07/01/05 */
/* */
/* CONSTRAINT OPERATIONS MODULE */
/*******************************************************/
/*************************************************************/
/* Purpose: Provides functions for performing operations on */
/* constraint records including computing the intersection */
/* and union of constraint records. */
/* */
/* Principal Programmer(s): */
/* Gary D. Riley */
/* */
/* Contributing Programmer(s): */
/* */
/* Revision History: */
/* */
/* 6.24: Added allowed-classes slot facet. */
/* */
/*************************************************************/
#define _CSTRNOPS_SOURCE_
#include "setup.h"
#include <stdio.h>
#define _STDIO_INCLUDED_
#include <stdlib.h>
#if (! RUN_TIME)
#include "constant.h"
#include "envrnmnt.h"
#include "memalloc.h"
#include "router.h"
#include "extnfunc.h"
#include "scanner.h"
#include "multifld.h"
#include "constrnt.h"
#include "cstrnchk.h"
#include "cstrnutl.h"
#include "cstrnops.h"
/***************************************/
/* LOCAL INTERNAL FUNCTION DEFINITIONS */
/***************************************/
static void IntersectNumericExpressions(void *,
CONSTRAINT_RECORD *,
CONSTRAINT_RECORD *,
CONSTRAINT_RECORD *,int);
static void IntersectAllowedValueExpressions(void *,
CONSTRAINT_RECORD *,
CONSTRAINT_RECORD *,
CONSTRAINT_RECORD *);
static void IntersectAllowedClassExpressions(void *,
CONSTRAINT_RECORD *,
CONSTRAINT_RECORD *,
CONSTRAINT_RECORD *);
static int FindItemInExpression(int,void *,int,struct expr *);
static void UpdateRestrictionFlags(CONSTRAINT_RECORD *);
#if (! BLOAD_ONLY)
static void UnionRangeMinMaxValueWithList(void *,
struct expr *,
struct expr *,
struct expr **,
struct expr **);
static void UnionNumericExpressions(void *,
CONSTRAINT_RECORD *,
CONSTRAINT_RECORD *,
CONSTRAINT_RECORD *,int);
static struct expr *AddToUnionList(void *,
struct expr *,struct expr *,
CONSTRAINT_RECORD *);
static void UnionAllowedValueExpressions(void *,
CONSTRAINT_RECORD *,
CONSTRAINT_RECORD *,
CONSTRAINT_RECORD *);
static void UnionAllowedClassExpressions(void *,
CONSTRAINT_RECORD *,
CONSTRAINT_RECORD *,
CONSTRAINT_RECORD *);
static int RestrictionOnType(int,CONSTRAINT_RECORD *);
#endif
/**************************************************************/
/* IntersectConstraints: Creates a new constraint record that */
/* is the intersection of two other constraint records. */
/**************************************************************/
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 (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);
}
/*==================================================*/
/* 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);
}
/*************************************************/
/* IntersectAllowedValueExpressions: Creates the */
/* intersection of two allowed-values lists. */
/*************************************************/
static void IntersectAllowedValueExpressions(
void *theEnv,
CONSTRAINT_RECORD *constraint1,
CONSTRAINT_RECORD *constraint2,
CONSTRAINT_RECORD *newConstraint)
{
struct expr *theList1, *theList2;
struct expr *theHead = NULL, *tmpExpr;
/*===========================================*/
/* Loop through each value in allowed-values */
/* list of the first constraint record. Add */
/* each value to a list if it satisfies the */
/* restrictions for both constraint records. */
/*===========================================*/
for (theList1 = constraint1->restrictionList;
theList1 != NULL;
theList1 = theList1->nextArg)
{
if (CheckAllowedValuesConstraint(theList1->type,theList1->value,constraint1) &&
CheckAllowedValuesConstraint(theList1->type,theList1->value,constraint2))
{
tmpExpr = GenConstant(theEnv,theList1->type,theList1->value);
tmpExpr->nextArg = theHead;
theHead = tmpExpr;
}
}
/*===========================================*/
/* Loop through each value in allowed-values */
/* list of the second constraint record. Add */
/* each value to a list if it satisfies the */
/* restrictions for both constraint records. */
/*===========================================*/
for (theList2 = constraint2->restrictionList;
theList2 != NULL;
theList2 = theList2->nextArg)
{
if (FindItemInExpression(theList2->type,theList2->value,TRUE,theHead))
{ /* The value is already in the list--Do nothing */ }
else if (CheckAllowedValuesConstraint(theList2->type,theList2->value,constraint1) &&
CheckAllowedValuesConstraint(theList2->type,theList2->value,constraint2))
{
tmpExpr = GenConstant(theEnv,theList2->type,theList2->value);
tmpExpr->nextArg = theHead;
theHead = tmpExpr;
}
}
/*================================================*/
/* Set the allowed values list for the constraint */
/* record to the intersected values of the two */
/* other constraint records. */
/*================================================*/
newConstraint->restrictionList = theHead;
}
/*************************************************/
/* IntersectAllowedClassExpressions: Creates the */
/* intersection of two allowed-classes lists. */
/*************************************************/
static void IntersectAllowedClassExpressions(
void *theEnv,
CONSTRAINT_RECORD *constraint1,
CONSTRAINT_RECORD *constraint2,
CONSTRAINT_RECORD *newConstraint)
{
struct expr *theList1, *theList2;
struct expr *theHead = NULL, *tmpExpr;
/*============================================*/
/* Loop through each value in allowed-classes */
/* list of the first constraint record. Add */
/* each value to a list if it satisfies the */
/* restrictions for both constraint records. */
/*============================================*/
for (theList1 = constraint1->classList;
theList1 != NULL;
theList1 = theList1->nextArg)
{
if (CheckAllowedClassesConstraint(theEnv,theList1->type,theList1->value,constraint1) &&
CheckAllowedClassesConstraint(theEnv,theList1->type,theList1->value,constraint2))
{
tmpExpr = GenConstant(theEnv,theList1->type,theList1->value);
tmpExpr->nextArg = theHead;
theHead = tmpExpr;
}
}
/*============================================*/
/* Loop through each value in allowed-classes */
/* list of the second constraint record. Add */
/* each value to a list if it satisfies the */
/* restrictions for both constraint records. */
/*============================================*/
for (theList2 = constraint2->classList;
theList2 != NULL;
theList2 = theList2->nextArg)
{
if (FindItemInExpression(theList2->type,theList2->value,TRUE,theHead))
{ /* The value is already in the list--Do nothing */ }
else if (CheckAllowedClassesConstraint(theEnv,theList2->type,theList2->value,constraint1) &&
CheckAllowedClassesConstraint(theEnv,theList2->type,theList2->value,constraint2))
{
tmpExpr = GenConstant(theEnv,theList2->type,theList2->value);
tmpExpr->nextArg = theHead;
theHead = tmpExpr;
}
}
/*=================================================*/
/* Set the allowed classes list for the constraint */
/* record to the intersected values of the two */
/* other constraint records. */
/*=================================================*/
newConstraint->classList = theHead;
}
/*********************************************************/
/* IntersectNumericExpressions: Creates the intersection */
/* of two range or two min/max-fields constraints. */
/*********************************************************/
static void IntersectNumericExpressions(
void *theEnv,
CONSTRAINT_RECORD *constraint1,
CONSTRAINT_RECORD *constraint2,
CONSTRAINT_RECORD *newConstraint,
int range)
{
struct expr *tmpmin1, *tmpmax1, *tmpmin2, *tmpmax2, *theMin, *theMax;
struct expr *theMinList, *theMaxList, *lastMin = NULL, *lastMax = NULL;
int cmaxmax, cminmin, cmaxmin, cminmax;
/*==========================================*/
/* Initialize the new range/min/max values */
/* for the intersection of the constraints. */
/*==========================================*/
theMinList = NULL;
theMaxList = NULL;
/*=================================*/
/* Determine the min/max values of */
/* the first constraint record. */
/*=================================*/
if (range)
{
tmpmin1 = constraint1->minValue;
tmpmax1 = constraint1->maxValue;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -