📄 analysis.c
字号:
/*******************************************************/
/* "C" Language Integrated Production System */
/* */
/* CLIPS Version 6.24 06/05/06 */
/* */
/* ANALYSIS MODULE */
/*******************************************************/
/*************************************************************/
/* Purpose: Analyzes LHS patterns to check for semantic */
/* errors and to determine variable comparisons and other */
/* tests which must be performed either in the pattern or */
/* join networks. */
/* */
/* Principal Programmer(s): */
/* Gary D. Riley */
/* */
/* Contributing Programmer(s): */
/* */
/* Revision History: */
/* */
/* 6.24: Renamed BOOLEAN macro type to intBool. */
/* */
/*************************************************************/
#define _ANALYSIS_SOURCE_
#include "setup.h"
#if (! RUN_TIME) && (! BLOAD_ONLY) && DEFRULE_CONSTRUCT
#include <stdio.h>
#define _STDIO_INCLUDED_
#include "constant.h"
#include "symbol.h"
#include "memalloc.h"
#include "exprnpsr.h"
#include "reorder.h"
#include "generate.h"
#include "pattern.h"
#include "router.h"
#include "ruledef.h"
#include "cstrnchk.h"
#include "cstrnutl.h"
#include "cstrnops.h"
#include "rulecstr.h"
#include "modulutl.h"
#include "analysis.h"
#if DEFGLOBAL_CONSTRUCT
#include "globldef.h"
#endif
/***************************************/
/* LOCAL INTERNAL FUNCTION DEFINITIONS */
/***************************************/
static int GetVariables(void *,struct lhsParseNode *);
static intBool UnboundVariablesInPattern(void *,struct lhsParseNode *,int);
static int PropagateVariableToNodes(void *,
struct lhsParseNode *,
int,
struct symbolHashNode *,
struct lhsParseNode *,
int,int,int);
static struct lhsParseNode *CheckExpression(void *,
struct lhsParseNode *,
struct lhsParseNode *,
int,
struct symbolHashNode *,
int);
static void VariableReferenceErrorMessage(void *,
struct symbolHashNode *,
struct lhsParseNode *,
int,
struct symbolHashNode *,
int);
static int ProcessField(void *theEnv,
struct lhsParseNode *,
struct lhsParseNode *,
struct lhsParseNode *);
static int ProcessVariable(void *,
struct lhsParseNode *,
struct lhsParseNode *,
struct lhsParseNode *);
static void VariableMixingErrorMessage(void *,struct symbolHashNode *);
static int PropagateVariableDriver(void *,
struct lhsParseNode *,
struct lhsParseNode *,
struct lhsParseNode *,
int,struct symbolHashNode *,
struct lhsParseNode *,
int);
/******************************************************************/
/* VariableAnalysis: Propagates variables references to other */
/* variables in the LHS and determines if there are any illegal */
/* variable references (e.g. referring to an unbound variable). */
/* The propagation of variable references simply means all */
/* subsequent references of a variable are made to "point" back */
/* to the variable being propagated. */
/******************************************************************/
globle int VariableAnalysis(
void *theEnv,
struct lhsParseNode *patternPtr)
{
struct lhsParseNode *rv, *theList, *tempList;
int errorFlag = FALSE;
/*======================================================*/
/* Loop through all of the CEs in the rule to determine */
/* which variables refer to other variables and whether */
/* any semantic errors exist when refering to variables */
/* (such as referring to a variable that was not */
/* previously bound). */
/*======================================================*/
while (patternPtr != NULL)
{
/*=========================================================*/
/* If a pattern CE is encountered, propagate any variables */
/* found in the pattern and note any illegal references to */
/* other variables. */
/*=========================================================*/
if (patternPtr->type == PATTERN_CE)
{
/*====================================================*/
/* Determine if the fact address associated with this */
/* pattern illegally refers to other variables. */
/*====================================================*/
if ((patternPtr->value != NULL) &&
(patternPtr->referringNode != NULL))
{
errorFlag = TRUE;
if (patternPtr->referringNode->index == -1)
{
PrintErrorID(theEnv,"ANALYSIS",1,TRUE);
EnvPrintRouter(theEnv,WERROR,"Duplicate pattern-address ?");
EnvPrintRouter(theEnv,WERROR,ValueToString(patternPtr->value));
EnvPrintRouter(theEnv,WERROR," found in CE #");
PrintLongInteger(theEnv,WERROR,(long) patternPtr->whichCE);
EnvPrintRouter(theEnv,WERROR,".\n");
}
else
{
PrintErrorID(theEnv,"ANALYSIS",2,TRUE);
EnvPrintRouter(theEnv,WERROR,"Pattern-address ?");
EnvPrintRouter(theEnv,WERROR,ValueToString(patternPtr->value));
EnvPrintRouter(theEnv,WERROR," used in CE #");
PrintLongInteger(theEnv,WERROR,(long) patternPtr->whichCE);
EnvPrintRouter(theEnv,WERROR," was previously bound within a pattern CE.\n");
}
}
/*====================================================*/
/* Propagate the pattern and field location of bound */
/* variables found in this pattern to other variables */
/* in the same semantic scope as the bound variable. */
/*====================================================*/
if (GetVariables(theEnv,patternPtr)) return(TRUE);
}
/*==============================================================*/
/* If a test CE is encountered, make sure that all references */
/* to variables have been previously bound. If they are bound */
/* then replace the references to variables with function calls */
/* to retrieve the variables. */
/*==============================================================*/
else if (patternPtr->type == TEST_CE)
{
/*=====================================================*/
/* Verify that all variables were referenced properly. */
/*=====================================================*/
rv = CheckExpression(theEnv,patternPtr->expression,NULL,(int) patternPtr->whichCE,NULL,0);
/*=========================================================*/
/* Determine the type and value constraints implied by the */
/* expression and propagate these constraints to other */
/* variables in the LHS. For example, the expression */
/* (+ ?x 1) implies that ?x is a number. */
/*=========================================================*/
theList = GetExpressionVarConstraints(theEnv,patternPtr->expression);
for (tempList = theList; tempList != NULL; tempList = tempList->right)
{
if (PropagateVariableDriver(theEnv,patternPtr,patternPtr,NULL,SF_VARIABLE,
(SYMBOL_HN *) tempList->value,tempList,FALSE))
{
ReturnLHSParseNodes(theEnv,theList);
return(TRUE);
}
}
ReturnLHSParseNodes(theEnv,theList);
/*========================================================*/
/* If the variables in the expression were all referenced */
/* properly, then create the expression to use in the */
/* join network. */
/*========================================================*/
if (rv != NULL)
{ errorFlag = TRUE; }
else
{ patternPtr->networkTest = GetvarReplace(theEnv,patternPtr->expression); }
}
/*=====================================================*/
/* Move on to the next pattern in the LHS of the rule. */
/*=====================================================*/
patternPtr = patternPtr->bottom;
}
/*==========================================*/
/* Return the error status of the analysis. */
/*==========================================*/
return(errorFlag);
}
/****************************************************************/
/* GetVariables: Loops through each field/slot within a pattern */
/* and propagates the pattern and field location of bound */
/* variables found in the pattern to other variables within */
/* the same semantic scope as the bound variables. */
/****************************************************************/
static int GetVariables(
void *theEnv,
struct lhsParseNode *thePattern)
{
struct lhsParseNode *patternHead = thePattern;
struct lhsParseNode *multifieldHeader = NULL;
/*======================================================*/
/* Loop through all the fields/slots found in a pattern */
/* looking for binding instances of variables. */
/*======================================================*/
while (thePattern != NULL)
{
/*================================================*/
/* A multifield slot contains a sublist of fields */
/* that must be traversed and checked. */
/*================================================*/
if (thePattern->multifieldSlot)
{
multifieldHeader = thePattern;
thePattern = thePattern->bottom;
}
/*==================================================*/
/* Propagate the binding occurences of single field */
/* variables, multifield variables, and fact */
/* addresses to other occurences of the variable. */
/* If an error is encountered, return TRUE. */
/*==================================================*/
if (thePattern != NULL)
{
if ((thePattern->type == SF_VARIABLE) ||
(thePattern->type == MF_VARIABLE) ||
((thePattern->type == PATTERN_CE) && (thePattern->value != NULL)))
{
if (ProcessVariable(theEnv,thePattern,multifieldHeader,patternHead))
{ return(TRUE); }
}
else
{
if (ProcessField(theEnv,thePattern,multifieldHeader,patternHead))
{ return(TRUE); }
}
}
/*===============================================*/
/* Move on to the next field/slot in the pattern */
/* or to the next field in a multifield slot. */
/*===============================================*/
if (thePattern == NULL)
{ thePattern = multifieldHeader; }
else if ((thePattern->right == NULL) && (multifieldHeader != NULL))
{
thePattern = multifieldHeader;
multifieldHeader = NULL;
}
thePattern = thePattern->right;
}
/*===============================*/
/* Return FALSE to indicate that */
/* no errors were detected. */
/*===============================*/
return(FALSE);
}
/******************************************************/
/* ProcessVariable: Processes a single occurence of a */
/* variable by propagating references to it. */
/******************************************************/
static int ProcessVariable(
void *theEnv,
struct lhsParseNode *thePattern,
struct lhsParseNode *multifieldHeader,
struct lhsParseNode *patternHead)
{
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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -