📄 analysis.c
字号:
/*========================================================*/
/* Return FALSE to indicate that no errors were detected. */
/*========================================================*/
return(FALSE);
}
/*************************************************************/
/* UnboundVariablesInPattern: Verifies that variables within */
/* a slot/field have been referenced properly (i.e. that */
/* variables have been previously bound if they are not a */
/* binding occurrence). */
/*************************************************************/
static intBool UnboundVariablesInPattern(
void *theEnv,
struct lhsParseNode *theSlot,
int pattern)
{
struct lhsParseNode *andField;
struct lhsParseNode *rv;
int result;
struct lhsParseNode *orField;
struct symbolHashNode *slotName;
CONSTRAINT_RECORD *theConstraints;
int theField;
/*===================================================*/
/* If a multifield slot is being checked, then check */
/* each of the fields grouped with the multifield. */
/*===================================================*/
if (theSlot->multifieldSlot)
{
theSlot = theSlot->bottom;
while (theSlot != NULL)
{
if (UnboundVariablesInPattern(theEnv,theSlot,pattern))
{ return(TRUE); }
theSlot = theSlot->right;
}
return(FALSE);
}
/*=======================*/
/* Check a single field. */
/*=======================*/
slotName = theSlot->slot;
theField = theSlot->index;
theConstraints = theSlot->constraints;
/*===========================================*/
/* Loop through each of the '|' constraints. */
/*===========================================*/
for (orField = theSlot->bottom;
orField != NULL;
orField = orField->bottom)
{
/*===========================================*/
/* Loop through each of the fields connected */
/* by the '&' within the '|' constraint. */
/*===========================================*/
for (andField = orField;
andField != NULL;
andField = andField->right)
{
/*=======================================================*/
/* If this is not a binding occurence of a variable and */
/* there is no previous binding occurence of a variable, */
/* then generate an error message for a variable that is */
/* referred to but not bound. */
/*=======================================================*/
if (((andField->type == SF_VARIABLE) || (andField->type == MF_VARIABLE)) &&
(andField->referringNode == NULL))
{
VariableReferenceErrorMessage(theEnv,(SYMBOL_HN *) andField->value,NULL,pattern,
slotName,theField);
return(TRUE);
}
/*==============================================*/
/* Check predicate and return value constraints */
/* to insure that all variables used within the */
/* constraint have been previously bound. */
/*==============================================*/
else if ((andField->type == PREDICATE_CONSTRAINT) ||
(andField->type == RETURN_VALUE_CONSTRAINT))
{
rv = CheckExpression(theEnv,andField->expression,NULL,pattern,slotName,theField);
if (rv != NULL) return(TRUE);
}
/*========================================================*/
/* If static constraint checking is being performed, then */
/* determine if constant values have violated the set of */
/* derived constraints for the slot/field (based on the */
/* deftemplate definition and propagated constraints). */
/*========================================================*/
else if (((andField->type == INTEGER) || (andField->type == FLOAT) ||
(andField->type == SYMBOL) || (andField->type == STRING) ||
(andField->type == INSTANCE_NAME)) &&
EnvGetStaticConstraintChecking(theEnv))
{
result = ConstraintCheckValue(theEnv,andField->type,andField->value,theConstraints);
if (result != NO_VIOLATION)
{
ConstraintViolationErrorMessage(theEnv,"A literal restriction value",
NULL,FALSE,pattern,
slotName,theField,result,
theConstraints,TRUE);
return(TRUE);
}
}
}
}
/*===============================*/
/* Return FALSE to indicate that */
/* no errors were detected. */
/*===============================*/
return(FALSE);
}
/******************************************************************/
/* CheckExpression: Verifies that variables within an expression */
/* have been referenced properly. All variables within an */
/* expression must have been previously bound. */
/******************************************************************/
static struct lhsParseNode *CheckExpression(
void *theEnv,
struct lhsParseNode *exprPtr,
struct lhsParseNode *lastOne,
int whichCE,
struct symbolHashNode *slotName,
int theField)
{
struct lhsParseNode *rv;
int i = 1;
while (exprPtr != NULL)
{
/*===============================================================*/
/* Check that single field variables contained in the expression */
/* were previously defined in the LHS. Also check to see if the */
/* variable has unmatchable constraints. */
/*===============================================================*/
if (exprPtr->type == SF_VARIABLE)
{
if (exprPtr->referringNode == NULL)
{
VariableReferenceErrorMessage(theEnv,(SYMBOL_HN *) exprPtr->value,lastOne,
whichCE,slotName,theField);
return(exprPtr);
}
else if ((UnmatchableConstraint(exprPtr->constraints)) &&
EnvGetStaticConstraintChecking(theEnv))
{
ConstraintReferenceErrorMessage(theEnv,(SYMBOL_HN *) exprPtr->value,lastOne,i,
whichCE,slotName,theField);
return(exprPtr);
}
}
/*==================================================*/
/* Check that multifield variables contained in the */
/* expression were previously defined in the LHS. */
/*==================================================*/
else if ((exprPtr->type == MF_VARIABLE) && (exprPtr->referringNode == NULL))
{
VariableReferenceErrorMessage(theEnv,(SYMBOL_HN *) exprPtr->value,lastOne,
whichCE,slotName,theField);
return(exprPtr);
}
/*=====================================================*/
/* Check that global variables are referenced properly */
/* (i.e. if you reference a global variable, it must */
/* already be defined by a defglobal construct). */
/*=====================================================*/
#if DEFGLOBAL_CONSTRUCT
else if (exprPtr->type == GBL_VARIABLE)
{
int count;
if (FindImportedConstruct(theEnv,"defglobal",NULL,ValueToString(exprPtr->value),
&count,TRUE,NULL) == NULL)
{
VariableReferenceErrorMessage(theEnv,(SYMBOL_HN *) exprPtr->value,lastOne,
whichCE,slotName,theField);
return(exprPtr);
}
}
#endif
/*============================================*/
/* Recursively check other function calls to */
/* insure variables are referenced correctly. */
/*============================================*/
else if (((exprPtr->type == FCALL)
#if DEFGENERIC_CONSTRUCT
|| (exprPtr->type == GCALL)
#endif
#if DEFFUNCTION_CONSTRUCT
|| (exprPtr->type == PCALL)
#endif
) && (exprPtr->bottom != NULL))
{
if ((rv = CheckExpression(theEnv,exprPtr->bottom,exprPtr,whichCE,slotName,theField)) != NULL)
{ return(rv); }
}
/*=============================================*/
/* Move on to the next part of the expression. */
/*=============================================*/
i++;
exprPtr = exprPtr->right;
}
/*================================================*/
/* Return NULL to indicate no error was detected. */
/*================================================*/
return(NULL);
}
/********************************************************/
/* VariableReferenceErrorMessage: Generic error message */
/* for referencing a variable before it is defined. */
/********************************************************/
static void VariableReferenceErrorMessage(
void *theEnv,
struct symbolHashNode *theVariable,
struct lhsParseNode *theExpression,
int whichCE,
struct symbolHashNode *slotName,
int theField)
{
struct expr *temprv;
/*=============================*/
/* Print the error message ID. */
/*=============================*/
PrintErrorID(theEnv,"ANALYSIS",4,TRUE);
/*=================================*/
/* Print the name of the variable. */
/*=================================*/
EnvPrintRouter(theEnv,WERROR,"Variable ?");
EnvPrintRouter(theEnv,WERROR,ValueToString(theVariable));
EnvPrintRouter(theEnv,WERROR," ");
/*=================================================*/
/* If the variable was found inside an expression, */
/* then print the expression. */
/*=================================================*/
if (theExpression != NULL)
{
temprv = LHSParseNodesToExpression(theEnv,theExpression);
ReturnExpression(theEnv,temprv->nextArg);
temprv->nextArg = NULL;
EnvPrintRouter(theEnv,WERROR,"found in the expression ");
PrintExpression(theEnv,WERROR,temprv);
EnvPrintRouter(theEnv,WERROR,"\n");
ReturnExpression(theEnv,temprv);
}
/*====================================================*/
/* Print the CE in which the variable was referenced. */
/*====================================================*/
EnvPrintRouter(theEnv,WERROR,"was referenced in CE #");
PrintLongInteger(theEnv,WERROR,(long int) whichCE);
/*=====================================*/
/* Identify the slot or field in which */
/* the variable was found. */
/*=====================================*/
if (slotName == NULL)
{
if (theField > 0)
{
EnvPrintRouter(theEnv,WERROR," field #");
PrintLongInteger(theEnv,WERROR,(long int) theField);
}
}
else
{
EnvPrintRouter(theEnv,WERROR," slot ");
EnvPrintRouter(theEnv,WERROR,ValueToString(slotName));
}
EnvPrintRouter(theEnv,WERROR," before being defined.\n");
}
/************************************************************/
/* VariableMixingErrorMessage: Prints the error message for */
/* the illegal mixing of single and multifield variables */
/* on the LHS of a rule. */
/************************************************************/
static void VariableMixingErrorMessage(
void *theEnv,
struct symbolHashNode *theVariable)
{
PrintErrorID(theEnv,"ANALYSIS",3,TRUE);
EnvPrintRouter(theEnv,WERROR,"Variable ?");
EnvPrintRouter(theEnv,WERROR,ValueToString(theVariable));
EnvPrintRouter(theEnv,WERROR," is used as both a single and multifield variable in the LHS\n");
}
#endif /* (! RUN_TIME) && (! BLOAD_ONLY) && DEFRULE_CONSTRUCT */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -