예제 #1
0
/**********************************************
  Build functions used by AddPatternParser() to
  provide object access to the pattern network
 **********************************************/
globle EXPRESSION *GenObjectPNConstantCompare(
  void *theEnv,
  struct lhsParseNode *theNode)
  {
   struct ObjectCmpPNConstant hack;
   EXPRESSION *theExp;
   unsigned short tmpType;

   /* ===============================================================
      If the value of a single field slot (or relation name) is being
      compared against a constant, then use specialized routines for
      doing the comparison.

      If a constant comparison is being done within a multifield slot
      and the constant's position has no multifields to the left or
      no multifields to the right, then use the same routine used for
      the single field slot case, but include the offset from either
      the beginning or end of the slot.

      Otherwise, use a general eq/neq test.
      =============================================================== */
   ClearBitString((void *) &hack,(int) sizeof(struct ObjectCmpPNConstant));
   if (theNode->negated)
     hack.fail = 1;
   else
     hack.pass = 1;
   if (((theNode->withinMultifieldSlot == FALSE) ||
        (theNode->multiFieldsAfter == 0) ||
        (theNode->multiFieldsBefore == 0)) &&
       (theNode->slotNumber != ISA_ID) && (theNode->slotNumber != NAME_ID))
     {
      if (theNode->withinMultifieldSlot == FALSE)
        hack.fromBeginning = TRUE;
      else if (theNode->multiFieldsBefore == 0)
        {
         hack.fromBeginning = TRUE;
         hack.offset = theNode->singleFieldsBefore;
        }
      else
        hack.offset = theNode->singleFieldsAfter;
      theExp = GenConstant(theEnv,OBJ_PN_CONSTANT,AddBitMap(theEnv,(void *) &hack,
                                        (int) sizeof(struct ObjectCmpPNConstant)));
      theExp->argList = GenConstant(theEnv,theNode->type,theNode->value);
     }
   else
     {
      hack.general = 1;
      theExp = GenConstant(theEnv,OBJ_PN_CONSTANT,AddBitMap(theEnv,(void *) &hack,
                                        (int) sizeof(struct ObjectCmpPNConstant)));
      theExp->argList = GenConstant(theEnv,0,NULL);
      tmpType = theNode->type;
      theNode->type = SF_VARIABLE;
      GenObjectGetVar(theEnv,FALSE,theExp->argList,theNode);
      theNode->type = tmpType;
      theExp->argList->nextArg = GenConstant(theEnv,theNode->type,theNode->value);
     }
   return(theExp);
  }
예제 #2
0
static void *FactGetVarJN2(
  struct lhsParseNode *theNode)
  {
   struct factGetVarJN2Call hack;

   /*===================================================*/
   /* Clear the bitmap for storing the argument values. */
   /*===================================================*/

   ClearBitString(&hack,sizeof(struct factGetVarJN2Call));

   /*=====================================================*/
   /* Store the position in the partial match from which  */
   /* the fact will be retrieved and the slot in the fact */
   /* from which the value will be retrieved.             */
   /*=====================================================*/

   hack.whichSlot = theNode->slotNumber - 1;
   hack.whichPattern = theNode->pattern - 1;

   /*=============================*/
   /* Return the argument bitmap. */
   /*=============================*/

   return(AddBitMap(&hack,sizeof(struct factGetVarJN2Call)));
  }
예제 #3
0
/****************************************************
  NAME         : GenObjectLengthTest
  DESCRIPTION  : Generates a test on the cardinality
                 of a slot matching an object pattern
  INPUTS       : The first lhsParseNode for a slot
                 in an object pattern
  RETURNS      : Nothing useful
  SIDE EFFECTS : The lhsParseNode network test is
                 modified to include the length test
  NOTES        : None
 ****************************************************/
globle void GenObjectLengthTest(
  struct lhsParseNode *theNode)
  {
   struct ObjectMatchLength hack;
   EXPRESSION *theTest;

   if ((theNode->singleFieldsAfter == 0) &&
       (theNode->type != SF_VARIABLE) &&
       (theNode->type != SF_WILDCARD))
     return;

   ClearBitString((void *) &hack,(int) sizeof(struct ObjectMatchLength));

   if ((theNode->type != MF_VARIABLE) &&
       (theNode->type != MF_WILDCARD) &&
       (theNode->multiFieldsAfter == 0))
     hack.exactly = 1;
   else
     hack.exactly = 0;

   if ((theNode->type == SF_VARIABLE) || (theNode->type == SF_WILDCARD))
     hack.minLength = 1 + theNode->singleFieldsAfter;
   else
     hack.minLength = theNode->singleFieldsAfter;

   theTest = GenConstant(OBJ_SLOT_LENGTH,AddBitMap((void *) &hack,
                                         (int) sizeof(struct ObjectMatchLength)));
   theNode->networkTest = CombineExpressions(theTest,theNode->networkTest);
  }
예제 #4
0
static void *FactGetVarPN1(
  struct lhsParseNode *theNode)
  {
   struct factGetVarPN1Call hack;

   /*===================================================*/
   /* Clear the bitmap for storing the argument values. */
   /*===================================================*/

   ClearBitString(&hack,sizeof(struct factGetVarPN1Call));

   /*========================================*/
   /* A slot value of zero indicates that we */
   /* want the pattern address returned.     */
   /*========================================*/

   if (theNode->slotNumber <= 0)
     {
      hack.factAddress = 1;
      hack.allFields = 0;
      hack.whichSlot = 0;
      hack.whichField = 0;
     }

   /*=====================================================*/
   /* A slot value greater than zero and a field value of */
   /* zero indicate that we want the entire contents of   */
   /* the slot whether it is a single field or multifield */
   /* slot.                                               */
   /*=====================================================*/

   else if (theNode->index <= 0)
     {
      hack.factAddress = 0;
      hack.allFields = 1;
      hack.whichSlot = theNode->slotNumber - 1;
      hack.whichField = 0;
     }

   /*=============================================*/
   /* A slot value, m, and a field value, n, both */
   /* greater than zero indicate that we want the */
   /* nth field of the mth slot.                  */
   /*=============================================*/

   else
     {
      hack.factAddress = 0;
      hack.allFields = 0;
      hack.whichSlot = theNode->slotNumber - 1;
      hack.whichField = theNode->index - 1;
     }

   /*=============================*/
   /* Return the argument bitmap. */
   /*=============================*/

   return(AddBitMap(&hack,sizeof(struct factGetVarPN1Call)));
  }
예제 #5
0
globle struct expr *FactPNVariableComparison(
  struct lhsParseNode *selfNode,
  struct lhsParseNode *referringNode)
  {
   struct expr *top;
   struct factCompVarsPN1Call hack;

   /*===================================================*/
   /* Clear the bitmap for storing the argument values. */
   /*===================================================*/

   ClearBitString(&hack,sizeof(struct factCompVarsPN1Call));

   /*================================================================*/
   /* If two single field slots of a deftemplate are being compared, */
   /* then use the following specified variable comparison routine.  */
   /*================================================================*/

   if ((selfNode->withinMultifieldSlot == FALSE) &&
       (selfNode->slotNumber > 0) &&
       (referringNode->withinMultifieldSlot == FALSE) &&
       (referringNode->slotNumber > 0))
     {
      hack.pass = 0;
      hack.fail = 0;
      hack.field1 = (unsigned int) selfNode->slotNumber - 1;
      hack.field2 = (unsigned int) referringNode->slotNumber - 1;

      if (selfNode->negated) hack.fail = 1;
      else hack.pass = 1;

      top = GenConstant(FACT_PN_CMP1,AddBitMap(&hack,sizeof(struct factCompVarsPN1Call)));
     }

   /*================================================================*/
   /* Otherwise, use the eq function to compare the values retrieved */
   /* by the appropriate get variable value functions.               */
   /*================================================================*/

   else
     {
      if (selfNode->negated) top = GenConstant(FCALL,PTR_NEQ);
      else top = GenConstant(FCALL,PTR_EQ);

      top->argList = FactGenGetfield(selfNode);
      top->argList->nextArg = FactGenGetfield(referringNode);
     }

   /*======================================*/
   /* Return the expression for performing */
   /* the variable comparison.             */
   /*======================================*/

   return(top);
  }
예제 #6
0
globle struct expr *FactGenCheckZeroLength(
  int theSlot)
  {
   struct factCheckLengthPNCall hack;

   ClearBitString(&hack,sizeof(struct factCheckLengthPNCall));

   hack.whichSlot = theSlot-1;
   hack.exactly = 1;
   hack.minLength = 0;

   return(GenConstant(FACT_SLOT_LENGTH,AddBitMap(&hack,sizeof(struct factCheckLengthPNCall))));
  }
예제 #7
0
/****************************************************
  NAME         : GenObjectZeroLengthTest
  DESCRIPTION  : Generates a test on the cardinality
                 of a slot matching an object pattern
  INPUTS       : The first lhsParseNode for a slot
                 in an object pattern
  RETURNS      : Nothing useful
  SIDE EFFECTS : The lhsParseNode network test is
                 modified to include the length test
  NOTES        : None
 ****************************************************/
globle void GenObjectZeroLengthTest(
  struct lhsParseNode *theNode)
  {
   struct ObjectMatchLength hack;
   EXPRESSION *theTest;

   ClearBitString((void *) &hack,(int) sizeof(struct ObjectMatchLength));
   hack.exactly = 1;
   hack.minLength = 0;
   theTest = GenConstant(OBJ_SLOT_LENGTH,AddBitMap((void *) &hack,
                                         (int) sizeof(struct ObjectMatchLength)));
   theNode->networkTest = CombineExpressions(theTest,theNode->networkTest);
  }
예제 #8
0
globle struct expr *FactGenCheckLength(
  struct lhsParseNode *theNode)
  {
   struct factCheckLengthPNCall hack;

   /*===================================================*/
   /* If the slot contains no single field constraints, */
   /* then a length test is not necessary.              */
   /*===================================================*/

   if ((theNode->singleFieldsAfter == 0) &&
       (theNode->type != SF_VARIABLE) &&
       (theNode->type != SF_WILDCARD))
     { return(NULL); }

   /*=======================================*/
   /* Initialize the length test arguments. */
   /*=======================================*/

   ClearBitString(&hack,sizeof(struct factCheckLengthPNCall));
   hack.whichSlot = theNode->slotNumber - 1;

   /*============================================*/
   /* If the slot has no multifield constraints, */
   /* then the length must match exactly.        */
   /*============================================*/

   if ((theNode->type != MF_VARIABLE) &&
       (theNode->type != MF_WILDCARD) &&
       (theNode->multiFieldsAfter == 0))
     { hack.exactly = 1; }
   else
     { hack.exactly = 0; }

   /*============================================*/
   /* The minimum length is the number of single */
   /* field constraints contained in the slot.   */
   /*============================================*/

   if ((theNode->type == SF_VARIABLE) || (theNode->type == SF_WILDCARD))
     { hack.minLength = 1 + theNode->singleFieldsAfter; }
   else
     { hack.minLength = theNode->singleFieldsAfter; }

   /*========================================================*/
   /* Generate call to test the length of a multifield slot. */
   /*========================================================*/

   return(GenConstant(FACT_SLOT_LENGTH,AddBitMap(&hack,sizeof(struct factCheckLengthPNCall))));
  }
예제 #9
0
/***************************************************
  NAME         : GenHandlerSlotReference
  DESCRIPTION  : Creates a bitmap of the class id
                 and slot index for the get or put
                 operation. The bitmap and operation
                 type are stored in the given
                 expression.
  INPUTS       : 1) The expression
                 2) The operation type
                 3) The class slot
  RETURNS      : Nothing useful
  SIDE EFFECTS : Bitmap created and expression
                 initialized
  NOTES        : None
 ***************************************************/
static void GenHandlerSlotReference(
  void *theEnv,
  EXPRESSION *theExp,
  unsigned short theType,
  SLOT_DESC *sd)
  {
   HANDLER_SLOT_REFERENCE handlerReference;

   ClearBitString(&handlerReference,sizeof(HANDLER_SLOT_REFERENCE));
   handlerReference.classID = (unsigned short) sd->cls->id;
   handlerReference.slotID = (unsigned) sd->slotName->id;
   theExp->type = theType;
   theExp->value =  AddBitMap(theEnv,(void *) &handlerReference,
                           (int) sizeof(HANDLER_SLOT_REFERENCE));
  }
예제 #10
0
static void *FactGetVarPN2(
  struct lhsParseNode *theNode)
  {
   struct factGetVarPN2Call hack;

   /*===================================================*/
   /* Clear the bitmap for storing the argument values. */
   /*===================================================*/

   ClearBitString(&hack,sizeof(struct factGetVarPN2Call));

   /*=======================================*/
   /* Store the slot in the fact from which */
   /* the value will be retrieved.          */
   /*=======================================*/

   hack.whichSlot = theNode->slotNumber - 1;

   /*=============================*/
   /* Return the argument bitmap. */
   /*=============================*/

   return(AddBitMap(&hack,sizeof(struct factGetVarPN2Call)));
  }
예제 #11
0
static void *FactGetVarPN3(
  struct lhsParseNode *theNode)
  {
   struct factGetVarPN3Call hack;

   /*===================================================*/
   /* Clear the bitmap for storing the argument values. */
   /*===================================================*/

   ClearBitString(&hack,sizeof(struct factGetVarPN3Call));

   /*=======================================*/
   /* Store the slot in the fact from which */
   /* the value will be retrieved.          */
   /*=======================================*/

   hack.whichSlot = theNode->slotNumber - 1;

   /*==============================================================*/
   /* If a single field variable value is being retrieved, then... */
   /*==============================================================*/

   if ((theNode->type == SF_WILDCARD) || (theNode->type == SF_VARIABLE))
     {
      /*=========================================================*/
      /* If no multifield values occur before the variable, then */
      /* the variable's value can be retrieved based on its      */
      /* offset from the beginning of the slot's value           */
      /* regardless of the number of multifield variables or     */
      /* wildcards following the variable being retrieved.       */
      /*=========================================================*/

      if (theNode->multiFieldsBefore == 0)
        {
         hack.fromBeginning = 1;
         hack.fromEnd = 0;
         hack.beginOffset = theNode->singleFieldsBefore;
         hack.endOffset = 0;
        }

      /*===============================================*/
      /* Otherwise the variable is retrieved based its */
      /* position relative to the end of the slot.     */
      /*===============================================*/

      else
        {
         hack.fromBeginning = 0;
         hack.fromEnd = 1;
         hack.beginOffset = 0;
         hack.endOffset = theNode->singleFieldsAfter;
        }

      return(AddBitMap(&hack,sizeof(struct factGetVarPN3Call)));
     }

   /*============================================================*/
   /* A multifield variable value is being retrieved. This means */
   /* that there are no other multifield variables or wildcards  */
   /* in the slot. The multifield value is retrieved by storing  */
   /* the number of single field values which come before and    */
   /* after the multifield value. The multifield value can then  */
   /* be retrieved based on the length of the value in the slot  */
   /* and the number of single field values which must occur     */
   /* before and after the multifield value.                     */
   /*============================================================*/

   hack.fromBeginning = 1;
   hack.fromEnd = 1;
   hack.beginOffset = theNode->singleFieldsBefore;
   hack.endOffset = theNode->singleFieldsAfter;

   /*=============================*/
   /* Return the argument bitmap. */
   /*=============================*/

   return(AddBitMap(&hack,sizeof(struct factGetVarPN3Call)));
  }
예제 #12
0
globle struct expr *FactJNVariableComparison(
  struct lhsParseNode *selfNode,
  struct lhsParseNode *referringNode)
  {
   struct expr *top;
   struct factCompVarsJN1Call hack1;
   struct factCompVarsJN2Call hack2;

   /*================================================================*/
   /* If two single field slots of a deftemplate are being compared, */
   /* then use the following specified variable comparison routine.  */
   /*================================================================*/

   if ((selfNode->withinMultifieldSlot == FALSE) &&
       (selfNode->slotNumber > 0) &&
       (referringNode->withinMultifieldSlot == FALSE) &&
       (referringNode->slotNumber > 0))
     {
      ClearBitString(&hack1,sizeof(struct factCompVarsJN1Call));
      hack1.pass = 0;
      hack1.fail = 0;
      hack1.slot1 = (unsigned int) selfNode->slotNumber - 1;
      hack1.pattern2 = (unsigned int) referringNode->pattern;
      if (referringNode->index < 0) hack1.slot2 = 0;
      else hack1.slot2 = (unsigned int) referringNode->slotNumber - 1;

      if (selfNode->negated) hack1.fail = 1;
      else hack1.pass = 1;

      top = GenConstant(FACT_JN_CMP1,AddBitMap(&hack1,sizeof(struct factCompVarsJN1Call)));
     }

   /*===============================================================*/
   /* If two single field values are compared and either or both of */
   /* them are contained in multifield slots (and the value can be  */
   /* accessed relative to either the beginning or end of the slot  */
   /* with no intervening multifield variables), then use the       */
   /* following specified variable comparison routine.              */
   /*===============================================================*/

   else if ((selfNode->slotNumber > 0) &&
            (selfNode->type == SF_VARIABLE) &&
            ((selfNode->multiFieldsBefore == 0) ||
             ((selfNode->multiFieldsBefore == 1) &&
              (selfNode->multiFieldsAfter == 0))) &&
            (referringNode->slotNumber > 0) &&
            (referringNode->type == SF_VARIABLE) &&
            ((referringNode->multiFieldsBefore == 0) ||
             (referringNode->multiFieldsAfter == 0)))
     {
      ClearBitString(&hack2,sizeof(struct factCompVarsJN2Call));
      hack2.pass = 0;
      hack2.fail = 0;
      hack2.slot1 = (unsigned int) selfNode->slotNumber - 1;
      hack2.pattern2 = (unsigned int) referringNode->pattern;
      hack2.slot2 = (unsigned int) referringNode->slotNumber - 1;

      if (selfNode->multiFieldsBefore == 0)
        {
         hack2.fromBeginning1 = 1;
         hack2.offset1 = selfNode->singleFieldsBefore;
        }
      else
        {
         hack2.fromBeginning1 = 0;
         hack2.offset1 = selfNode->singleFieldsAfter;
        }

      if (referringNode->multiFieldsBefore == 0)
        {
         hack2.fromBeginning2 = 1;
         hack2.offset2 = referringNode->singleFieldsBefore;
        }
      else
        {
         hack2.fromBeginning2 = 0;
         hack2.offset2 = referringNode->singleFieldsAfter;
        }

      if (selfNode->negated) hack2.fail = 1;
      else hack2.pass = 1;

      top = GenConstant(FACT_JN_CMP2,AddBitMap(&hack2,sizeof(struct factCompVarsJN2Call)));
     }

   /*===============================================================*/
   /* Otherwise, use the equality or inequality function to compare */
   /* the values returned by the appropriate join network variable  */
   /* retrieval function call.                                      */
   /*===============================================================*/

   else
     {
      if (selfNode->negated)
        { top = GenConstant(FCALL,PTR_NEQ); }
      else
        { top = GenConstant(FCALL,PTR_EQ); }

      top->argList = FactGenGetvar(selfNode);
      top->argList->nextArg = FactGenGetvar(referringNode);
     }

   /*======================================*/
   /* Return the expression for performing */
   /* the variable comparison.             */
   /*======================================*/

   return(top);
  }
예제 #13
0
/***************************************************************
  NAME         : GenerateSlotComparisonTest
  DESCRIPTION  : Generates pattern and join network
                 expressions for comparing object
                 pattern variables
  INPUTS       : 1) A flag indicating if this is a
                    pattern or join network test
                 2) The intermediate parse node
                    for the first variable
                 3) The intermediate parse node
                    for the second variable
  RETURNS      : An expression for comparing the
                 variables
  SIDE EFFECTS : Expression and bitmaps generated
  NOTES        : The following tests are generated
                 for the following scenarios:

                 SF slot w/ SF slot: PN_1 or JN_1
                 Example: (foo ?x) with (bar ?xy)

                 SF slot w/ SF reference in MF slot: PN_2 or JN_2
                 Example: (foo ?x) (bar ? ?x ? ?)

                 SF reference w/ SF reference: PN_3 or JN_3
                 Example: (foo ? ?x ?) and (bar ? ? ? ?x)

                 All other cases: EQ/NEQ general test
                 Example: (foo $? ?x $?) and (bar ?x)
 ***************************************************************/
static EXPRESSION *GenerateSlotComparisonTest(
  int joinTest,
  struct lhsParseNode *selfNode,
  struct lhsParseNode *referringNode)
  {
   EXPRESSION *exp;
   struct ObjectCmpPNSingleSlotVars1 phack1;
   struct ObjectCmpPNSingleSlotVars2 phack2;
   struct ObjectCmpPNSingleSlotVars3 phack3;
   struct ObjectCmpJoinSingleSlotVars1 jhack1;
   struct ObjectCmpJoinSingleSlotVars2 jhack2;
   struct ObjectCmpJoinSingleSlotVars3 jhack3;

   /* =========================================================
      If we are comparing two single-field slot variables that
      don't require multifield markers for lookup, use
      a quick comparison.  Otherwise, use a general eq/neq with
      the pattern variable access routines
      ========================================================= */
   if (IsSimpleSlotVariable(selfNode) && IsSimpleSlotVariable(referringNode))
     {
      /* ==============================
         Compare two single-field slots
         ============================== */
      if ((selfNode->withinMultifieldSlot == FALSE) &&
          (referringNode->withinMultifieldSlot == FALSE))
        {
         ClearBitString((void *) &phack1,(int) sizeof(struct ObjectCmpPNSingleSlotVars1));
         ClearBitString((void *) &jhack1,(int) sizeof(struct ObjectCmpJoinSingleSlotVars1));
         if (selfNode->negated)
           phack1.fail = jhack1.fail = 1;
         else
           phack1.pass = jhack1.pass = 1;
         phack1.firstSlot = jhack1.firstSlot = (unsigned) selfNode->slotNumber;
         phack1.secondSlot = jhack1.secondSlot = (unsigned) referringNode->slotNumber;
         if (joinTest)
           {
            jhack1.firstPattern = (unsigned) selfNode->pattern;
            jhack1.secondPattern = (unsigned) referringNode->pattern;
            exp = GenConstant(OBJ_JN_CMP1,AddBitMap((void *) &jhack1,
                                           (int) sizeof(struct ObjectCmpJoinSingleSlotVars1)));
           }
         else
           exp = GenConstant(OBJ_PN_CMP1,AddBitMap((void *) &phack1,
                                           (int) sizeof(struct ObjectCmpPNSingleSlotVars1)));
        }
      /* ============================================
         Compare a single-field slot with a
         single-field in a multifield slot (make sure
         the multifield slot reference is first
         ============================================ */
      else if ((selfNode->withinMultifieldSlot == FALSE) ||
               (referringNode->withinMultifieldSlot == FALSE))
        {
         ClearBitString((void *) &phack2,(int) sizeof(struct ObjectCmpPNSingleSlotVars2));
         ClearBitString((void *) &jhack2,(int) sizeof(struct ObjectCmpJoinSingleSlotVars2));
         if (selfNode->negated)
           phack2.fail = jhack2.fail = 1;
         else
           phack2.pass = jhack2.pass = 1;
         if (selfNode->withinMultifieldSlot == TRUE)
           {
            phack2.firstSlot = jhack2.firstSlot = (unsigned) selfNode->slotNumber;
            phack2.secondSlot = jhack2.secondSlot = (unsigned) referringNode->slotNumber;
            if (joinTest)
              {
               jhack2.firstPattern = (unsigned) selfNode->pattern;
               jhack2.secondPattern = (unsigned) referringNode->pattern;
              }
            if (selfNode->multiFieldsBefore == 0)
              {
               phack2.fromBeginning = jhack2.fromBeginning = 1;
               phack2.offset = jhack2.offset = selfNode->singleFieldsBefore;
              }
            else
              phack2.offset = jhack2.offset = selfNode->singleFieldsAfter;
           }
         else
           {
            phack2.firstSlot = jhack2.firstSlot = (unsigned) referringNode->slotNumber;
            phack2.secondSlot = jhack2.secondSlot = (unsigned) selfNode->slotNumber;
            if (joinTest)
              {
               jhack2.firstPattern = (unsigned) referringNode->pattern;
               jhack2.secondPattern = (unsigned) selfNode->pattern;
              }
            if (referringNode->multiFieldsBefore == 0)
              {
               phack2.fromBeginning = jhack2.fromBeginning = 1;
               phack2.offset = jhack2.offset = referringNode->singleFieldsBefore;
              }
            else
              phack2.offset = jhack2.offset = referringNode->singleFieldsAfter;
           }
         if (joinTest)
           exp = GenConstant(OBJ_JN_CMP2,AddBitMap((void *) &jhack2,
                                           (int) sizeof(struct ObjectCmpJoinSingleSlotVars2)));
         else
           exp = GenConstant(OBJ_PN_CMP2,AddBitMap((void *) &phack2,
                                           (int) sizeof(struct ObjectCmpPNSingleSlotVars2)));
        }

      /* ===================================
         Compare two single-field references
         within multifield slots
         =================================== */
      else
        {
         ClearBitString((void *) &phack3,(int) sizeof(struct ObjectCmpPNSingleSlotVars3));
         ClearBitString((void *) &jhack3,(int) sizeof(struct ObjectCmpJoinSingleSlotVars3));
         if (selfNode->negated)
           phack3.fail = jhack3.fail = 1;
         else
           phack3.pass = jhack3.pass = 1;
         phack3.firstSlot = jhack3.firstSlot = (unsigned) selfNode->slotNumber;
         phack3.secondSlot = jhack3.secondSlot = (unsigned) referringNode->slotNumber;
         if (selfNode->multiFieldsBefore == 0)
           {
            phack3.firstFromBeginning = jhack3.firstFromBeginning = 1;
            phack3.firstOffset = jhack3.firstOffset = selfNode->singleFieldsBefore;
           }
         else
           phack3.firstOffset = jhack3.firstOffset = selfNode->singleFieldsAfter;
         if (referringNode->multiFieldsBefore == 0)
           {
            phack3.secondFromBeginning = jhack3.secondFromBeginning = 1;
            phack3.secondOffset = jhack3.secondOffset = referringNode->singleFieldsBefore;
           }
         else
           phack3.secondOffset = jhack3.secondOffset = referringNode->singleFieldsAfter;
         if (joinTest)
           {
            jhack3.firstPattern = (unsigned) selfNode->pattern;
            jhack3.secondPattern = (unsigned) referringNode->pattern;
            exp = GenConstant(OBJ_JN_CMP3,AddBitMap((void *) &jhack3,
                                         (int) sizeof(struct ObjectCmpJoinSingleSlotVars3)));
           }
         else
           exp = GenConstant(OBJ_PN_CMP3,AddBitMap((void *) &phack3,
                                           (int) sizeof(struct ObjectCmpPNSingleSlotVars3)));
        }
     }

   /* ==================================================
      General comparison for multifield slot references,
      references which require multifield markers, and
      object addresses
      ================================================== */
   else
     {
      exp = GenConstant(FCALL,selfNode->negated ? PTR_NEQ : PTR_EQ);
      exp->argList = GenConstant(0,NULL);
      GenObjectGetVar(joinTest,exp->argList,selfNode);
      exp->argList->nextArg = GenConstant(0,NULL);
      GenObjectGetVar(joinTest,exp->argList->nextArg,referringNode);
     }
   return(exp);
  }
예제 #14
0
/***************************************************
  NAME         : GenObjectGetVar
  DESCRIPTION  : Generates the expressions necessary
                 to access object pattern variables
  INPUTS       : 1) An integer code indicating if
                    this is a join network reference
                    or a pattern network reference
                 2) The expression for which to set
                    the type and value
                 3) The lhsParseNode for the
                    variable reference
  RETURNS      : Nothing useful
  SIDE EFFECTS : The value is a packed long holding
                 pattern index, slot number,
                 field index, etc.
  NOTES        : None
 ***************************************************/
static void GenObjectGetVar(
  int joinReference,
  EXPRESSION *theItem,
  struct lhsParseNode *theNode)
  {
   struct ObjectMatchVar1 hack1;
   struct ObjectMatchVar2 hack2;

   ClearBitString((void *) &hack1,(int) sizeof(struct ObjectMatchVar1));
   ClearBitString((void *) &hack2,(int) sizeof(struct ObjectMatchVar2));

   if (joinReference)
     {
      hack1.whichPattern = (unsigned) theNode->pattern;
      hack2.whichPattern = (unsigned) theNode->pattern;
     }

   /* ========================
      Access an object address
      ======================== */
   if (theNode->slotNumber < 0)
     {
      hack1.objectAddress = 1;
      theItem->type = (short) (joinReference ? OBJ_GET_SLOT_JNVAR1 : OBJ_GET_SLOT_PNVAR1);
      theItem->value = AddBitMap((void *) &hack1,(int) sizeof(struct ObjectMatchVar1));
      return;
     }

   /* ======================================
      Access the entire contents of the slot
      ====================================== */
   if ((theNode->singleFieldsBefore == 0) &&
       (theNode->singleFieldsAfter == 0) &&
       (theNode->multiFieldsBefore == 0) &&
       (theNode->multiFieldsAfter == 0) &&
       ((theNode->withinMultifieldSlot == FALSE) ||
        (theNode->type == MF_VARIABLE) ||
        (theNode->type == MF_WILDCARD)))
     {
      hack1.allFields = 1;
      hack1.whichSlot = (unsigned) theNode->slotNumber;
      theItem->type = (short) (joinReference ? OBJ_GET_SLOT_JNVAR1 : OBJ_GET_SLOT_PNVAR1);
      theItem->value = AddBitMap((void *) &hack1,(int) sizeof(struct ObjectMatchVar1));
      return;
     }

   /* =============================================================
      Access a particular field(s) in a multifield slot pattern
      containing at most one multifield variable and at least
      one (or two if no multifield variables) single-field variable
      ============================================================= */
   if (((theNode->type == SF_WILDCARD) || (theNode->type == SF_VARIABLE)) &&
       ((theNode->multiFieldsBefore == 0) || (theNode->multiFieldsAfter == 0)))
     {
      hack2.whichSlot = (unsigned) theNode->slotNumber;
      if (theNode->multiFieldsBefore == 0)
        {
         hack2.fromBeginning = 1;
         hack2.beginningOffset = theNode->singleFieldsBefore;
        }
      else
        {
         hack2.fromEnd = 1;
         hack2.endOffset = theNode->singleFieldsAfter;
        }
      theItem->type = (short) (joinReference ? OBJ_GET_SLOT_JNVAR2 : OBJ_GET_SLOT_PNVAR2);
      theItem->value = AddBitMap((void *) &hack2,sizeof(struct ObjectMatchVar2));
      return;
     }

   if (((theNode->type == MF_WILDCARD) || (theNode->type == MF_VARIABLE)) &&
       (theNode->multiFieldsBefore == 0) &&
       (theNode->multiFieldsAfter == 0))
     {
      hack2.whichSlot = (unsigned) theNode->slotNumber;
      hack2.fromBeginning = 1;
      hack2.fromEnd = 1;
      hack2.beginningOffset = theNode->singleFieldsBefore;
      hack2.endOffset = theNode->singleFieldsAfter;
      theItem->type = (short) (joinReference ? OBJ_GET_SLOT_JNVAR2 : OBJ_GET_SLOT_PNVAR2);
      theItem->value = AddBitMap((void *) &hack2,sizeof(struct ObjectMatchVar2));
      return;
     }

   /* ==================================================
      General slot field access using multifield markers
      ================================================== */
   hack1.whichSlot = (unsigned) theNode->slotNumber;
   hack1.whichField = (unsigned) theNode->index;
   theItem->type = (short) (joinReference ? OBJ_GET_SLOT_JNVAR1 : OBJ_GET_SLOT_PNVAR1);
   theItem->value = AddBitMap((void *) &hack1,sizeof(struct ObjectMatchVar1));
  }
예제 #15
0
static struct expr *GetSlotAssertValues(
  struct templateSlot *slotPtr,
  struct expr *firstSlot,
  int *error)
  {
   struct expr *slotItem;
   struct expr *newArg, *tempArg;
   DATA_OBJECT theDefault;
   char *nullBitMap = "\0";

   /*==================================================*/
   /* Determine if the slot is assigned in the assert. */
   /*==================================================*/

   slotItem = FindAssertSlotItem(slotPtr,firstSlot);

   /*==========================================*/
   /* If the slot is assigned, use that value. */
   /*==========================================*/

   if (slotItem != NULL)
     {
      newArg = slotItem->argList;
      slotItem->argList = NULL;
     }

   /*=================================*/
   /* Otherwise, use a default value. */
   /*=================================*/

   else
     {
      /*================================================*/
      /* If the (default ?NONE) attribute was specified */
      /* for the slot, then a value must be supplied.   */
      /*================================================*/

      if (slotPtr->noDefault)
        {
         PrintErrorID("TMPLTRHS",1,TRUE);
         PrintRouter(WERROR,"Slot ");
         PrintRouter(WERROR,slotPtr->slotName->contents);
         PrintRouter(WERROR," requires a value because of its (default ?NONE) attribute.\n");
         *error = TRUE;
         return(NULL);
        }

      /*===================================================*/
      /* If the (default ?DERIVE) attribute was specified  */
      /* (the default), then derive the default value from */
      /* the slot's constraints.                           */
      /*===================================================*/

      else if ((slotPtr->defaultPresent == FALSE) &&
               (slotPtr->defaultDynamic == FALSE))
        {
         DeriveDefaultFromConstraints(slotPtr->constraints,&theDefault,
                                      (int) slotPtr->multislot);
         newArg = ConvertValueToExpression(&theDefault);
        }

      /*=========================================*/
      /* Otherwise, use the expression contained */
      /* in the default attribute.               */
      /*=========================================*/

      else
        { newArg = CopyExpression(slotPtr->defaultList); }
     }

   /*=======================================================*/
   /* Since a multifield slot default can contain a list of */
   /* values, the values need to have a store-multifield    */
   /* function called wrapped around it to group all of the */
   /* values into a single multifield value.                */
   /*=======================================================*/

   if (slotPtr->multislot)
     {
      tempArg = GenConstant(FACT_STORE_MULTIFIELD,AddBitMap((void *) nullBitMap,1));
      tempArg->argList = newArg;
      newArg = tempArg;
     }

   /*==============================================*/
   /* Return the value to be asserted in the slot. */
   /*==============================================*/

   return(newArg);
  }
예제 #16
0
globle struct expr *FactGenPNConstant(
  struct lhsParseNode *theField)
  {
   struct expr *top;
   int tempValue;
   struct factConstantPN1Call hack1;
   struct factConstantPN2Call hack2;

   /*=================================================================*/
   /* If the value of a single field slot (or relation name) is being */
   /* compared against a constant, then use specialized routines for  */
   /* doing the comparison.                                           */
   /*=================================================================*/

   if (theField->withinMultifieldSlot == FALSE)
     {
      ClearBitString(&hack1,sizeof(struct factConstantPN1Call));

      if (theField->negated) hack1.testForEquality = FALSE;
      else hack1.testForEquality = TRUE;

      hack1.whichSlot = theField->slotNumber - 1;

      top = GenConstant(FACT_PN_CONSTANT1,AddBitMap(&hack1,sizeof(struct factConstantPN1Call)));

      top->argList = GenConstant(theField->type,theField->value);

      return(top);
     }

   /*=================================================================*/
   /* If a constant comparison is being done within a multifield slot */
   /* and the constant's position has no multifields to the left,     */
   /* then use the same routine used for the single field slot case,  */
   /* but include the offset from the beginning of the slot.          */
   /*=================================================================*/

   else if ((theField->multiFieldsBefore == 0) ||
            ((theField->multiFieldsBefore == 1) && (theField->multiFieldsAfter == 0)))
     {
      ClearBitString(&hack2,sizeof(struct factConstantPN2Call));

      if (theField->negated) hack2.testForEquality = FALSE;
      else hack2.testForEquality = TRUE;

      hack2.whichSlot = theField->slotNumber - 1;

      if (theField->multiFieldsBefore == 0)
        {
         hack2.fromBeginning = TRUE;
         hack2.offset = theField->singleFieldsBefore;
        }
      else
        {
         hack2.fromBeginning = FALSE;
         hack2.offset = theField->singleFieldsAfter;
        }

      top = GenConstant(FACT_PN_CONSTANT2,AddBitMap(&hack2,sizeof(struct factConstantPN2Call)));

      top->argList = GenConstant(theField->type,theField->value);

      return(top);
     }

   /*===============================================================*/
   /* Otherwise, use the equality or inequality function to compare */
   /* the constant against the value returned by the appropriate    */
   /* pattern network variable retrieval function call.             */
   /*===============================================================*/

   else
     {
      if (theField->negated)
        { top = GenConstant(FCALL,PTR_NEQ); }
      else
        { top = GenConstant(FCALL,PTR_EQ); }

      tempValue = theField->type;
      theField->type = SF_VARIABLE;
      top->argList = FactGenGetfield(theField);
      theField->type = tempValue;

      top->argList->nextArg = GenConstant(theField->type,theField->value);
     }

   /*===============================================================*/
   /* Return the expression for performing the constant comparison. */
   /*===============================================================*/

   return(top);
  }
예제 #17
0
globle struct expr *GetRHSPattern(
  char *readSource,
  struct token *tempToken,
  int *error,
  int constantsOnly,
  int readFirstParen,
  int checkFirstParen,
  int endType)
  {
   struct expr *lastOne = NULL;
   struct expr *nextOne, *firstOne, *argHead = NULL;
   int printError, count;
   struct deftemplate *theDeftemplate;
   struct symbolHashNode *templateName;

   /*=================================================*/
   /* Get the opening parenthesis of the RHS pattern. */
   /*=================================================*/

   *error = FALSE;

   if (readFirstParen) GetToken(readSource,tempToken);

   if (checkFirstParen)
     {
      if (tempToken->type == endType) return(NULL);

      if (tempToken->type != LPAREN)
        {
         SyntaxErrorMessage("RHS patterns");
         *error = TRUE;
         return(NULL);
        }
     }

   /*======================================================*/
   /* The first field of an asserted fact must be a symbol */
   /* (but not = or : which have special significance).    */
   /*======================================================*/

   GetToken(readSource,tempToken);
   if (tempToken->type != SYMBOL)
     {
      SyntaxErrorMessage("first field of a RHS pattern");
      *error = TRUE;
      return(NULL);
     }
   else if ((strcmp(ValueToString(tempToken->value),"=") == 0) ||
            (strcmp(ValueToString(tempToken->value),":") == 0))
     {
      SyntaxErrorMessage("first field of a RHS pattern");
      *error = TRUE;
      return(NULL);
     }

   /*=========================================================*/
   /* Check to see if the relation name is a reserved symbol. */
   /*=========================================================*/

   templateName = (struct symbolHashNode *) tempToken->value;

   if (ReservedPatternSymbol(ValueToString(templateName),NULL))
     {
      ReservedPatternSymbolErrorMsg(ValueToString(templateName),"a relation name");
      *error = TRUE;
      return(NULL);
     }

   /*============================================================*/
   /* A module separator in the name is illegal in this context. */
   /*============================================================*/

   if (FindModuleSeparator(ValueToString(templateName)))
     {
      IllegalModuleSpecifierMessage();

      *error = TRUE;
      return(NULL);
     }

   /*=============================================================*/
   /* Determine if there is an associated deftemplate. If so, let */
   /* the deftemplate parsing functions parse the RHS pattern and */
   /* then return the fact pattern that was parsed.               */
   /*=============================================================*/

   theDeftemplate = (struct deftemplate *)
                    FindImportedConstruct("deftemplate",NULL,ValueToString(templateName),
                                          &count,TRUE,NULL);

   if (count > 1)
     {
      AmbiguousReferenceErrorMessage("deftemplate",ValueToString(templateName));
      *error = TRUE;
      return(NULL);
     }

   /*======================================================*/
   /* If no deftemplate exists with the specified relation */
   /* name, then create an implied deftemplate.            */
   /*======================================================*/

   if (theDeftemplate == NULL)
#if (! BLOAD_ONLY) && (! RUN_TIME)
     {
#if BLOAD || BLOAD_AND_BSAVE
      if ((Bloaded()) && (! CheckSyntaxMode))
        {
         NoSuchTemplateError(ValueToString(templateName));
         *error = TRUE;
         return(NULL);
        }
#endif
#if DEFMODULE_CONSTRUCT
      if (FindImportExportConflict("deftemplate",((struct defmodule *) GetCurrentModule()),ValueToString(templateName)))
        {
         ImportExportConflictMessage("implied deftemplate",ValueToString(templateName),NULL,NULL);
         *error = TRUE;
         return(NULL);
        }
#endif
      if (! CheckSyntaxMode)
        { theDeftemplate = CreateImpliedDeftemplate((SYMBOL_HN *) templateName,TRUE); }
     }
#else
    {
     NoSuchTemplateError(ValueToString(templateName));
     *error = TRUE;
     return(NULL);
    }
#endif

   /*=========================================*/
   /* If an explicit deftemplate exists, then */
   /* parse the fact as a deftemplate fact.   */
   /*=========================================*/

   if ((theDeftemplate != NULL) && (theDeftemplate->implied == FALSE))
     {
      firstOne = GenConstant(DEFTEMPLATE_PTR,theDeftemplate);
      firstOne->nextArg = ParseAssertTemplate(readSource,tempToken,
                                              error,endType,
                                              constantsOnly,theDeftemplate);
      if (*error)
        {
         ReturnExpression(firstOne);
         firstOne = NULL;
        }

      return(firstOne);
     }

   /*========================================*/
   /* Parse the fact as an ordered RHS fact. */
   /*========================================*/

   firstOne = GenConstant(DEFTEMPLATE_PTR,theDeftemplate);

#if (! RUN_TIME) && (! BLOAD_ONLY)
   SavePPBuffer(" ");
#endif

   while ((nextOne = GetAssertArgument(readSource,tempToken,
                                        error,endType,constantsOnly,&printError)) != NULL)
     {
      if (argHead == NULL) argHead = nextOne;
      else lastOne->nextArg = nextOne;
      lastOne = nextOne;
#if (! RUN_TIME) && (! BLOAD_ONLY)
      SavePPBuffer(" ");
#endif
     }

   /*===========================================================*/
   /* If an error occurred, set the error flag and return NULL. */
   /*===========================================================*/

   if (*error)
     {
      if (printError) SyntaxErrorMessage("RHS patterns");
      ReturnExpression(firstOne);
      ReturnExpression(argHead);
      return(NULL);
     }

   /*=====================================*/
   /* Fix the pretty print representation */
   /* of the RHS ordered fact.            */
   /*=====================================*/

#if (! RUN_TIME) && (! BLOAD_ONLY)
   PPBackup();
   PPBackup();
   SavePPBuffer(tempToken->printForm);
#endif

   /*==========================================================*/
   /* Ordered fact assertions are processed by stuffing all of */
   /* the fact's proposition (except the relation name) into a */
   /* single multifield slot.                                  */
   /*==========================================================*/

   firstOne->nextArg = GenConstant(FACT_STORE_MULTIFIELD,AddBitMap("\0",1));
   firstOne->nextArg->argList = argHead;

   /*==============================*/
   /* Return the RHS ordered fact. */
   /*==============================*/

   return(firstOne);
  }
예제 #18
0
globle struct expr *GetRHSPattern(
  char *readSource,
  struct token *tempToken,
  int *error,
  int constantsOnly,
  int readFirstParen,
  int checkFirstParen,
  int endType)
  {
   struct expr *lastOne = NULL;
   struct expr *nextOne, *firstOne, *argHead = NULL;
   int printError, count;
   struct deftemplate *theDeftemplate;
   struct symbolHashNode *templateName;

   /*=================================================*/
   /* Get the opening parenthesis of the RHS pattern. */
   /*=================================================*/

   *error = FALSE;

   if (readFirstParen) GetToken(readSource,tempToken);

   if (checkFirstParen)
     {
      if (tempToken->type == endType) return(NULL);

      if (tempToken->type != LPAREN)
        {
         SyntaxErrorMessage("RHS patterns");
         *error = TRUE;
         return(NULL);
        }
     }

   /*======================================================*/
   /* The first field of an asserted fact must be a symbol */
   /* (but not = or : which have special significance).    */
   /*======================================================*/

   GetToken(readSource,tempToken);
   if (tempToken->type != SYMBOL)
     {
      SyntaxErrorMessage("first field of a RHS pattern");
      *error = TRUE;
      return(NULL);
     }
   else if ((strcmp(ValueToString(tempToken->value),"=") == 0) ||
            (strcmp(ValueToString(tempToken->value),":") == 0))
     {
      SyntaxErrorMessage("first field of a RHS pattern");
      *error = TRUE;
      return(NULL);
     }

   /*=========================================================*/
   /* Check to see if the relation name is a reserved symbol. */
   /*=========================================================*/

   templateName = (struct symbolHashNode *) tempToken->value;

   if (ReservedPatternSymbol(ValueToString(templateName),NULL))
     {
      ReservedPatternSymbolErrorMsg(ValueToString(templateName),"a relation name");
      *error = TRUE;
      return(NULL);
     }

   /*============================================================*/
   /* A module separator in the name is illegal in this context. */
   /*============================================================*/

   if (FindModuleSeparator(ValueToString(templateName)))
     {
      IllegalModuleSpecifierMessage();

      *error = TRUE;
      return(NULL);
     }

   /*=============================================================*/
   /* Determine if there is an associated deftemplate. If so, let */
   /* the deftemplate parsing functions parse the RHS pattern and */
   /* then return the fact pattern that was parsed.               */
   /*=============================================================*/

   theDeftemplate = (struct deftemplate *)
                    FindImportedConstruct("deftemplate",NULL,ValueToString(templateName),
                                          &count,TRUE,NULL);

   if (count > 1)
     {
      AmbiguousReferenceErrorMessage("deftemplate",ValueToString(templateName));
      *error = TRUE;
      return(NULL);
     }

   /*======================================================*/
   /* If no deftemplate exists with the specified relation */
   /* name, then create an implied deftemplate.            */
   /*======================================================*/

   if (theDeftemplate == NULL)
#if (! BLOAD_ONLY) && (! RUN_TIME)
     {
#if BLOAD || BLOAD_AND_BSAVE
      if ((Bloaded()) && (! CheckSyntaxMode))
        {
         NoSuchTemplateError(ValueToString(templateName));
         *error = TRUE;
         return(NULL);
        }
#endif
#if DEFMODULE_CONSTRUCT
      if (FindImportExportConflict("deftemplate",((struct defmodule *) GetCurrentModule()),ValueToString(templateName)))
        {
         ImportExportConflictMessage("implied deftemplate",ValueToString(templateName),NULL,NULL);
         *error = TRUE;
         return(NULL);
        }
#endif
      if (! CheckSyntaxMode)
        { theDeftemplate = CreateImpliedDeftemplate((SYMBOL_HN *) templateName,TRUE); }
     }
#else
    {
     NoSuchTemplateError(ValueToString(templateName));
     *error = TRUE;
     return(NULL);
    }
#endif

   /*=========================================*/
   /* If an explicit deftemplate exists, then */
   /* parse the fact as a deftemplate fact.   */
   /*=========================================*/

   if ((theDeftemplate != NULL) && (theDeftemplate->implied == FALSE))
     {
      firstOne = GenConstant(DEFTEMPLATE_PTR,theDeftemplate);
#if FUZZY_DEFTEMPLATES 
      if (theDeftemplate->fuzzyTemplate != NULL)
         firstOne->nextArg = ParseAssertFuzzyFact(readSource,tempToken,
                                              error,endType,
                                              constantsOnly,theDeftemplate,
                                              TRUE);
      else
#endif

      firstOne->nextArg = ParseAssertTemplate(readSource,tempToken,
                                              error,endType,
                                              constantsOnly,theDeftemplate);
      if (*error)
        {
         ReturnExpression(firstOne);
         firstOne = NULL;
        }

#if CERTAINTY_FACTORS 
      else
        {
          /* if certaintly factors allowed then the next item after a fact
             specifier COULD be a certainty factor spec --- CF x.xxx
          */
          SavePPBuffer(" ");
          GetToken(readSource,tempToken);
          if ((tempToken->type == SYMBOL) &&
              ((strcmp(ValueToString(tempToken->value),"CF") == 0) ||
               (strcmp(ValueToString(tempToken->value),"cf") == 0))
             )
            {
              struct expr *CFexpr;
              /* expecting a certainty factor (float) expression */
              /* tokenToFloatExpression expect 1st token already read */
              SavePPBuffer(" ");
              GetToken(readSource,tempToken);
              CFexpr = tokenToFloatExpression(readSource,tempToken,error,constantsOnly);

              if (*error)
                {
                  ReturnExpression(firstOne);
                  return( NULL );
                }

              if (CFexpr->type == FLOAT) /* if constant -- check range */
                {
                  double cfval = ValueToDouble(CFexpr->value);
                  if (cfval > 1.0 || cfval < 0.0)
                    {
                      *error = TRUE;
                      ReturnExpression(CFexpr);
                      cfRangeError();
                      ReturnExpression(firstOne);
                      return( NULL );
                    }
                }

             /* store the CF expression in the argList of the DEFTEMPLATE_PTR expr */
             firstOne->argList = CFexpr;
            }
          else
            {
              /* Do an 'UnGetToken' function here to undo the lookahead for a CF.
                 Also need to PPBackup over the space added before reading the
                 potential CF expression -- UnGetToken does one PPBackup over the
                 token which was added to the PP Buffer
              */
              UnGetToken(tempToken);
              PPBackup();
            }
        }
#endif

      return(firstOne);
     }


   /*========================================*/
   /* Parse the fact as an ordered RHS fact. */
   /*========================================*/

   firstOne = GenConstant(DEFTEMPLATE_PTR,theDeftemplate);

#if FUZZY_DEFTEMPLATES
   /*=============================================*/
   /* Fuzzy facts parsed differently              */
   /*=============================================*/
   if (theDeftemplate->fuzzyTemplate != NULL)
     {
       firstOne->nextArg = ParseAssertFuzzyFact(readSource,tempToken,
                                                error,endType,
                                                constantsOnly,theDeftemplate,
                                                TRUE);
       if (*error)
         {
          ReturnExpression(firstOne);
          return(NULL);
         }
     }
   else
     { /*   --- matches } below with FUZZY_DEFTEMPLATES */

#endif   /* FUZZY_DEFTEMPLATES */


#if (! RUN_TIME) && (! BLOAD_ONLY)
   SavePPBuffer(" ");
#endif

   while ((nextOne = GetAssertArgument(readSource,tempToken,
                                        error,endType,constantsOnly,&printError)) != NULL)
     {
      if (argHead == NULL) argHead = nextOne;
      else lastOne->nextArg = nextOne;
      lastOne = nextOne;
#if (! RUN_TIME) && (! BLOAD_ONLY)
      SavePPBuffer(" ");
#endif
     }

   /*===========================================================*/
   /* If an error occurred, set the error flag and return NULL. */
   /*===========================================================*/

   if (*error)
     {
      if (printError) SyntaxErrorMessage("RHS patterns");
      ReturnExpression(firstOne);
      ReturnExpression(argHead);
      return(NULL);
     }

   /*=====================================*/
   /* Fix the pretty print representation */
   /* of the RHS ordered fact.            */
   /*=====================================*/

#if (! RUN_TIME) && (! BLOAD_ONLY)
   PPBackup();
   PPBackup();
   SavePPBuffer(tempToken->printForm);
#endif

   /*==========================================================*/
   /* Ordered fact assertions are processed by stuffing all of */
   /* the fact's proposition (except the relation name) into a */
   /* single multifield slot.                                  */
   /*==========================================================*/

   firstOne->nextArg = GenConstant(FACT_STORE_MULTIFIELD,AddBitMap("\0",1));
   firstOne->nextArg->argList = argHead;

#if FUZZY_DEFTEMPLATES 
     }  /*    --- matches else { above with FUZZY_DEFTEMPLATES */
#endif

#if CERTAINTY_FACTORS 
   /* if certaintly factors allowed then the next item after a fact
          specifier could be a certainty factor spec --- CF x.xxx
   */
#if (! RUN_TIME) && (! BLOAD_ONLY)
   SavePPBuffer(" ");
#endif
   GetToken(readSource,tempToken);
   if ((tempToken->type == SYMBOL) &&
           ((strcmp(ValueToString(tempToken->value),"CF") == 0) ||
                (strcmp(ValueToString(tempToken->value),"cf") == 0))
          )
         {
            struct expr *CFexpr;

                /* expecting a certainty factor (float) expression */
        /* tokenToFloatExpression expect 1st token already read */
#if (! RUN_TIME) && (! BLOAD_ONLY)
        SavePPBuffer(" ");
#endif
        GetToken(readSource,tempToken);
                CFexpr = tokenToFloatExpression(readSource,tempToken,error,constantsOnly);

            if (*error)
          {
            ReturnExpression(firstOne);
            return( NULL );
          }

            if (CFexpr->type == FLOAT) /* if constant -- check range */
                  {
                    double cfval = ValueToDouble(CFexpr->value);
                        if (cfval > 1.0 || cfval < 0.0)
                          {
                            *error = TRUE;
                ReturnExpression(CFexpr);
                            cfRangeError();
                ReturnExpression(firstOne);
                return( NULL );
                          }
                  }

                /* store the CF expression in the argList of the DEFTEMPLATE_PTR expr */
            firstOne->argList = CFexpr;
          }
        else
      {
            /* Do an 'UnGetToken' function here to undo the lookahead for a CF.
                   Also need to PPBackup over the space added before reading the
                   potential CF expression -- UnGetToken does one PPBackup over the
                   token which was added to the PP Buffer
                */
                UnGetToken(tempToken);
#if (! RUN_TIME) && (! BLOAD_ONLY)
        PPBackup();
#endif
      }

#endif   /* CERTAINTY_FACTORS */


   /*==============================*/
   /* Return the RHS ordered fact. */
   /*==============================*/

   return(firstOne);
  }