📄 analysis.c
字号:
/*******************************************************/ /* "C" Language Integrated Production System */ /* */ /* CLIPS Version 6.05 04/09/97 */ /* */ /* 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: *//* *//*************************************************************/#define _ANALYSIS_SOURCE_#include "setup.h"#if (! RUN_TIME) && (! BLOAD_ONLY) && DEFRULE_CONSTRUCT#include <stdio.h>#define _CLIPS_STDIO_#include "constant.h"#include "symbol.h"#include "clipsmem.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 *//***************************************/ #if ANSI_COMPILER static int GetVariables(struct lhsParseNode *); static BOOLEAN UnboundVariablesInPattern(struct lhsParseNode *,int); static int PropagateVariableToNodes(struct lhsParseNode *, int, struct symbolHashNode *, struct lhsParseNode *, int,int,int); static struct lhsParseNode *CheckExpression(struct lhsParseNode *, struct lhsParseNode *, int, struct symbolHashNode *, int); static VOID VariableReferenceErrorMessage(struct symbolHashNode *, struct lhsParseNode *, int, struct symbolHashNode *, int); static int ProcessField(struct lhsParseNode *, struct lhsParseNode *, struct lhsParseNode *); static int ProcessVariable(struct lhsParseNode *, struct lhsParseNode *, struct lhsParseNode *); static VOID VariableMixingErrorMessage(struct symbolHashNode *); static int PropagateVariableDriver(struct lhsParseNode *, struct lhsParseNode *, struct lhsParseNode *, int,struct symbolHashNode *, struct lhsParseNode *, int);#else static int GetVariables(); static BOOLEAN UnboundVariablesInPattern(); static int PropagateVariableToNodes(); static struct lhsParseNode *CheckExpression(); static VOID VariableReferenceErrorMessage(); static int ProcessField(); static int ProcessVariable(); static VOID VariableMixingErrorMessage(); static int PropagateVariableDriver();#endif /******************************************************************//* 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(patternPtr) struct lhsParseNode *patternPtr; { struct lhsParseNode *rv, *theList, *tempList; int errorFlag = CLIPS_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 = CLIPS_TRUE; if (patternPtr->referringNode->index == -1) { PrintErrorID("ANALYSIS",1,CLIPS_TRUE); PrintCLIPS(WERROR,"Duplicate pattern-address ?"); PrintCLIPS(WERROR,ValueToString(patternPtr->value)); PrintCLIPS(WERROR," found in CE #"); PrintLongInteger(WERROR,(long) patternPtr->whichCE); PrintCLIPS(WERROR,".\n"); } else { PrintErrorID("ANALYSIS",2,CLIPS_TRUE); PrintCLIPS(WERROR,"Pattern-address ?"); PrintCLIPS(WERROR,ValueToString(patternPtr->value)); PrintCLIPS(WERROR," used in CE #"); PrintLongInteger(WERROR,(long) patternPtr->whichCE); PrintCLIPS(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(patternPtr)) return(CLIPS_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(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(patternPtr->expression); for (tempList = theList; tempList != NULL; tempList = tempList->right) { if (PropagateVariableDriver(patternPtr,patternPtr,NULL,SF_VARIABLE, tempList->value,tempList,CLIPS_FALSE)) { ReturnLHSParseNodes(theList); return(CLIPS_TRUE); } } ReturnLHSParseNodes(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 = CLIPS_TRUE; } else { patternPtr->networkTest = GetvarReplace(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(thePattern) 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(thePattern,multifieldHeader,patternHead)) { return(CLIPS_TRUE); } } else { if (ProcessField(thePattern,multifieldHeader,patternHead)) { return(CLIPS_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(CLIPS_FALSE); } /******************************************************//* ProcessVariable: Processes a single occurence of a *//* variable by propagating references to it. */ /******************************************************/static int ProcessVariable(thePattern,multifieldHeader,patternHead) struct lhsParseNode *thePattern, *multifieldHeader, *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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -