static struct lhsParseNode *UnionVariableConstraints( struct lhsParseNode *list1, struct lhsParseNode *list2) { struct lhsParseNode *list3 = NULL, *trace, *temp; /*===================================*/ /* Loop through all of the variables */ /* in the first list. */ /*===================================*/ while (list1 != NULL) { /*=============================================*/ /* Search for the variable in the second list. */ /*=============================================*/ for (trace = list2; trace != NULL; trace = trace->right) { /*============================================*/ /* If the variable is found in both lists, */ /* union the constraints and add the variable */ /* to the new list being constructed. */ /*============================================*/ if (list1->value == trace->value) { temp = GetLHSParseNode(); temp->derivedConstraints = TRUE; temp->value = list1->value; temp->constraints = UnionConstraints(list1->constraints,trace->constraints); temp->right = list3; list3 = temp; break; } } /*==============================*/ /* Move on to the next variable */ /* in the first list. */ /*==============================*/ temp = list1->right; list1->right = NULL; ReturnLHSParseNodes(list1); list1 = temp; } /*====================================*/ /* Free the items in the second list. */ /*====================================*/ ReturnLHSParseNodes(list2); /*======================*/ /* Return the new list. */ /*======================*/ return(list3); }
globle struct lhsParseNode *DeftemplateLHSParse( void *theEnv, char *readSource, struct deftemplate *theDeftemplate) { struct lhsParseNode *head, *firstSlot; struct token theToken; int error; /*===============================================================*/ /* Make sure the deftemplate name is not connected to subfields. */ /*===============================================================*/ GetToken(theEnv,readSource,&theToken); if ((theToken.type == OR_CONSTRAINT) || (theToken.type == AND_CONSTRAINT)) { SyntaxErrorMessage(theEnv,(char*)"deftemplate patterns"); return(NULL); } /*===================================================*/ /* Create the pattern node for the deftemplate name. */ /*===================================================*/ head = GetLHSParseNode(theEnv); head->type = SF_WILDCARD; head->negated = FALSE; head->exists = FALSE; head->index = 0; head->slotNumber = 1; head->bottom = GetLHSParseNode(theEnv); head->bottom->type = SYMBOL; head->bottom->negated = FALSE; head->bottom->exists = FALSE; head->bottom->value = (void *) theDeftemplate->header.name; /*==========================================*/ /* Get the other fields in the deftemplate. */ /*==========================================*/ error = FALSE; firstSlot = GetLHSSlots(theEnv,readSource,&theToken,theDeftemplate,&error); if (error) { ReturnLHSParseNodes(theEnv,firstSlot); ReturnLHSParseNodes(theEnv,head); return(NULL); } /*=========================*/ /* Return the LHS pattern. */ /*=========================*/ head->right = firstSlot; return(head); }
static struct lhsParseNode *TestPattern( void *theEnv, EXEC_STATUS, char *readSource, int *error) { struct lhsParseNode *theNode; struct token theToken; struct expr *theExpression; /*================================================*/ /* Create the data specification for the test CE. */ /*================================================*/ SavePPBuffer(theEnv,execStatus," "); theNode = GetLHSParseNode(theEnv,execStatus); theNode->type = TEST_CE; theExpression = Function0Parse(theEnv,execStatus,readSource); theNode->expression = ExpressionToLHSParseNodes(theEnv,execStatus,theExpression); ReturnExpression(theEnv,execStatus,theExpression); if (theNode->expression == NULL) { *error = TRUE; ReturnLHSParseNodes(theEnv,execStatus,theNode); return(NULL); } /*=========================================================*/ /* Check for the closing right parenthesis of the test CE. */ /*=========================================================*/ GetToken(theEnv,execStatus,readSource,&theToken); if (theToken.type != RPAREN) { SyntaxErrorMessage(theEnv,execStatus,"test conditional element"); *error = TRUE; ReturnLHSParseNodes(theEnv,execStatus,theNode); return(NULL); } /*=====================*/ /* Return the test CE. */ /*=====================*/ return(theNode); }
static void AttachTestCEsToPatternCEs( void *theEnv, struct lhsParseNode *theLHS) { struct lhsParseNode *lastNode, *tempNode; if (theLHS == NULL) return; /*=============================================================*/ /* Attach test CEs that can be attached directly to a pattern. */ /*=============================================================*/ lastNode = theLHS; theLHS = lastNode->bottom; while (theLHS != NULL) { if ((theLHS->type != TEST_CE) || (lastNode->beginNandDepth != lastNode->endNandDepth) || (lastNode->beginNandDepth != theLHS->beginNandDepth)) { lastNode = theLHS; theLHS = theLHS->bottom; continue; } if (lastNode->negated) { lastNode->secondaryNetworkTest = CombineExpressions(theEnv,lastNode->secondaryNetworkTest,theLHS->networkTest); } else { lastNode->networkTest = CombineExpressions(theEnv,lastNode->networkTest,theLHS->networkTest); } theLHS->networkTest = NULL; tempNode = theLHS->bottom; theLHS->bottom = NULL; lastNode->bottom = tempNode; lastNode->endNandDepth = theLHS->endNandDepth; ReturnLHSParseNodes(theEnv,theLHS); theLHS = tempNode; } }
static struct lhsParseNode *AddToVariableConstraints( struct lhsParseNode *oldList, struct lhsParseNode *newItems) { CONSTRAINT_RECORD *newConstraints; struct lhsParseNode *temp, *trace; /*=================================================*/ /* Loop through each of the new constraints adding */ /* it to the list if it's not already present or */ /* modifying the constraint if it is. */ /*=================================================*/ while (newItems != NULL) { /*==========================================*/ /* Get the next item since the next pointer */ /* value (right) needs to be set to NULL. */ /*==========================================*/ temp = newItems->right; newItems->right = NULL; /*===================================*/ /* Search the list for the variable. */ /*===================================*/ for (trace = oldList; trace != NULL; trace = trace->right) { /*=========================================*/ /* If the variable is already in the list, */ /* modify the constraint already there to */ /* include the new constraint. */ /*=========================================*/ if (trace->value == newItems->value) { newConstraints = IntersectConstraints(trace->constraints, newItems->constraints); RemoveConstraint(trace->constraints); trace->constraints = newConstraints; ReturnLHSParseNodes(newItems); break; } } /*=================================*/ /* Add the variable constraints to */ /* the list if it wasn't found. */ /*=================================*/ if (trace == NULL) { newItems->right = oldList; oldList = newItems; } /*===========================*/ /* Move on to the next item. */ /*===========================*/ newItems = temp; } return(oldList); }
static struct lhsParseNode *GetSingleLHSSlot( void *theEnv, char *readSource, struct token *tempToken, struct templateSlot *slotPtr, int *error, short position) { struct lhsParseNode *nextSlot; SYMBOL_HN *slotName; /*================================================*/ /* Get the slot name and read in the first token. */ /*================================================*/ slotName = (SYMBOL_HN *) tempToken->value; SavePPBuffer(theEnv,(char*)" "); GetToken(theEnv,readSource,tempToken); /*====================================*/ /* Get value for a single field slot. */ /*====================================*/ if (slotPtr->multislot == FALSE) { /*=======================*/ /* Get the single value. */ /*=======================*/ nextSlot = RestrictionParse(theEnv,readSource,tempToken,FALSE, slotPtr->slotName,(short) (position - 1), slotPtr->constraints,0); if (nextSlot == NULL) { *error = TRUE; return(NULL); } /*======================================*/ /* Multi field wildcards and variables */ /* not allowed in a single field slot. */ /*======================================*/ if ((nextSlot->type == MF_VARIABLE) || (nextSlot->type == MULTIFIELD)) { SingleFieldSlotCardinalityError(theEnv,slotPtr->slotName->contents); *error = TRUE; ReturnLHSParseNodes(theEnv,nextSlot); return(NULL); } } /*===================================*/ /* Get values for a multifield slot. */ /*===================================*/ else { nextSlot = RestrictionParse(theEnv,readSource,tempToken,TRUE,slotName,(short) (position - 1), slotPtr->constraints,1); if (nextSlot == NULL) { *error = TRUE; return(NULL); } } /*========================================================*/ /* The slot definition must end with a right parenthesis. */ /*========================================================*/ if (tempToken->type != RPAREN) { PPBackup(theEnv); SavePPBuffer(theEnv,(char*)" "); SavePPBuffer(theEnv,tempToken->printForm); SyntaxErrorMessage(theEnv,(char*)"deftemplate patterns"); *error = TRUE; ReturnLHSParseNodes(theEnv,nextSlot); return(NULL); } /*===============================================*/ /* Fix the pretty print output if the multifield */ /* slot contained no restrictions. */ /*===============================================*/ if ((nextSlot->bottom == NULL) && slotPtr->multislot) { PPBackup(theEnv); PPBackup(theEnv); SavePPBuffer(theEnv,(char*)")"); } /*=================================*/ /* Add the slot values to the slot */ /* structure and return it. */ /*=================================*/ return(nextSlot); }
static int ProcessField( void *theEnv, struct lhsParseNode *thePattern, struct lhsParseNode *multifieldHeader, struct lhsParseNode *patternHead, int patternHeadType, struct nandFrame *theNandFrames) { struct lhsParseNode *theList, *tempList; /*====================================================*/ /* Nothing needs to be done for the node representing */ /* the entire pattern. Return FALSE to indicate that */ /* no errors were generated. */ /*====================================================*/ if (thePattern->type == PATTERN_CE) return(FALSE); /*====================================================================*/ /* Derive a set of constraints based on values found in the slot or */ /* field. For example, if a slot can only contain the values 1, 2, or */ /* 3, the field constraint ~2 would generate a constraint record that */ /* only allows the value 1 or 3. Once generated, the constraints are */ /* propagated to other slots and fields. */ /*====================================================================*/ theList = DeriveVariableConstraints(theEnv,thePattern); for (tempList = theList; tempList != NULL; tempList = tempList->right) { if (PropagateVariableDriver(theEnv,patternHead,thePattern,multifieldHeader,tempList->type, (SYMBOL_HN *) tempList->value,tempList,FALSE,patternHeadType)) { ReturnLHSParseNodes(theEnv,theList); return(TRUE); } } ReturnLHSParseNodes(theEnv,theList); /*===========================================================*/ /* Check for "variable referenced, but not previously bound" */ /* errors. Return TRUE if this type of error is detected. */ /*===========================================================*/ if (UnboundVariablesInPattern(theEnv,thePattern,(int) patternHead->whichCE)) { return(TRUE); } /*==================================================*/ /* Check for constraint errors for this slot/field. */ /* If the slot/field has unmatchable constraints */ /* then return TRUE to indicate a semantic error. */ /*==================================================*/ if (ProcessConnectedConstraints(theEnv,thePattern,multifieldHeader,patternHead)) { return(TRUE); } /*==============================================================*/ /* Convert the slot/field constraint to a series of expressions */ /* that will be used in the pattern and join networks. */ /*==============================================================*/ FieldConversion(theEnv,thePattern,patternHead,theNandFrames); /*=========================================================*/ /* Return FALSE to indicate that no errors were generated. */ /*=========================================================*/ return(FALSE); }
static struct lhsParseNode *LiteralRestrictionParse( char *readSource, struct token *theToken, int *error) { struct lhsParseNode *topNode; struct expr *theExpression; /*============================================*/ /* Create a node to represent the constraint. */ /*============================================*/ topNode = GetLHSParseNode(); /*=================================================*/ /* 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(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(readSource); if (theExpression == NULL) { *error = TRUE; ReturnLHSParseNodes(topNode); return(NULL); } topNode->type = RETURN_VALUE_CONSTRAINT; topNode->expression = ExpressionToLHSParseNodes(theExpression); ReturnExpression(theExpression); } /*=============================*/ /* If the symbol is a :, parse */ /* a predicate constraint. */ /*=============================*/ else if (strcmp(ValueToString(theToken->value),":") == 0) { theExpression = Function0Parse(readSource); if (theExpression == NULL) { *error = TRUE; ReturnLHSParseNodes(topNode); return(NULL); } topNode->type = PREDICATE_CONSTRAINT; topNode->expression = ExpressionToLHSParseNodes(theExpression); ReturnExpression(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("defrule"); *error = TRUE; ReturnLHSParseNodes(topNode); return(NULL); } /*===============================*/ /* Return the parsed constraint. */ /*===============================*/ return(topNode); }
struct lhsParseNode *RestrictionParse( char *readSource, struct token *theToken, int multifieldSlot, struct symbolHashNode *theSlot, int slotNumber, CONSTRAINT_RECORD *theConstraints, int position) { struct lhsParseNode *topNode = NULL, *lastNode = NULL, *nextNode; int numberOfSingleFields = 0; int numberOfMultifields = 0; int startPosition = position; int error = FALSE; CONSTRAINT_RECORD *tempConstraints; /*==================================================*/ /* Keep parsing fields until a right parenthesis is */ /* encountered. This will either indicate the end */ /* of an instance or deftemplate slot or the end of */ /* an ordered fact. */ /*==================================================*/ while (theToken->type != RPAREN) { /*========================================*/ /* Look for either a single or multifield */ /* wildcard or a conjuctive restriction. */ /*========================================*/ if ((theToken->type == SF_WILDCARD) || (theToken->type == MF_WILDCARD)) { nextNode = GetLHSParseNode(); nextNode->type = theToken->type; nextNode->negated = FALSE; GetToken(readSource,theToken); } else { nextNode = ConjuctiveRestrictionParse(readSource,theToken,&error); if (nextNode == NULL) { ReturnLHSParseNodes(topNode); return(NULL); } } /*========================================================*/ /* Fix up the pretty print representation of a multifield */ /* slot so that the fields don't run together. */ /*========================================================*/ if ((theToken->type != RPAREN) && (multifieldSlot == TRUE)) { PPBackup(); SavePPBuffer(" "); SavePPBuffer(theToken->printForm); } /*========================================*/ /* Keep track of the number of single and */ /* multifield restrictions encountered. */ /*========================================*/ if ((nextNode->type == SF_WILDCARD) || (nextNode->type == SF_VARIABLE)) { numberOfSingleFields++; } else { numberOfMultifields++; } /*===================================*/ /* Assign the slot name and indices. */ /*===================================*/ nextNode->slot = theSlot; nextNode->slotNumber = slotNumber; nextNode->index = position++; /*==============================================*/ /* If we're not dealing with a multifield slot, */ /* attach the constraints directly to the node */ /* and return. */ /*==============================================*/ if (! multifieldSlot) { if (theConstraints == NULL) { if (nextNode->type == SF_VARIABLE) { nextNode->constraints = GetConstraintRecord(); } else nextNode->constraints = NULL; } else nextNode->constraints = theConstraints; return(nextNode); } /*====================================================*/ /* Attach the restriction to the list of restrictions */ /* already parsed for this slot or ordered fact. */ /*====================================================*/ if (lastNode == NULL) topNode = nextNode; else lastNode->right = nextNode; lastNode = nextNode; } /*=====================================================*/ /* Once we're through parsing, check to make sure that */ /* a single field slot was given a restriction. If the */ /* following test fails, then we know we're dealing */ /* with a multifield slot. */ /*=====================================================*/ if ((topNode == NULL) && (! multifieldSlot)) { SyntaxErrorMessage("defrule"); return(NULL); } /*===============================================*/ /* Loop through each of the restrictions in the */ /* list of restrictions for the multifield slot. */ /*===============================================*/ for (nextNode = topNode; nextNode != NULL; nextNode = nextNode->right) { /*===================================================*/ /* Assign a constraint record to each constraint. If */ /* the slot has an explicit constraint, then copy */ /* this and store it with the constraint. Otherwise, */ /* create a constraint record for a single field */ /* constraint and skip the constraint modifications */ /* for a multifield constraint. */ /*===================================================*/ if (theConstraints == NULL) { if (nextNode->type == SF_VARIABLE) { nextNode->constraints = GetConstraintRecord(); } else { continue; } } else { nextNode->constraints = CopyConstraintRecord(theConstraints); } /*==========================================*/ /* Remove the min and max field constraints */ /* for the entire slot from the constraint */ /* record for this single constraint. */ /*==========================================*/ ReturnExpression(nextNode->constraints->minFields); ReturnExpression(nextNode->constraints->maxFields); nextNode->constraints->minFields = GenConstant(SYMBOL,NegativeInfinity); nextNode->constraints->maxFields = GenConstant(SYMBOL,PositiveInfinity); nextNode->derivedConstraints = TRUE; /*====================================================*/ /* If we're not dealing with a multifield constraint, */ /* then no further modifications are needed to the */ /* min and max constraints for this constraint. */ /*====================================================*/ if ((nextNode->type != MF_WILDCARD) && (nextNode->type != MF_VARIABLE)) { continue; } /*==========================================================*/ /* Create a separate constraint record to keep track of the */ /* cardinality information for this multifield constraint. */ /*==========================================================*/ tempConstraints = GetConstraintRecord(); SetConstraintType(MULTIFIELD,tempConstraints); tempConstraints->singlefieldsAllowed = FALSE; tempConstraints->multifield = nextNode->constraints; nextNode->constraints = tempConstraints; /*=====================================================*/ /* Adjust the min and max field values for this single */ /* multifield constraint based on the min and max */ /* fields for the entire slot and the number of single */ /* field values contained in the slot. */ /*=====================================================*/ if (theConstraints->maxFields->value != PositiveInfinity) { ReturnExpression(tempConstraints->maxFields); tempConstraints->maxFields = GenConstant(INTEGER,AddLong(ValueToLong(theConstraints->maxFields->value) - numberOfSingleFields)); } if ((numberOfMultifields == 1) && (theConstraints->minFields->value != NegativeInfinity)) { ReturnExpression(tempConstraints->minFields); tempConstraints->minFields = GenConstant(INTEGER,AddLong(ValueToLong(theConstraints->minFields->value) - numberOfSingleFields)); } } /*================================================*/ /* If a multifield slot is being parsed, place a */ /* node on top of the list of constraints parsed. */ /*================================================*/ if (multifieldSlot) { nextNode = GetLHSParseNode(); nextNode->type = MF_WILDCARD; nextNode->multifieldSlot = TRUE; nextNode->bottom = topNode; nextNode->slot = theSlot; nextNode->slotNumber = slotNumber; nextNode->index = startPosition; nextNode->constraints = theConstraints; topNode = nextNode; TallyFieldTypes(topNode->bottom); } /*=================================*/ /* Return the list of constraints. */ /*=================================*/ return(topNode); }
static struct lhsParseNode *RemoveUnneededSlots( void *theEnv, struct lhsParseNode *thePattern) { struct lhsParseNode *tempPattern = thePattern; struct lhsParseNode *lastPattern = NULL, *head = thePattern; struct expr *theTest; while (tempPattern != NULL) { /*=============================================================*/ /* A single field slot that has no pattern network expression */ /* associated with it can be removed (i.e. any value contained */ /* in this slot will satisfy the pattern being matched). */ /*=============================================================*/ if (((tempPattern->type == SF_WILDCARD) || (tempPattern->type == SF_VARIABLE)) && (tempPattern->networkTest == NULL)) { if (lastPattern != NULL) lastPattern->right = tempPattern->right; else head = tempPattern->right; tempPattern->right = NULL; ReturnLHSParseNodes(theEnv,tempPattern); if (lastPattern != NULL) tempPattern = lastPattern->right; else tempPattern = head; } /*=======================================================*/ /* A multifield variable or wildcard within a multifield */ /* slot can be removed if there are no other multifield */ /* variables or wildcards contained in the same slot */ /* (and the multifield has no expressions which must be */ /* evaluated in the fact pattern network). */ /*=======================================================*/ else if (((tempPattern->type == MF_WILDCARD) || (tempPattern->type == MF_VARIABLE)) && (tempPattern->multifieldSlot == FALSE) && (tempPattern->networkTest == NULL) && (tempPattern->multiFieldsBefore == 0) && (tempPattern->multiFieldsAfter == 0)) { if (lastPattern != NULL) lastPattern->right = tempPattern->right; else head = tempPattern->right; tempPattern->right = NULL; ReturnLHSParseNodes(theEnv,tempPattern); if (lastPattern != NULL) tempPattern = lastPattern->right; else tempPattern = head; } /*==================================================================*/ /* A multifield wildcard or variable contained in a multifield slot */ /* that contains no other multifield wildcards or variables, but */ /* does have an expression that must be evaluated, can be changed */ /* to a single field pattern node with the same expression. */ /*==================================================================*/ else if (((tempPattern->type == MF_WILDCARD) || (tempPattern->type == MF_VARIABLE)) && (tempPattern->multifieldSlot == FALSE) && (tempPattern->networkTest != NULL) && (tempPattern->multiFieldsBefore == 0) && (tempPattern->multiFieldsAfter == 0)) { tempPattern->type = SF_WILDCARD; lastPattern = tempPattern; tempPattern = tempPattern->right; } /*=========================================================*/ /* If we're dealing with a multifield slot with no slot */ /* restrictions, then treat the multfield slot as a single */ /* field slot, but attach a test which verifies that the */ /* slot contains a zero length multifield value. */ /*=========================================================*/ else if ((tempPattern->type == MF_WILDCARD) && (tempPattern->multifieldSlot == TRUE) && (tempPattern->bottom == NULL)) { tempPattern->type = SF_WILDCARD; tempPattern->networkTest = FactGenCheckZeroLength(theEnv,tempPattern->slotNumber); tempPattern->multifieldSlot = FALSE; lastPattern = tempPattern; tempPattern = tempPattern->right; } /*===================================================*/ /* Recursively call RemoveUnneededSlots for the slot */ /* restrictions contained within a multifield slot. */ /*===================================================*/ else if ((tempPattern->type == MF_WILDCARD) && (tempPattern->multifieldSlot == TRUE)) { /*=======================================================*/ /* Add an expression to the first pattern restriction in */ /* the multifield slot that determines whether or not */ /* the fact's slot value contains the minimum number of */ /* required fields to satisfy the pattern restrictions */ /* for this slot. The length check is place before any */ /* other tests, so that preceeding checks do not have to */ /* determine if there are enough fields in the slot to */ /* safely retrieve a value. */ /*=======================================================*/ theTest = FactGenCheckLength(theEnv,tempPattern->bottom); theTest = CombineExpressions(theEnv,theTest,tempPattern->bottom->networkTest); tempPattern->bottom->networkTest = theTest; /*=========================================================*/ /* Remove any unneeded pattern restrictions from the slot. */ /*=========================================================*/ tempPattern->bottom = RemoveUnneededSlots(theEnv,tempPattern->bottom); /*===========================================================*/ /* If the slot no longer contains any restrictions, then the */ /* multifield slot can be completely removed. In any case, */ /* move on to the next slot to be examined for removal. */ /*===========================================================*/ if (tempPattern->bottom == NULL) { if (lastPattern != NULL) lastPattern->right = tempPattern->right; else head = tempPattern->right; tempPattern->right = NULL; ReturnLHSParseNodes(theEnv,tempPattern); if (lastPattern != NULL) tempPattern = lastPattern->right; else tempPattern = head; } else { lastPattern = tempPattern; tempPattern = tempPattern->right; } } /*=======================================================*/ /* If none of the other tests for removing slots or slot */ /* restrictions apply, then move on to the next slot or */ /* slot restriction to be tested. */ /*=======================================================*/ else { lastPattern = tempPattern; tempPattern = tempPattern->right; } } /*======================================*/ /* Return the pattern with unused slots */ /* and slot restrictions removed. */ /*======================================*/ return(head); }
static struct lhsParseNode *RuleBodyParse( void *theEnv, char *readSource, struct token *theToken, char *ruleName, int *error) { struct lhsParseNode *theNode, *otherNodes; /*=============================*/ /* Set the error return value. */ /*=============================*/ *error = FALSE; /*==================================================*/ /* If we're already at the separator, "=>", between */ /* the LHS and RHS, then the LHS is empty. */ /*==================================================*/ if ((theToken->type == SYMBOL) ? (strcmp(ValueToString(theToken->value),"=>") == 0) : FALSE) { return(NULL); } /*===========================================*/ /* Parse the first pattern as a special case */ /* (the declare statement is allowed). */ /*===========================================*/ theNode = LHSPattern(theEnv,readSource,SYMBOL,"=>",error,TRUE,theToken,ruleName); if (*error == TRUE) { ReturnLHSParseNodes(theEnv,theNode); return(NULL); } PPCRAndIndent(theEnv); /*======================================*/ /* Parse the other patterns in the LHS. */ /*======================================*/ otherNodes = GroupPatterns(theEnv,readSource,SYMBOL,"=>",error); if (*error == TRUE) { ReturnLHSParseNodes(theEnv,theNode); return(NULL); } /*================================================*/ /* Construct the final LHS by combining the first */ /* pattern with the remaining patterns. */ /*================================================*/ if (theNode == NULL) { theNode = otherNodes; } else { theNode->bottom = otherNodes; } /*=======================*/ /* Return the final LHS. */ /*=======================*/ return(theNode); }
static struct lhsParseNode *SimplePatternParse( void *theEnv, char *readSource, struct token *theToken, int *error) { struct lhsParseNode *theNode; struct patternParser *tempParser; /*=================================================*/ /* The first field of a pattern must be a symbol. */ /* In addition, the symbols ":" and "=" can not */ /* be used because they have special significance. */ /*=================================================*/ if (theToken->type != SYMBOL) { SyntaxErrorMessage(theEnv,"the first field of a pattern"); *error = TRUE; return(NULL); } else if ((strcmp(ValueToString(theToken->value),"=") == 0) || (strcmp(ValueToString(theToken->value),":") == 0)) { SyntaxErrorMessage(theEnv,"the field field of a pattern"); *error = TRUE; return(NULL); } /*===============================================*/ /* Construct the topmost node of the pattern CE. */ /*===============================================*/ theNode = GetLHSParseNode(theEnv); theNode->type = PATTERN_CE; theNode->negated = FALSE; /*======================================================*/ /* Search for a pattern parser that claims the pattern. */ /*======================================================*/ for (tempParser = PatternData(theEnv)->ListOfPatternParsers; tempParser != NULL; tempParser = tempParser->next) { if ((*tempParser->recognizeFunction)((SYMBOL_HN *) theToken->value)) { theNode->patternType = tempParser; theNode->right = (*tempParser->parseFunction)(theEnv,readSource,theToken); if (theNode->right == NULL) { *error = TRUE; ReturnLHSParseNodes(theEnv,theNode); return(NULL); } PropagatePatternType(theNode,tempParser); return(theNode); } } /*=================================*/ /* If a pattern parser couldn't be */ /* found, then signal an error. */ /*=================================*/ *error = TRUE; SyntaxErrorMessage(theEnv,"the field field of a pattern"); ReturnLHSParseNodes(theEnv,theNode); return(NULL); }
static struct lhsParseNode *AssignmentParse( void *theEnv, char *readSource, SYMBOL_HN *factAddress, int *error) { struct lhsParseNode *theNode; struct token theToken; /*=====================================================*/ /* Patterns cannot be bound if they are with a not CE. */ /*=====================================================*/ if (PatternData(theEnv)->WithinNotCE) { PrintErrorID(theEnv,"RULELHS",2,TRUE); EnvPrintRouter(theEnv,WERROR,"A pattern CE cannot be bound to a pattern-address within a not CE\n"); *error = TRUE; return(NULL); } /*===============================================*/ /* Check for binder token, "<-", after variable. */ /*===============================================*/ SavePPBuffer(theEnv," "); GetToken(theEnv,readSource,&theToken); if ((theToken.type == SYMBOL) ? (strcmp(ValueToString(theToken.value),"<-") != 0) : TRUE) { SyntaxErrorMessage(theEnv,"binding patterns"); *error = TRUE; return(NULL); } SavePPBuffer(theEnv," "); /*================================================*/ /* Check for opening left parenthesis of pattern. */ /*================================================*/ GetToken(theEnv,readSource,&theToken); if (theToken.type != LPAREN) { SyntaxErrorMessage(theEnv,"binding patterns"); *error = TRUE; return(NULL); } /*======================================================*/ /* Parse the pattern and return the data specification. */ /*======================================================*/ GetToken(theEnv,readSource,&theToken); theNode = SimplePatternParse(theEnv,readSource,&theToken,error); if (*error == TRUE) { ReturnLHSParseNodes(theEnv,theNode); return(NULL); } /*=============================================*/ /* Store the name of the variable to which the */ /* pattern is bound and return the pattern. */ /*=============================================*/ theNode->value = (void *) factAddress; return(theNode); }
globle int ParseDefrule( void *theEnv, const char *readSource) { #if (! RUN_TIME) && (! BLOAD_ONLY) SYMBOL_HN *ruleName; struct lhsParseNode *theLHS; struct expr *actions; struct token theToken; struct defrule *topDisjunct, *tempPtr; struct defruleModule *theModuleItem; int error; /*================================================*/ /* Flush the buffer which stores the pretty print */ /* representation for a rule. Add the already */ /* parsed keyword defrule to this buffer. */ /*================================================*/ SetPPBufferStatus(theEnv,ON); FlushPPBuffer(theEnv); SavePPBuffer(theEnv,"(defrule "); /*=========================================================*/ /* Rules cannot be loaded when a binary load is in effect. */ /*=========================================================*/ #if BLOAD || BLOAD_ONLY || BLOAD_AND_BSAVE if ((Bloaded(theEnv) == TRUE) && (! ConstructData(theEnv)->CheckSyntaxMode)) { CannotLoadWithBloadMessage(theEnv,"defrule"); return(TRUE); } #endif /*================================================*/ /* Parse the name and comment fields of the rule, */ /* deleting the rule if it already exists. */ /*================================================*/ #if DEBUGGING_FUNCTIONS DefruleData(theEnv)->DeletedRuleDebugFlags = 0; #endif ruleName = GetConstructNameAndComment(theEnv,readSource,&theToken,"defrule", EnvFindDefruleInModule,EnvUndefrule,"*",FALSE, TRUE,TRUE,FALSE); if (ruleName == NULL) return(TRUE); /*============================*/ /* Parse the LHS of the rule. */ /*============================*/ theLHS = ParseRuleLHS(theEnv,readSource,&theToken,ValueToString(ruleName),&error); if (error) { ReturnPackedExpression(theEnv,PatternData(theEnv)->SalienceExpression); PatternData(theEnv)->SalienceExpression = NULL; return(TRUE); } /*============================*/ /* Parse the RHS of the rule. */ /*============================*/ ClearParsedBindNames(theEnv); ExpressionData(theEnv)->ReturnContext = TRUE; actions = ParseRuleRHS(theEnv,readSource); if (actions == NULL) { ReturnPackedExpression(theEnv,PatternData(theEnv)->SalienceExpression); PatternData(theEnv)->SalienceExpression = NULL; ReturnLHSParseNodes(theEnv,theLHS); return(TRUE); } /*=======================*/ /* Process the rule LHS. */ /*=======================*/ topDisjunct = ProcessRuleLHS(theEnv,theLHS,actions,ruleName,&error); ReturnExpression(theEnv,actions); ClearParsedBindNames(theEnv); ReturnLHSParseNodes(theEnv,theLHS); if (error) { ReturnPackedExpression(theEnv,PatternData(theEnv)->SalienceExpression); PatternData(theEnv)->SalienceExpression = NULL; return(TRUE); } /*==============================================*/ /* If we're only checking syntax, don't add the */ /* successfully parsed defrule to the KB. */ /*==============================================*/ if (ConstructData(theEnv)->CheckSyntaxMode) { ReturnPackedExpression(theEnv,PatternData(theEnv)->SalienceExpression); PatternData(theEnv)->SalienceExpression = NULL; return(FALSE); } PatternData(theEnv)->SalienceExpression = NULL; /*======================================*/ /* Save the nice printout of the rules. */ /*======================================*/ SavePPBuffer(theEnv,"\n"); if (EnvGetConserveMemory(theEnv) == TRUE) { topDisjunct->header.ppForm = NULL; } else { topDisjunct->header.ppForm = CopyPPBuffer(theEnv); } /*=======================================*/ /* Store a pointer to the rule's module. */ /*=======================================*/ theModuleItem = (struct defruleModule *) GetModuleItem(theEnv,NULL,FindModuleItem(theEnv,"defrule")->moduleIndex); for (tempPtr = topDisjunct; tempPtr != NULL; tempPtr = tempPtr->disjunct) { tempPtr->header.whichModule = (struct defmoduleItemHeader *) theModuleItem; tempPtr->header.ppForm = topDisjunct->header.ppForm; } /*===============================================*/ /* Rule completely parsed. Add to list of rules. */ /*===============================================*/ AddToDefruleList(topDisjunct); /*========================================================================*/ /* If a rule is redefined, then we want to restore its breakpoint status. */ /*========================================================================*/ #if DEBUGGING_FUNCTIONS if (BitwiseTest(DefruleData(theEnv)->DeletedRuleDebugFlags,0)) { EnvSetBreak(theEnv,topDisjunct); } if (BitwiseTest(DefruleData(theEnv)->DeletedRuleDebugFlags,1) || EnvGetWatchItem(theEnv,"activations")) { EnvSetDefruleWatchActivations(theEnv,ON,(void *) topDisjunct); } if (BitwiseTest(DefruleData(theEnv)->DeletedRuleDebugFlags,2) || EnvGetWatchItem(theEnv,"rules")) { EnvSetDefruleWatchFirings(theEnv,ON,(void *) topDisjunct); } #endif /*================================*/ /* Perform the incremental reset. */ /*================================*/ IncrementalReset(theEnv,topDisjunct); /*=============================================*/ /* Return FALSE to indicate no errors occured. */ /*=============================================*/ #endif return(FALSE); }
static struct lhsParseNode *LHSPattern( void *theEnv, char *readSource, int terminator, char *terminatorString, int *error, int allowDeclaration, struct token *firstToken, char *ruleName) { struct token theToken; struct lhsParseNode *theNode; /*=========================================================*/ /* Check to see if the first token has already been read. */ /* This should only occur for the first pattern in a rule. */ /*=========================================================*/ if (firstToken == NULL) GetToken(theEnv,readSource,&theToken); else CopyToken(&theToken,firstToken); /*=====================================================*/ /* A left parenthesis begins all CEs and declarations. */ /*=====================================================*/ if (theToken.type == LPAREN) { /*================================================*/ /* The first field of a pattern must be a symbol. */ /*================================================*/ GetToken(theEnv,readSource,&theToken); if (theToken.type != SYMBOL) { SyntaxErrorMessage(theEnv,"the first field of a pattern"); *error = TRUE; return(NULL); } /*====================================*/ /* If this is the first CE of a rule, */ /* then a declare statement is valid. */ /*====================================*/ if (allowDeclaration && (strcmp(ValueToString(theToken.value),"declare") == 0)) { if (ruleName == NULL) SystemError(theEnv,"RULELHS",1); DeclarationParse(theEnv,readSource,ruleName,error); theNode = NULL; } /*==================================*/ /* Otherwise check for a *test* CE. */ /*==================================*/ else if (strcmp(ValueToString(theToken.value),"test") == 0) { theNode = TestPattern(theEnv,readSource,error); } /*============================================*/ /* Otherwise check for an *and*, *or*, *not*, */ /* *logical*, *exists*, or *forall* CE. */ /*============================================*/ else if ((strcmp(ValueToString(theToken.value),"and") == 0) || (strcmp(ValueToString(theToken.value),"logical") == 0) || (strcmp(ValueToString(theToken.value),"not") == 0) || (strcmp(ValueToString(theToken.value),"exists") == 0) || (strcmp(ValueToString(theToken.value),"forall") == 0) || (strcmp(ValueToString(theToken.value),"or") == 0)) { theNode = ConnectedPatternParse(theEnv,readSource,&theToken,error); } /*=================================*/ /* Otherwise parse a *pattern* CE. */ /*=================================*/ else { theNode = SimplePatternParse(theEnv,readSource,&theToken,error); } } /*=======================================*/ /* Check for a pattern address variable. */ /*=======================================*/ else if (theToken.type == SF_VARIABLE) { theNode = AssignmentParse(theEnv,readSource,(SYMBOL_HN *) theToken.value,error); } /*=================================================*/ /* Check for the group terminator (either a "=>" */ /* separating the LHS from the RHS or a ")" ending */ /* a CE containing other CEs such as an *and* CE). */ /*=================================================*/ else if ((theToken.type == terminator) ? (strcmp(theToken.printForm,terminatorString) == 0) : FALSE) { return(NULL); } /*====================================*/ /* Otherwise invalid syntax was used. */ /*====================================*/ else { SyntaxErrorMessage(theEnv,"defrule"); *error = TRUE; return(NULL); } /*================================*/ /* If an error occurred, free any */ /* allocated data structures. */ /*================================*/ if (*error == TRUE) { ReturnLHSParseNodes(theEnv,theNode); return(NULL); } /*=========================*/ /* Return the LHS pattern. */ /*=========================*/ return(theNode); }
static struct patternNodeHeader *PlaceFactPattern( void *theEnv, struct lhsParseNode *thePattern) { struct lhsParseNode *tempPattern = NULL; struct factPatternNode *currentLevel, *lastLevel; struct factPatternNode *nodeBeforeMatch, *newNode = NULL; unsigned endSlot; int count; char *deftemplateName; /*======================================================================*/ /* Get the name of the deftemplate associated with the pattern being */ /* added (recall that the first field of any pattern must be a symbol). */ /*======================================================================*/ deftemplateName = ValueToString(thePattern->right->bottom->value); /*=====================================================*/ /* Remove any slot tests that test only for existance. */ /*=====================================================*/ thePattern->right = RemoveUnneededSlots(theEnv,thePattern->right); /*========================================================*/ /* If the constant test for the relation name is the only */ /* pattern network test and there are no other network */ /* tests, then remove the test, but keep the node since */ /* there must be a link from the fact pattern network to */ /* the join network. Otherwise, remove the test for the */ /* relation name since this test has already been done */ /* before entering the pattern network (since each */ /* deftemplate has its own pattern network). */ /*========================================================*/ if (thePattern->right->right == NULL) { ReturnExpression(theEnv,thePattern->right->networkTest); thePattern->right->networkTest = NULL; } else { tempPattern = thePattern->right; thePattern->right = thePattern->right->right; tempPattern->right = NULL; ReturnLHSParseNodes(theEnv,tempPattern); tempPattern = NULL; } /*============================================================*/ /* Get a pointer to the deftemplate data structure associated */ /* with the pattern (use the deftemplate name extracted from */ /* the first field of the pattern). */ /*============================================================*/ FactData(theEnv)->CurrentDeftemplate = (struct deftemplate *) FindImportedConstruct(theEnv,"deftemplate",NULL, deftemplateName,&count, TRUE,NULL); /*================================================*/ /* Initialize some pointers to indicate where the */ /* pattern is being added to the pattern network. */ /*================================================*/ currentLevel = FactData(theEnv)->CurrentDeftemplate->patternNetwork; lastLevel = NULL; thePattern = thePattern->right; /*===========================================*/ /* Loop until all fields in the pattern have */ /* been added to the pattern network. */ /*===========================================*/ while (thePattern != NULL) { /*===========================================================*/ /* If a multifield slot is being processed, then process the */ /* pattern nodes attached to the multifield pattern node. */ /*===========================================================*/ if (thePattern->multifieldSlot) { tempPattern = thePattern; thePattern = thePattern->bottom; } /*============================================*/ /* Determine if the last pattern field within */ /* a multifield slot is being processed. */ /*============================================*/ if ((thePattern->right == NULL) && (tempPattern != NULL)) { endSlot = TRUE; } else { endSlot = FALSE; } /*========================================*/ /* Is there a node in the pattern network */ /* that can be reused (shared)? */ /*========================================*/ newNode = FindPatternNode(currentLevel,thePattern,&nodeBeforeMatch,endSlot); /*================================================*/ /* If the pattern node cannot be shared, then add */ /* a new pattern node to the pattern network. */ /*================================================*/ if (newNode == NULL) { newNode = CreateNewPatternNode(theEnv,thePattern,nodeBeforeMatch,lastLevel,endSlot); } /*===========================================================*/ /* Move on to the next field in the new pattern to be added. */ /*===========================================================*/ if ((thePattern->right == NULL) && (tempPattern != NULL)) { thePattern = tempPattern; tempPattern = NULL; } thePattern = thePattern->right; /*==========================================================*/ /* If there are no more pattern nodes to be added to the */ /* pattern network, then mark the last pattern node added */ /* as a stop node (i.e. if you get to this node and the */ /* network test succeeds, then a pattern has been matched). */ /*==========================================================*/ if (thePattern == NULL) newNode->header.stopNode = TRUE; /*================================================*/ /* Update the pointers which indicate where we're */ /* trying to add the new pattern to the currently */ /* existing pattern network. */ /*================================================*/ lastLevel = newNode; currentLevel = newNode->nextLevel; } /*==================================================*/ /* Return the leaf node of the newly added pattern. */ /*==================================================*/ return((struct patternNodeHeader *) newNode); }
static struct lhsParseNode *ConnectedPatternParse( void *theEnv, char *readSource, struct token *theToken, int *error) { unsigned short connectorValue = 0; struct lhsParseNode *theNode, *tempNode, *theGroup; char *errorCE = NULL; int logical = FALSE; int tempValue; /*==========================================================*/ /* Use appropriate spacing for pretty printing of the rule. */ /*==========================================================*/ IncrementIndentDepth(theEnv,5); if (strcmp(ValueToString(theToken->value),"or") == 0) { connectorValue = OR_CE; errorCE = "the or conditional element"; SavePPBuffer(theEnv," "); } else if (strcmp(ValueToString(theToken->value),"and") == 0) { connectorValue = AND_CE; errorCE = "the and conditional element"; SavePPBuffer(theEnv," "); } else if (strcmp(ValueToString(theToken->value),"not") == 0) { connectorValue = NOT_CE; errorCE = "the not conditional element"; SavePPBuffer(theEnv," "); } else if (strcmp(ValueToString(theToken->value),"exists") == 0) { connectorValue = EXISTS_CE; errorCE = "the exists conditional element"; PPCRAndIndent(theEnv); } else if (strcmp(ValueToString(theToken->value),"forall") == 0) { connectorValue = FORALL_CE; errorCE = "the forall conditional element"; PPCRAndIndent(theEnv); } else if (strcmp(ValueToString(theToken->value),"logical") == 0) { connectorValue = AND_CE; errorCE = "the logical conditional element"; logical = TRUE; PPCRAndIndent(theEnv); } /*=====================================================*/ /* The logical CE cannot be contained within a not CE. */ /*=====================================================*/ if (PatternData(theEnv)->WithinNotCE && logical) { PrintErrorID(theEnv,"RULELHS",1,TRUE); EnvPrintRouter(theEnv,WERROR,"The logical CE cannot be used within a not/exists/forall CE.\n"); *error = TRUE; return(NULL); } /*=====================================================*/ /* Remember if we're currently within a *not* CE and */ /* then check to see if we're entering a new *not* CE. */ /*=====================================================*/ tempValue = PatternData(theEnv)->WithinNotCE; if ((connectorValue == NOT_CE) || (connectorValue == EXISTS_CE) || (connectorValue == FORALL_CE)) { PatternData(theEnv)->WithinNotCE = TRUE; } /*===========================================*/ /* Parse all of the CEs contained with the */ /* CE. A ) will terminate the end of the CE. */ /*===========================================*/ theGroup = GroupPatterns(theEnv,readSource,RPAREN,")",error); /*====================================*/ /* Restore the "with a *not* CE" flag */ /* and reset the indentation depth. */ /*====================================*/ PatternData(theEnv)->WithinNotCE = tempValue; DecrementIndentDepth(theEnv,5); /*============================================*/ /* If an error occured while parsing, return. */ /*============================================*/ if (*error == TRUE) { ReturnLHSParseNodes(theEnv,theGroup); return(NULL); } /*=========================================================*/ /* If we parsed a *logical* CE, then mark the logical flag */ /* for all of the CEs contained within the logical CE. */ /*=========================================================*/ if (logical) TagLHSLogicalNodes(theGroup); /*=====================================================*/ /* All the connected CEs must contain at least one CE. */ /*=====================================================*/ if (theGroup == NULL) { SyntaxErrorMessage(theEnv,errorCE); *error = TRUE; return(NULL); } /*============================================*/ /* A not CE may not contain more than one CE. */ /*============================================*/ if ((connectorValue == NOT_CE) && (theGroup->bottom != NULL)) { SyntaxErrorMessage(theEnv,errorCE); ReturnLHSParseNodes(theEnv,theGroup); *error = TRUE; return(NULL); } /*============================================*/ /* A forall CE must contain at least two CEs. */ /*============================================*/ if ((connectorValue == FORALL_CE) && (theGroup->bottom == NULL)) { SyntaxErrorMessage(theEnv,errorCE); ReturnLHSParseNodes(theEnv,theGroup); *error = TRUE; return(NULL); } /*========================================================*/ /* Remove an "and" and "or" CE that only contains one CE. */ /*========================================================*/ if (((connectorValue == AND_CE) || (connectorValue == OR_CE)) && (theGroup->bottom == NULL)) { theGroup->logical = logical; return(theGroup); } /*===========================================================*/ /* Create the top most node which connects the CEs together. */ /*===========================================================*/ theNode = GetLHSParseNode(theEnv); theNode->logical = logical; /*======================================================*/ /* Attach and/or/not CEs directly to the top most node. */ /*======================================================*/ if ((connectorValue == AND_CE) || (connectorValue == OR_CE) || (connectorValue == NOT_CE)) { theNode->type = connectorValue; theNode->right = theGroup; } /*=================================================================*/ /* Wrap two not CEs around the patterns contained in an exists CE. */ /*=================================================================*/ else if (connectorValue == EXISTS_CE) { theNode->type = NOT_CE; theNode->right = GetLHSParseNode(theEnv); theNode->right->type = NOT_CE; theNode->right->logical = logical; if (theGroup->bottom != NULL) { theNode->right->right = GetLHSParseNode(theEnv); theNode->right->right->type = AND_CE; theNode->right->right->logical = logical; theNode->right->right->right = theGroup; } else { theNode->right->right = theGroup; } } /*==================================================*/ /* For a forall CE, wrap a not CE around all of the */ /* CEs and a not CE around the 2nd through nth CEs. */ /*==================================================*/ else if (connectorValue == FORALL_CE) { theNode->type = NOT_CE; tempNode = theGroup->bottom; theGroup->bottom = NULL; theNode->right = GetLHSParseNode(theEnv); theNode->right->type = AND_CE; theNode->right->logical = logical; theNode->right->right = theGroup; theGroup = tempNode; theNode->right->right->bottom = GetLHSParseNode(theEnv); theNode->right->right->bottom->type = NOT_CE; theNode->right->right->bottom->logical = logical; tempNode = theNode->right->right->bottom; if (theGroup->bottom == NULL) { tempNode->right = theGroup; } else { tempNode->right = GetLHSParseNode(theEnv); tempNode->right->type = AND_CE; tempNode->right->logical = logical; tempNode->right->right = theGroup; } } /*================*/ /* Return the CE. */ /*================*/ return(theNode); }
globle struct lhsParseNode *SequenceRestrictionParse( void *theEnv, char *readSource, struct token *theToken) { struct lhsParseNode *topNode; struct lhsParseNode *nextField; /*================================================*/ /* Create the pattern node for the relation name. */ /*================================================*/ topNode = GetLHSParseNode(theEnv); topNode->type = SF_WILDCARD; topNode->negated = FALSE; topNode->exists = FALSE; topNode->index = -1; topNode->slotNumber = 1; topNode->bottom = GetLHSParseNode(theEnv); topNode->bottom->type = SYMBOL; topNode->bottom->negated = FALSE; topNode->bottom->exists = FALSE; topNode->bottom->value = (void *) theToken->value; /*======================================================*/ /* Connective constraints cannot be used in conjunction */ /* with the first field of a pattern. */ /*======================================================*/ SavePPBuffer(theEnv," "); GetToken(theEnv,readSource,theToken); if ((theToken->type == OR_CONSTRAINT) || (theToken->type == AND_CONSTRAINT)) { ReturnLHSParseNodes(theEnv,topNode); SyntaxErrorMessage(theEnv,"the first field of a pattern"); return(NULL); } /*============================================================*/ /* Treat the remaining constraints of an ordered fact pattern */ /* as if they were contained in a multifield slot. */ /*============================================================*/ nextField = RestrictionParse(theEnv,readSource,theToken,TRUE,NULL,1,NULL,1); if (nextField == NULL) { ReturnLHSParseNodes(theEnv,topNode); return(NULL); } topNode->right = nextField; /*================================================*/ /* The pattern must end with a right parenthesis. */ /*================================================*/ if (theToken->type != RPAREN) { PPBackup(theEnv); SavePPBuffer(theEnv," "); SavePPBuffer(theEnv,theToken->printForm); SyntaxErrorMessage(theEnv,"fact patterns"); ReturnLHSParseNodes(theEnv,topNode); return(NULL); } /*====================================*/ /* Fix the pretty print output if the */ /* slot contained no restrictions. */ /*====================================*/ if (nextField->bottom == NULL) { PPBackup(theEnv); PPBackup(theEnv); SavePPBuffer(theEnv,")"); } /*===================================*/ /* If no errors, return the pattern. */ /*===================================*/ return(topNode); }
static struct lhsParseNode *GroupPatterns( void *theEnv, char *readSource, int terminator, char *terminatorString, int *error) { struct lhsParseNode *lastNode, *newNode, *theNode; lastNode = theNode = NULL; while (TRUE) { /*==================*/ /* Get the next CE. */ /*==================*/ newNode = LHSPattern(theEnv,readSource,terminator,terminatorString, error,FALSE,NULL,NULL); /*=======================================================*/ /* If an error occurred, release any LHS data structures */ /* previously allocated by this routine. */ /*=======================================================*/ if (*error) { ReturnLHSParseNodes(theEnv,theNode); return(NULL); } /*===============================================*/ /* A NULL value for the CE just parsed indicates */ /* that the terminator for the group of patterns */ /* was encountered (either a "=>" or a ")". */ /*===============================================*/ if (newNode == NULL) { PPBackup(theEnv); PPBackup(theEnv); if (terminator == RPAREN) { SavePPBuffer(theEnv,terminatorString); } else { PPCRAndIndent(theEnv); SavePPBuffer(theEnv,terminatorString); } return(theNode); } /*============================*/ /* Add the new CE to the list */ /* of CEs being grouped. */ /*============================*/ if (lastNode == NULL) { theNode = newNode; } else { lastNode->bottom = newNode; } lastNode = newNode; /*======================================*/ /* Fix the pretty print representation. */ /*======================================*/ PPCRAndIndent(theEnv); } }
static struct lhsParseNode *ConjuctiveRestrictionParse( 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(readSource,theToken,error); if (*error == TRUE) { return(NULL); } GetToken(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(); 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(readSource,theToken); theNode = LiteralRestrictionParse(readSource,theToken,error); if (*error == TRUE) { ReturnLHSParseNodes(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("RULEPSR",1); ExitRouter(EXIT_FAILURE); } /*==================================================*/ /* Determine if any more restrictions are connected */ /* to the current list of restrictions. */ /*==================================================*/ GetToken(readSource,theToken); } /*==========================================*/ /* Check for illegal mixing of single and */ /* multifield values within the constraint. */ /*==========================================*/ if (CheckForVariableMixing(bindNode)) { *error = TRUE; ReturnLHSParseNodes(bindNode); return(NULL); } /*========================*/ /* Return the constraint. */ /*========================*/ return(bindNode); }
static struct lhsParseNode *GetLHSSlots( void *theEnv, char *readSource, struct token *tempToken, struct deftemplate *theDeftemplate, int *error) { struct lhsParseNode *firstSlot = NULL, *nextSlot, *lastSlot = NULL; struct templateSlot *slotPtr; short position; /*=======================================================*/ /* Continue parsing slot definitions until the pattern's */ /* closing right parenthesis is encountered. */ /*=======================================================*/ while (tempToken->type != RPAREN) { PPBackup(theEnv); SavePPBuffer(theEnv,(char*)" "); SavePPBuffer(theEnv,tempToken->printForm); /*=================================================*/ /* Slot definitions begin with a left parenthesis. */ /*=================================================*/ if (tempToken->type != LPAREN) { *error = TRUE; SyntaxErrorMessage(theEnv,(char*)"deftemplate patterns"); ReturnLHSParseNodes(theEnv,firstSlot); return(NULL); } /*====================*/ /* Get the slot name. */ /*====================*/ GetToken(theEnv,readSource,tempToken); if (tempToken->type != SYMBOL) { *error = TRUE; SyntaxErrorMessage(theEnv,(char*)"deftemplate patterns"); ReturnLHSParseNodes(theEnv,firstSlot); return(NULL); } /*==========================================================*/ /* Determine if the slot name is valid for the deftemplate. */ /*==========================================================*/ if ((slotPtr = FindSlot(theDeftemplate,(SYMBOL_HN *) tempToken->value,&position)) == NULL) { *error = TRUE; InvalidDeftemplateSlotMessage(theEnv,ValueToString(tempToken->value), ValueToString(theDeftemplate->header.name),TRUE); ReturnLHSParseNodes(theEnv,firstSlot); return(NULL); } /*============================================*/ /* Determine if the slot is multiply defined. */ /*============================================*/ if (MultiplyDefinedLHSSlots(theEnv,firstSlot,(SYMBOL_HN *) tempToken->value) == TRUE) { *error = TRUE; ReturnLHSParseNodes(theEnv,firstSlot); return(NULL); } /*==============================================================*/ /* Get the pattern matching values used in the slot definition. */ /*==============================================================*/ nextSlot = GetSingleLHSSlot(theEnv,readSource,tempToken,slotPtr,error,(short) (position+1)); if (*error) { ReturnLHSParseNodes(theEnv,firstSlot); ReturnLHSParseNodes(theEnv,nextSlot); return(NULL); } /*=====================================*/ /* Add the slot definition to the list */ /* of slot definitions already parsed. */ /*=====================================*/ if (lastSlot == NULL) { firstSlot = nextSlot; } else { lastSlot->right = nextSlot; } while (nextSlot->right != NULL) nextSlot = nextSlot->right; lastSlot = nextSlot; /*==============================*/ /* Begin parsing the next slot. */ /*==============================*/ GetToken(theEnv,readSource,tempToken); } /*===========================================================*/ /* Return all the slot definitions found in the lhs pattern. */ /*===========================================================*/ return(firstSlot); }
static void AttachTestCEsToPatternCEs( void *theEnv, struct lhsParseNode *theLHS) { struct lhsParseNode *lastNode, *tempNode; if (theLHS == NULL) return; /*=============================================================*/ /* Attach test CEs that can be attached directly to a pattern. */ /*=============================================================*/ lastNode = theLHS; theLHS = lastNode->bottom; while (theLHS != NULL) { if ((theLHS->type != TEST_CE) || (lastNode->beginNandDepth != lastNode->endNandDepth) || (lastNode->beginNandDepth != theLHS->beginNandDepth)) { lastNode = theLHS; theLHS = theLHS->bottom; continue; } if (lastNode->negated) { lastNode->secondaryNetworkTest = CombineExpressions(theEnv,lastNode->secondaryNetworkTest,theLHS->networkTest); } else { lastNode->networkTest = CombineExpressions(theEnv,lastNode->networkTest,theLHS->networkTest); } /*==============================================================*/ /* If an exists with multiple conditions has just a pattern and */ /* a test, it should be treated as a single pattern and use the */ /* simpler exists logic rather than the logic used for multiple */ /* patterns with an exists CE. */ /*==============================================================*/ if (lastNode->existsNand) { lastNode->existsNand = FALSE; lastNode->exists = TRUE; lastNode->negated = TRUE; lastNode->beginNandDepth = theLHS->endNandDepth; } theLHS->networkTest = NULL; tempNode = theLHS->bottom; theLHS->bottom = NULL; lastNode->bottom = tempNode; lastNode->endNandDepth = theLHS->endNandDepth; ReturnLHSParseNodes(theEnv,theLHS); theLHS = tempNode; } }
static int TestCEAnalysis( void *theEnv, struct lhsParseNode *patternPtr, struct lhsParseNode *theExpression, int secondary, int *errorFlag, struct nandFrame *theNandFrames) { struct lhsParseNode *rv, *theList, *tempList, *tempRight; if (theExpression == NULL) return FALSE; /*=====================================================*/ /* Verify that all variables were referenced properly. */ /*=====================================================*/ rv = CheckExpression(theEnv,theExpression,NULL,(int) patternPtr->whichCE,NULL,0); /*====================================================================*/ /* Temporarily disconnect the right nodes. If this is a pattern node */ /* with an attached test CE, we only want to propagate to following */ /* patterns, not to nodes of this pattern which preceded the test CE. */ /*====================================================================*/ tempRight = patternPtr->right; patternPtr->right = NULL; /*=========================================================*/ /* 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,theExpression); for (tempList = theList; tempList != NULL; tempList = tempList->right) { if (PropagateVariableDriver(theEnv,patternPtr,patternPtr,NULL,SF_VARIABLE, (SYMBOL_HN *) tempList->value,tempList,FALSE,TEST_CE)) { ReturnLHSParseNodes(theEnv,theList); patternPtr->right = tempRight; return(TRUE); } } ReturnLHSParseNodes(theEnv,theList); /*============================*/ /* Reconnect the right nodes. */ /*============================*/ patternPtr->right = tempRight; /*========================================================*/ /* 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 if (secondary) { patternPtr->secondaryNetworkTest = CombineExpressions(theEnv,patternPtr->secondaryNetworkTest,GetvarReplace(theEnv,theExpression,FALSE,theNandFrames)); } else { patternPtr->networkTest = CombineExpressions(theEnv,patternPtr->networkTest,GetvarReplace(theEnv,theExpression,FALSE,theNandFrames)); } return FALSE; }