📄 pattern.c
字号:
/* */
/* <connected-constraint> */
/* ::= <single-constraint> | */
/* <single-constraint> & <connected-constraint> | */
/* <single-constraint> | <connected-constraint> */
/*******************************************************************/
static struct lhsParseNode *ConjuctiveRestrictionParse(
void *theEnv,
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(theEnv,readSource,theToken,error);
if (*error == TRUE)
{ return(NULL); }
GetToken(theEnv,readSource,theToken);
if (((theNode->type == SF_VARIABLE) || (theNode->type == MF_VARIABLE)) &&
(theNode->negated == FALSE) &&
(theToken->type != OR_CONSTRAINT))
{
theNode->bindingVariable = TRUE;
bindNode = theNode;
nextOr = NULL;
nextAnd = NULL;
}
else
{
bindNode = GetLHSParseNode(theEnv);
if (theNode->type == MF_VARIABLE) bindNode->type = MF_WILDCARD;
else bindNode->type = SF_WILDCARD;
bindNode->negated = 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(theEnv,readSource,theToken);
theNode = LiteralRestrictionParse(theEnv,readSource,theToken,error);
if (*error == TRUE)
{
ReturnLHSParseNodes(theEnv,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
{
SystemError(theEnv,"RULEPSR",1);
EnvExitRouter(theEnv,EXIT_FAILURE);
}
/*==================================================*/
/* Determine if any more restrictions are connected */
/* to the current list of restrictions. */
/*==================================================*/
GetToken(theEnv,readSource,theToken);
}
/*==========================================*/
/* Check for illegal mixing of single and */
/* multifield values within the constraint. */
/*==========================================*/
if (CheckForVariableMixing(theEnv,bindNode))
{
*error = TRUE;
ReturnLHSParseNodes(theEnv,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(
void *theEnv,
struct lhsParseNode *theRestriction)
{
struct lhsParseNode *tempRestriction;
CONSTRAINT_RECORD *theConstraint;
int multifield = FALSE;
int singlefield = FALSE;
int constant = FALSE;
int singleReturnValue = FALSE;
int multiReturnValue = FALSE;
/*================================================*/
/* If the constraint contains a binding variable, */
/* determine whether it is a single field or */
/* multifield variable. */
/*================================================*/
if (theRestriction->type == SF_VARIABLE) singlefield = TRUE;
else if (theRestriction->type == MF_VARIABLE) multifield = 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 = TRUE;
else if (tempRestriction->type == MF_VARIABLE) multifield = TRUE;
else if (ConstantType(tempRestriction->type)) constant = TRUE;
else if (tempRestriction->type == RETURN_VALUE_CONSTRAINT)
{
theConstraint = FunctionCallToConstraintRecord(theEnv,tempRestriction->expression->value);
if (theConstraint->anyAllowed) { /* Do nothing. */ }
else if (theConstraint->multifieldsAllowed) multiReturnValue = TRUE;
else singleReturnValue = TRUE;
RemoveConstraint(theEnv,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(theEnv,"PATTERN",2,TRUE);
EnvPrintRouter(theEnv,WERROR,"Single and multifield constraints cannot be mixed in a field constraint\n");
return(TRUE);
}
/*=======================================*/
/* Otherwise return FALSE to indicate no */
/* illegal variable mixing was detected. */
/*=======================================*/
return(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(
void *theEnv,
char *readSource,
struct token *theToken,
int *error)
{
struct lhsParseNode *topNode;
struct expr *theExpression;
/*============================================*/
/* Create a node to represent the constraint. */
/*============================================*/
topNode = GetLHSParseNode(theEnv);
/*=================================================*/
/* 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(theEnv,readSource,theToken);
topNode->negated = TRUE;
}
else
{ topNode->negated = 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(theEnv,readSource);
if (theExpression == NULL)
{
*error = TRUE;
ReturnLHSParseNodes(theEnv,topNode);
return(NULL);
}
topNode->type = RETURN_VALUE_CONSTRAINT;
topNode->expression = ExpressionToLHSParseNodes(theEnv,theExpression);
ReturnExpression(theEnv,theExpression);
}
/*=============================*/
/* If the symbol is a :, parse */
/* a predicate constraint. */
/*=============================*/
else if (strcmp(ValueToString(theToken->value),":") == 0)
{
theExpression = Function0Parse(theEnv,readSource);
if (theExpression == NULL)
{
*error = TRUE;
ReturnLHSParseNodes(theEnv,topNode);
return(NULL);
}
topNode->type = PREDICATE_CONSTRAINT;
topNode->expression = ExpressionToLHSParseNodes(theEnv,theExpression);
ReturnExpression(theEnv,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(theEnv,"defrule");
*error = TRUE;
ReturnLHSParseNodes(theEnv,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 + -