/*************************************************************************************** NAME : ParseDefclass DESCRIPTION : (defclass ...) is a construct (as opposed to a function), thus no variables may be used. This means classes may only be STATICALLY defined (like rules). INPUTS : The logical name of the router for the parser input RETURNS : FALSE if successful parse, TRUE otherwise SIDE EFFECTS : Inserts valid class definition into Class Table. NOTES : H/L Syntax : (defclass <name> [<comment>] (is-a <superclass-name>+) <class-descriptor>*) <class-descriptor> :== (slot <name> <slot-descriptor>*) | (role abstract|concrete) | (pattern-match reactive|non-reactive) These are for documentation only: (message-handler <name> [<type>]) <slot-descriptor> :== (default <default-expression>) | (default-dynamic <default-expression>) | (storage shared|local) | (access read-only|read-write|initialize-only) | (propagation no-inherit|inherit) | (source composite|exclusive) (pattern-match reactive|non-reactive) (visibility public|private) (override-message <message-name>) (type ...) | (cardinality ...) | (allowed-symbols ...) | (allowed-strings ...) | (allowed-numbers ...) | (allowed-integers ...) | (allowed-floats ...) | (allowed-values ...) | (allowed-instance-names ...) | (allowed-classes ...) | (range ...) <default-expression> ::= ?NONE | ?VARIABLE | <expression>* ***************************************************************************************/ globle int ParseDefclass( void *theEnv, char *readSource) { SYMBOL_HN *cname; DEFCLASS *cls; PACKED_CLASS_LINKS *sclasses,*preclist; TEMP_SLOT_LINK *slots = NULL; int roleSpecified = FALSE, abstract = FALSE, parseError; #if DEFRULE_CONSTRUCT int patternMatchSpecified = FALSE, reactive = TRUE; #endif SetPPBufferStatus(theEnv,ON); FlushPPBuffer(theEnv); SetIndentDepth(theEnv,3); SavePPBuffer(theEnv,"(defclass "); #if BLOAD || BLOAD_ONLY || BLOAD_AND_BSAVE if ((Bloaded(theEnv)) && (! ConstructData(theEnv)->CheckSyntaxMode)) { CannotLoadWithBloadMessage(theEnv,"defclass"); return(TRUE); } #endif cname = GetConstructNameAndComment(theEnv,readSource,&DefclassData(theEnv)->ObjectParseToken,"defclass", EnvFindDefclass,NULL,"#",TRUE, TRUE,TRUE); if (cname == NULL) return(TRUE); if (ValidClassName(theEnv,ValueToString(cname),&cls) == FALSE) return(TRUE); sclasses = ParseSuperclasses(theEnv,readSource,cname); if (sclasses == NULL) return(TRUE); preclist = FindPrecedenceList(theEnv,cls,sclasses); if (preclist == NULL) { DeletePackedClassLinks(theEnv,sclasses,TRUE); return(TRUE); } parseError = FALSE; GetToken(theEnv,readSource,&DefclassData(theEnv)->ObjectParseToken); while (GetType(DefclassData(theEnv)->ObjectParseToken) != RPAREN) { if (GetType(DefclassData(theEnv)->ObjectParseToken) != LPAREN) { SyntaxErrorMessage(theEnv,"defclass"); parseError = TRUE; break; } PPBackup(theEnv); PPCRAndIndent(theEnv); SavePPBuffer(theEnv,"("); GetToken(theEnv,readSource,&DefclassData(theEnv)->ObjectParseToken); if (GetType(DefclassData(theEnv)->ObjectParseToken) != SYMBOL) { SyntaxErrorMessage(theEnv,"defclass"); parseError = TRUE; break; } if (strcmp(DOToString(DefclassData(theEnv)->ObjectParseToken),ROLE_RLN) == 0) { if (ParseSimpleQualifier(theEnv,readSource,ROLE_RLN,CONCRETE_RLN,ABSTRACT_RLN, &roleSpecified,&abstract) == FALSE) { parseError = TRUE; break; } } #if DEFRULE_CONSTRUCT else if (strcmp(DOToString(DefclassData(theEnv)->ObjectParseToken),MATCH_RLN) == 0) { if (ParseSimpleQualifier(theEnv,readSource,MATCH_RLN,NONREACTIVE_RLN,REACTIVE_RLN, &patternMatchSpecified,&reactive) == FALSE) { parseError = TRUE; break; } } #endif else if (strcmp(DOToString(DefclassData(theEnv)->ObjectParseToken),SLOT_RLN) == 0) { slots = ParseSlot(theEnv,readSource,slots,preclist,FALSE,FALSE); if (slots == NULL) { parseError = TRUE; break; } } else if (strcmp(DOToString(DefclassData(theEnv)->ObjectParseToken),SGL_SLOT_RLN) == 0) { slots = ParseSlot(theEnv,readSource,slots,preclist,FALSE,TRUE); if (slots == NULL) { parseError = TRUE; break; } } else if (strcmp(DOToString(DefclassData(theEnv)->ObjectParseToken),MLT_SLOT_RLN) == 0) { slots = ParseSlot(theEnv,readSource,slots,preclist,TRUE,TRUE); if (slots == NULL) { parseError = TRUE; break; } } else if (strcmp(DOToString(DefclassData(theEnv)->ObjectParseToken),HANDLER_DECL) == 0) { if (ReadUntilClosingParen(theEnv,readSource,&DefclassData(theEnv)->ObjectParseToken) == FALSE) { parseError = TRUE; break; } } else { SyntaxErrorMessage(theEnv,"defclass"); parseError = TRUE; break; } GetToken(theEnv,readSource,&DefclassData(theEnv)->ObjectParseToken); } if ((GetType(DefclassData(theEnv)->ObjectParseToken) != RPAREN) || (parseError == TRUE)) { DeletePackedClassLinks(theEnv,sclasses,TRUE); DeletePackedClassLinks(theEnv,preclist,TRUE); DeleteSlots(theEnv,slots); return(TRUE); } SavePPBuffer(theEnv,"\n"); /* ========================================================================= The abstract/reactive qualities of a class are inherited if not specified ========================================================================= */ if (roleSpecified == FALSE) { if (preclist->classArray[1]->system && /* Change to cause */ (DefclassData(theEnv)->ClassDefaultsMode == CONVENIENCE_MODE)) /* default role of */ { abstract = FALSE; } /* classes to be concrete. */ else { abstract = preclist->classArray[1]->abstract; } } #if DEFRULE_CONSTRUCT if (patternMatchSpecified == FALSE) { if ((preclist->classArray[1]->system) && /* Change to cause */ (! abstract) && /* default pattern-match */ (DefclassData(theEnv)->ClassDefaultsMode == CONVENIENCE_MODE)) /* of classes to be */ { reactive = TRUE; } /* reactive. */ else { reactive = preclist->classArray[1]->reactive; } } /* ================================================================ An abstract class cannot have direct instances, thus it makes no sense for it to be reactive since it will have no objects to respond to pattern-matching ================================================================ */ if (abstract && reactive) { PrintErrorID(theEnv,"CLASSPSR",1,FALSE); EnvPrintRouter(theEnv,WERROR,"An abstract class cannot be reactive.\n"); DeletePackedClassLinks(theEnv,sclasses,TRUE); DeletePackedClassLinks(theEnv,preclist,TRUE); DeleteSlots(theEnv,slots); return(TRUE); } #endif /* ======================================================= If we're only checking syntax, don't add the successfully parsed defclass to the KB. ======================================================= */ if (ConstructData(theEnv)->CheckSyntaxMode) { DeletePackedClassLinks(theEnv,sclasses,TRUE); DeletePackedClassLinks(theEnv,preclist,TRUE); DeleteSlots(theEnv,slots); return(FALSE); } cls = NewClass(theEnv,cname); cls->abstract = abstract; #if DEFRULE_CONSTRUCT cls->reactive = reactive; #endif cls->directSuperclasses.classCount = sclasses->classCount; cls->directSuperclasses.classArray = sclasses->classArray; /* ======================================================= This is a hack to let functions which need to iterate over a class AND its superclasses to conveniently do so The real precedence list starts in position 1 ======================================================= */ preclist->classArray[0] = cls; cls->allSuperclasses.classCount = preclist->classCount; cls->allSuperclasses.classArray = preclist->classArray; rtn_struct(theEnv,packedClassLinks,sclasses); rtn_struct(theEnv,packedClassLinks,preclist); /* ================================= Shove slots into contiguous array ================================= */ if (slots != NULL) PackSlots(theEnv,cls,slots); AddClass(theEnv,cls); return(FALSE); }
static struct templateSlot *SlotDeclarations( void *theEnv, char *readSource, struct token *inputToken) { struct templateSlot *newSlot, *slotList = NULL, *lastSlot = NULL; struct templateSlot *multiSlot = NULL; while (inputToken->type != RPAREN) { /*====================================================*/ /* Slots begin with a '(' followed by a slot keyword. */ /*====================================================*/ if (inputToken->type != LPAREN) { SyntaxErrorMessage(theEnv,"deftemplate"); ReturnSlots(theEnv,slotList); ReturnSlots(theEnv,multiSlot); DeftemplateData(theEnv)->DeftemplateError = TRUE; return(NULL); } GetToken(theEnv,readSource,inputToken); if (inputToken->type != SYMBOL) { SyntaxErrorMessage(theEnv,"deftemplate"); ReturnSlots(theEnv,slotList); ReturnSlots(theEnv,multiSlot); DeftemplateData(theEnv)->DeftemplateError = TRUE; return(NULL); } /*=================*/ /* Parse the slot. */ /*=================*/ newSlot = ParseSlot(theEnv,readSource,inputToken,slotList); if (DeftemplateData(theEnv)->DeftemplateError == TRUE) { ReturnSlots(theEnv,newSlot); ReturnSlots(theEnv,slotList); ReturnSlots(theEnv,multiSlot); return(NULL); } /*===========================================*/ /* Attach the new slot to the list of slots. */ /*===========================================*/ if (newSlot != NULL) { if (lastSlot == NULL) { slotList = newSlot; } else { lastSlot->next = newSlot; } lastSlot = newSlot; } /*================================*/ /* Check for closing parenthesis. */ /*================================*/ GetToken(theEnv,readSource,inputToken); if (inputToken->type != RPAREN) { PPBackup(theEnv); SavePPBuffer(theEnv,"\n "); SavePPBuffer(theEnv,inputToken->printForm); } } SavePPBuffer(theEnv,"\n"); /*=======================*/ /* Return the slot list. */ /*=======================*/ return(slotList); }