/*******************************************************/ /* "C" Language Integrated Production System */ /* */ /* CLIPS Version 6.40 10/01/16 */ /* */ /* DEFMODULE MODULE */ /*******************************************************/ /*************************************************************/ /* Purpose: Defines basic defmodule primitive functions such */ /* as allocating and deallocating, traversing, and finding */ /* defmodule data structures. */ /* */ /* Principal Programmer(s): */ /* Gary D. Riley */ /* */ /* Contributing Programmer(s): */ /* Brian L. Dantes */ /* */ /* Revision History: */ /* */ /* 6.23: Correction for FalseSymbol/TrueSymbol. DR0859 */ /* */ /* Corrected compilation errors for files */ /* generated by constructs-to-c. DR0861 */ /* */ /* 6.24: Renamed BOOLEAN macro type to intBool. */ /* */ /* 6.30: Changed integer type/precision. */ /* */ /* Removed conditional code for unsupported */ /* compilers/operating systems (IBM_MCW, */ /* MAC_MCW, and IBM_TBC). */ /* */ /* Added const qualifiers to remove C++ */ /* deprecation warnings. */ /* */ /* Converted API macros to function calls. */ /* */ /* 6.40: Pragma once and other inclusion changes. */ /* */ /* Added support for booleans with . */ /* */ /* Removed use of void pointers for specific */ /* data structures. */ /* */ /* ALLOW_ENVIRONMENT_GLOBALS no longer supported. */ /* */ /* Callbacks must be environment aware. */ /* */ /* UDF redesign. */ /* */ /*************************************************************/ #include "setup.h" #include #include #include "argacces.h" #if BLOAD || BLOAD_ONLY || BLOAD_AND_BSAVE #include "bload.h" #include "modulbin.h" #endif #include "constant.h" #include "constrct.h" #include "envrnmnt.h" #include "extnfunc.h" #include "memalloc.h" #include "modulbsc.h" #include "modulcmp.h" #include "modulpsr.h" #include "prntutil.h" #include "router.h" #include "utility.h" #include "moduldef.h" /***************************************/ /* LOCAL INTERNAL FUNCTION DEFINITIONS */ /***************************************/ #if (! RUN_TIME) static void ReturnDefmodule(Environment *,Defmodule *,bool); #endif static void DeallocateDefmoduleData(Environment *); /************************************************/ /* AllocateDefmoduleGlobals: Initializes global */ /* variables used by the defmodule construct. */ /************************************************/ void AllocateDefmoduleGlobals( Environment *theEnv) { AllocateEnvironmentData(theEnv,DEFMODULE_DATA,sizeof(struct defmoduleData),NULL); AddEnvironmentCleanupFunction(theEnv,"defmodules",DeallocateDefmoduleData,-1000); DefmoduleData(theEnv)->CallModuleChangeFunctions = true; DefmoduleData(theEnv)->MainModuleRedefinable = true; } /****************************************************/ /* DeallocateDefmoduleData: Deallocates environment */ /* data for the defmodule construct. */ /****************************************************/ static void DeallocateDefmoduleData( Environment *theEnv) { struct moduleStackItem *tmpMSPtr, *nextMSPtr; struct moduleItem *tmpMIPtr, *nextMIPtr; #if (! RUN_TIME) && (! BLOAD_ONLY) Defmodule *tmpDMPtr, *nextDMPtr; struct portConstructItem *tmpPCPtr, *nextPCPtr; #endif #if (BLOAD || BLOAD_ONLY || BLOAD_AND_BSAVE) && (! RUN_TIME) unsigned int i; size_t space; #endif #if (BLOAD || BLOAD_ONLY || BLOAD_AND_BSAVE) && (! RUN_TIME) for (i = 0; i < DefmoduleData(theEnv)->BNumberOfDefmodules; i++) { if (DefmoduleData(theEnv)->DefmoduleArray[i].itemsArray != NULL) { rm(theEnv,DefmoduleData(theEnv)->DefmoduleArray[i].itemsArray, sizeof(void *) * GetNumberOfModuleItems(theEnv)); } } space = DefmoduleData(theEnv)->BNumberOfDefmodules * sizeof(Defmodule); if (space != 0) { genfree(theEnv,DefmoduleData(theEnv)->DefmoduleArray,space); DefmoduleData(theEnv)->ListOfDefmodules = NULL; } space = DefmoduleData(theEnv)->NumberOfPortItems * sizeof(struct portItem); if (space != 0) genfree(theEnv,DefmoduleData(theEnv)->PortItemArray,space); #endif #if (! RUN_TIME) && (! BLOAD_ONLY) tmpDMPtr = DefmoduleData(theEnv)->ListOfDefmodules; while (tmpDMPtr != NULL) { nextDMPtr = (Defmodule *) tmpDMPtr->header.next; ReturnDefmodule(theEnv,tmpDMPtr,true); tmpDMPtr = nextDMPtr; } tmpPCPtr = DefmoduleData(theEnv)->ListOfPortConstructItems; while (tmpPCPtr != NULL) { nextPCPtr = tmpPCPtr->next; rtn_struct(theEnv,portConstructItem,tmpPCPtr); tmpPCPtr = nextPCPtr; } #endif tmpMSPtr = DefmoduleData(theEnv)->ModuleStack; while (tmpMSPtr != NULL) { nextMSPtr = tmpMSPtr->next; rtn_struct(theEnv,moduleStackItem,tmpMSPtr); tmpMSPtr = nextMSPtr; } tmpMIPtr = DefmoduleData(theEnv)->ListOfModuleItems; while (tmpMIPtr != NULL) { nextMIPtr = tmpMIPtr->next; rtn_struct(theEnv,moduleItem,tmpMIPtr); tmpMIPtr = nextMIPtr; } #if (! RUN_TIME) && (! BLOAD_ONLY) DeallocateVoidCallList(theEnv,DefmoduleData(theEnv)->AfterModuleDefinedFunctions); #endif DeallocateVoidCallList(theEnv,DefmoduleData(theEnv)->AfterModuleChangeFunctions); } /**************************************************************/ /* InitializeDefmodules: Initializes the defmodule construct. */ /**************************************************************/ void InitializeDefmodules( Environment *theEnv) { DefmoduleBasicCommands(theEnv); #if (! RUN_TIME) CreateMainModule(theEnv,NULL); #endif #if DEFMODULE_CONSTRUCT && (! RUN_TIME) && (! BLOAD_ONLY) AddConstruct(theEnv,"defmodule","defmodules",ParseDefmodule,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL); #endif #if (! RUN_TIME) && DEFMODULE_CONSTRUCT AddUDF(theEnv,"get-current-module","y",0,0,NULL,GetCurrentModuleCommand,"GetCurrentModuleCommand",NULL); AddUDF(theEnv,"set-current-module","y",1,1,"y",SetCurrentModuleCommand,"SetCurrentModuleCommand",NULL); #endif } /******************************************************/ /* RegisterModuleItem: Called to register a construct */ /* which can be placed within a module. */ /******************************************************/ unsigned RegisterModuleItem( Environment *theEnv, const char *theItem, AllocateModuleFunction *allocateFunction, FreeModuleFunction *freeFunction, void *(*bloadModuleReference)(Environment *,unsigned long), void (*constructsToCModuleReference)(Environment *,FILE *,unsigned long,unsigned int,unsigned int), FindConstructFunction *findFunction) { struct moduleItem *newModuleItem; newModuleItem = get_struct(theEnv,moduleItem); newModuleItem->name = theItem; newModuleItem->allocateFunction = allocateFunction; newModuleItem->freeFunction = freeFunction; newModuleItem->bloadModuleReference = bloadModuleReference; newModuleItem->constructsToCModuleReference = constructsToCModuleReference; newModuleItem->findFunction = findFunction; newModuleItem->moduleIndex = DefmoduleData(theEnv)->NumberOfModuleItems++; newModuleItem->next = NULL; if (DefmoduleData(theEnv)->LastModuleItem == NULL) { DefmoduleData(theEnv)->ListOfModuleItems = newModuleItem; DefmoduleData(theEnv)->LastModuleItem = newModuleItem; } else { DefmoduleData(theEnv)->LastModuleItem->next = newModuleItem; DefmoduleData(theEnv)->LastModuleItem = newModuleItem; } return newModuleItem->moduleIndex; } /***********************************************************/ /* GetListOfModuleItems: Returns the list of module items. */ /***********************************************************/ struct moduleItem *GetListOfModuleItems( Environment *theEnv) { return (DefmoduleData(theEnv)->ListOfModuleItems); } /***************************************************************/ /* GetNumberOfModuleItems: Returns the number of module items. */ /***************************************************************/ unsigned GetNumberOfModuleItems( Environment *theEnv) { return DefmoduleData(theEnv)->NumberOfModuleItems; } /********************************************************/ /* FindModuleItem: Finds the module item data structure */ /* corresponding to the specified name. */ /********************************************************/ struct moduleItem *FindModuleItem( Environment *theEnv, const char *theName) { struct moduleItem *theModuleItem; for (theModuleItem = DefmoduleData(theEnv)->ListOfModuleItems; theModuleItem != NULL; theModuleItem = theModuleItem->next) { if (strcmp(theModuleItem->name,theName) == 0) return(theModuleItem); } return NULL; } /***************************************/ /* GetCurrentModule: Returns a pointer */ /* to the current module. */ /***************************************/ Defmodule *GetCurrentModule( Environment *theEnv) { return DefmoduleData(theEnv)->CurrentModule; } /***********************************************************/ /* SetCurrentModule: Sets the value of the current module. */ /***********************************************************/ Defmodule *SetCurrentModule( Environment *theEnv, Defmodule *newModule) { struct voidCallFunctionItem *changeFunctions; Defmodule *oldModule; /*=============================================*/ /* Change the current module to the specified */ /* module and save the previous current module */ /* for the return value. */ /*=============================================*/ oldModule = DefmoduleData(theEnv)->CurrentModule; DefmoduleData(theEnv)->CurrentModule = newModule; /*==========================================================*/ /* Call the list of registered functions that need to know */ /* when the module has changed. The module change functions */ /* should only be called if this is a "real" module change. */ /* Many routines temporarily change the module to look for */ /* constructs, etc. The SaveCurrentModule function will */ /* disable the change functions from being called. */ /*==========================================================*/ if (DefmoduleData(theEnv)->CallModuleChangeFunctions) { DefmoduleData(theEnv)->ModuleChangeIndex++; changeFunctions = DefmoduleData(theEnv)->AfterModuleChangeFunctions; while (changeFunctions != NULL) { (*changeFunctions->func)(theEnv,changeFunctions->context); changeFunctions = changeFunctions->next; } } /*=====================================*/ /* Return the previous current module. */ /*=====================================*/ return oldModule; } /********************************************************/ /* SaveCurrentModule: Saves current module on stack and */ /* prevents SetCurrentModule() from calling change */ /* functions */ /********************************************************/ void SaveCurrentModule( Environment *theEnv) { ModuleStackItem *tmp; tmp = get_struct(theEnv,moduleStackItem); tmp->changeFlag = DefmoduleData(theEnv)->CallModuleChangeFunctions; DefmoduleData(theEnv)->CallModuleChangeFunctions = false; tmp->theModule = DefmoduleData(theEnv)->CurrentModule; tmp->next = DefmoduleData(theEnv)->ModuleStack; DefmoduleData(theEnv)->ModuleStack = tmp; } /**********************************************************/ /* RestoreCurrentModule: Restores saved module and resets */ /* ability of SetCurrentModule() to call changed */ /* functions to previous state */ /**********************************************************/ void RestoreCurrentModule( Environment *theEnv) { ModuleStackItem *tmp; tmp = DefmoduleData(theEnv)->ModuleStack; DefmoduleData(theEnv)->ModuleStack = tmp->next; DefmoduleData(theEnv)->CallModuleChangeFunctions = tmp->changeFlag; DefmoduleData(theEnv)->CurrentModule = tmp->theModule; rtn_struct(theEnv,moduleStackItem,tmp); } /*************************************************************/ /* GetModuleItem: Returns the data pointer for the specified */ /* module item in the specified module. If no module is */ /* indicated, then the module item for the current module */ /* is returned. */ /*************************************************************/ void *GetModuleItem( Environment *theEnv, Defmodule *theModule, unsigned moduleItemIndex) { if (theModule == NULL) { if (DefmoduleData(theEnv)->CurrentModule == NULL) return NULL; theModule = DefmoduleData(theEnv)->CurrentModule; } if (theModule->itemsArray == NULL) return (NULL); return ((void *) theModule->itemsArray[moduleItemIndex]); } /************************************************************/ /* SetModuleItem: Sets the data pointer for the specified */ /* module item in the specified module. If no module is */ /* indicated, then the module item for the current module */ /* is returned. */ /************************************************************/ void SetModuleItem( Environment *theEnv, Defmodule *theModule, unsigned moduleItemIndex, void *newValue) { if (theModule == NULL) { if (DefmoduleData(theEnv)->CurrentModule == NULL) return; theModule = DefmoduleData(theEnv)->CurrentModule; } if (theModule->itemsArray == NULL) return; theModule->itemsArray[moduleItemIndex] = (struct defmoduleItemHeader *) newValue; } /******************************************************/ /* CreateMainModule: Creates the default MAIN module. */ /******************************************************/ void CreateMainModule( Environment *theEnv, void *context) { Defmodule *newDefmodule; struct moduleItem *theItem; unsigned int i; struct defmoduleItemHeader *theHeader; /*=======================================*/ /* Allocate the defmodule data structure */ /* and name it the MAIN module. */ /*=======================================*/ newDefmodule = get_struct(theEnv,defmodule); newDefmodule->header.name = CreateSymbol(theEnv,"MAIN"); IncrementLexemeCount(newDefmodule->header.name); newDefmodule->header.whichModule = NULL; newDefmodule->header.next = NULL; newDefmodule->header.ppForm = NULL; newDefmodule->importList = NULL; newDefmodule->exportList = NULL; newDefmodule->header.bsaveID = 0L; newDefmodule->header.usrData = NULL; newDefmodule->header.constructType = DEFMODULE; newDefmodule->header.env = theEnv; /*==================================*/ /* Initialize the array for storing */ /* the module's construct lists. */ /*==================================*/ if (DefmoduleData(theEnv)->NumberOfModuleItems == 0) newDefmodule->itemsArray = NULL; else { newDefmodule->itemsArray = (struct defmoduleItemHeader **) gm2(theEnv,sizeof(void *) * DefmoduleData(theEnv)->NumberOfModuleItems); for (i = 0, theItem = DefmoduleData(theEnv)->ListOfModuleItems; (i < DefmoduleData(theEnv)->NumberOfModuleItems) && (theItem != NULL); i++, theItem = theItem->next) { if (theItem->allocateFunction == NULL) { newDefmodule->itemsArray[i] = NULL; } else { newDefmodule->itemsArray[i] = (struct defmoduleItemHeader *) (*theItem->allocateFunction)(theEnv); theHeader = (struct defmoduleItemHeader *) newDefmodule->itemsArray[i]; theHeader->theModule = newDefmodule; theHeader->firstItem = NULL; theHeader->lastItem = NULL; } } } /*=======================================*/ /* Add the module to the list of modules */ /* and make it the current module. */ /*=======================================*/ #if (! BLOAD_ONLY) && (! RUN_TIME) && DEFMODULE_CONSTRUCT SetNumberOfDefmodules(theEnv,1); #endif DefmoduleData(theEnv)->LastDefmodule = newDefmodule; DefmoduleData(theEnv)->ListOfDefmodules = newDefmodule; SetCurrentModule(theEnv,newDefmodule); } /*********************************************************************/ /* SetListOfDefmodules: Sets the list of defmodules to the specified */ /* value. Normally used when initializing a run-time module or */ /* when bloading a binary file to install the list of defmodules. */ /*********************************************************************/ void SetListOfDefmodules( Environment *theEnv, Defmodule *defmodulePtr) { DefmoduleData(theEnv)->ListOfDefmodules = defmodulePtr; DefmoduleData(theEnv)->LastDefmodule = DefmoduleData(theEnv)->ListOfDefmodules; if (DefmoduleData(theEnv)->LastDefmodule == NULL) return; DefmoduleData(theEnv)->LastDefmodule->header.env = theEnv; while (DefmoduleData(theEnv)->LastDefmodule->header.next != NULL) { DefmoduleData(theEnv)->LastDefmodule = (Defmodule *) DefmoduleData(theEnv)->LastDefmodule->header.next; DefmoduleData(theEnv)->LastDefmodule->header.env = theEnv; } } /*******************************************************************/ /* GetNextDefmodule: If passed a NULL pointer, returns the first */ /* defmodule in the ListOfDefmodules. Otherwise returns the next */ /* defmodule following the defmodule passed as an argument. */ /*******************************************************************/ Defmodule *GetNextDefmodule( Environment *theEnv, Defmodule *defmodulePtr) { if (defmodulePtr == NULL) { return DefmoduleData(theEnv)->ListOfDefmodules; } else { return (Defmodule *) defmodulePtr->header.next; } } /***********************************/ /* DefmoduleName: Returns the name */ /* of the specified defmodule. */ /***********************************/ const char *DefmoduleName( Defmodule *defmodulePtr) { return defmodulePtr->header.name->contents; } /************************************************/ /* DefmodulePPForm: Returns the pretty print */ /* representation of the specified defmodule. */ /************************************************/ const char *DefmodulePPForm( Defmodule *defmodulePtr) { return defmodulePtr->header.ppForm; } #if (! RUN_TIME) /***********************************************/ /* RemoveAllDefmodules: Removes all defmodules */ /* from the current environment. */ /***********************************************/ void RemoveAllDefmodules( Environment *theEnv, void *context) { Defmodule *nextDefmodule; while (DefmoduleData(theEnv)->ListOfDefmodules != NULL) { nextDefmodule = (Defmodule *) DefmoduleData(theEnv)->ListOfDefmodules->header.next; ReturnDefmodule(theEnv,DefmoduleData(theEnv)->ListOfDefmodules,false); DefmoduleData(theEnv)->ListOfDefmodules = nextDefmodule; } DefmoduleData(theEnv)->CurrentModule = NULL; DefmoduleData(theEnv)->LastDefmodule = NULL; } /************************************************************/ /* ReturnDefmodule: Returns the data structures associated */ /* with a defmodule construct to the pool of free memory. */ /************************************************************/ static void ReturnDefmodule( Environment *theEnv, Defmodule *theDefmodule, bool environmentClear) { unsigned int i; struct moduleItem *theItem; struct portItem *theSpec, *nextSpec; /*=====================================================*/ /* Set the current module to the module being deleted. */ /*=====================================================*/ if (theDefmodule == NULL) return; if (! environmentClear) { SetCurrentModule(theEnv,theDefmodule); } /*============================================*/ /* Call the free functions for the constructs */ /* belonging to this module. */ /*============================================*/ if (theDefmodule->itemsArray != NULL) { if (! environmentClear) { for (i = 0, theItem = DefmoduleData(theEnv)->ListOfModuleItems; (i < DefmoduleData(theEnv)->NumberOfModuleItems) && (theItem != NULL); i++, theItem = theItem->next) { if (theItem->freeFunction != NULL) { (*theItem->freeFunction)(theEnv,theDefmodule->itemsArray[i]); } } } rm(theEnv,theDefmodule->itemsArray,sizeof(void *) * DefmoduleData(theEnv)->NumberOfModuleItems); } /*======================================================*/ /* Decrement the symbol count for the defmodule's name. */ /*======================================================*/ if (! environmentClear) { ReleaseLexeme(theEnv,theDefmodule->header.name); } /*====================================*/ /* Free the items in the import list. */ /*====================================*/ theSpec = theDefmodule->importList; while (theSpec != NULL) { nextSpec = theSpec->next; if (! environmentClear) { if (theSpec->moduleName != NULL) ReleaseLexeme(theEnv,theSpec->moduleName); if (theSpec->constructType != NULL) ReleaseLexeme(theEnv,theSpec->constructType); if (theSpec->constructName != NULL) ReleaseLexeme(theEnv,theSpec->constructName); } rtn_struct(theEnv,portItem,theSpec); theSpec = nextSpec; } /*====================================*/ /* Free the items in the export list. */ /*====================================*/ theSpec = theDefmodule->exportList; while (theSpec != NULL) { nextSpec = theSpec->next; if (! environmentClear) { if (theSpec->moduleName != NULL) ReleaseLexeme(theEnv,theSpec->moduleName); if (theSpec->constructType != NULL) ReleaseLexeme(theEnv,theSpec->constructType); if (theSpec->constructName != NULL) ReleaseLexeme(theEnv,theSpec->constructName); } rtn_struct(theEnv,portItem,theSpec); theSpec = nextSpec; } /*=========================================*/ /* Free the defmodule pretty print string. */ /*=========================================*/ if (theDefmodule->header.ppForm != NULL) { rm(theEnv,(void *) theDefmodule->header.ppForm, sizeof(char) * (strlen(theDefmodule->header.ppForm) + 1)); } /*=======================*/ /* Return the user data. */ /*=======================*/ ClearUserDataList(theEnv,theDefmodule->header.usrData); /*======================================*/ /* Return the defmodule data structure. */ /*======================================*/ rtn_struct(theEnv,defmodule,theDefmodule); } #endif /* (! RUN_TIME) */ /************************************************/ /* FindDefmodule: Searches for a defmodule in */ /* the list of defmodules. Returns a pointer */ /* to the defmodule if found, otherwise NULL. */ /************************************************/ Defmodule *FindDefmodule( Environment *theEnv, const char *defmoduleName) { Defmodule *defmodulePtr; CLIPSLexeme *findValue; if ((findValue = FindSymbolHN(theEnv,defmoduleName,SYMBOL_BIT)) == NULL) return NULL; defmodulePtr = DefmoduleData(theEnv)->ListOfDefmodules; while (defmodulePtr != NULL) { if (defmodulePtr->header.name == findValue) { return defmodulePtr; } defmodulePtr = (Defmodule *) defmodulePtr->header.next; } return NULL; } /*************************************************/ /* GetCurrentModuleCommand: H/L access routine */ /* for the get-current-module command. */ /*************************************************/ void GetCurrentModuleCommand( Environment *theEnv, UDFContext *context, UDFValue *returnValue) { Defmodule *theModule; theModule = GetCurrentModule(theEnv); if (theModule == NULL) { returnValue->lexemeValue = FalseSymbol(theEnv); return; } returnValue->value = theModule->header.name; } /*************************************************/ /* SetCurrentModuleCommand: H/L access routine */ /* for the set-current-module command. */ /*************************************************/ void SetCurrentModuleCommand( Environment *theEnv, UDFContext *context, UDFValue *returnValue) { UDFValue theArg; const char *argument; Defmodule *theModule; CLIPSLexeme *oldModuleName; /*=======================*/ /* Set the return value. */ /*=======================*/ theModule = GetCurrentModule(theEnv); if (theModule == NULL) { returnValue->lexemeValue = FalseSymbol(theEnv); return; } oldModuleName = theModule->header.name; returnValue->value = oldModuleName; /*=====================================================*/ /* Check for the correct number and type of arguments. */ /*=====================================================*/ if (! UDFFirstArgument(context,SYMBOL_BIT,&theArg)) { return; } argument = theArg.lexemeValue->contents; /*================================================*/ /* Set the current module to the specified value. */ /*================================================*/ theModule = FindDefmodule(theEnv,argument); if (theModule == NULL) { CantFindItemErrorMessage(theEnv,"defmodule",argument,true); return; } SetCurrentModule(theEnv,theModule); } /*************************************************/ /* AddAfterModuleChangeFunction: Adds a function */ /* to the list of functions to be called after */ /* a module change occurs. */ /*************************************************/ void AddAfterModuleChangeFunction( Environment *theEnv, const char *name, VoidCallFunction *func, int priority, void *context) { DefmoduleData(theEnv)->AfterModuleChangeFunctions = AddVoidFunctionToCallList(theEnv,name,priority,func,DefmoduleData(theEnv)->AfterModuleChangeFunctions,context); } /************************************************/ /* IllegalModuleSpecifierMessage: Error message */ /* for the illegal use of a module specifier. */ /************************************************/ void IllegalModuleSpecifierMessage( Environment *theEnv) { PrintErrorID(theEnv,"MODULDEF",1,true); WriteString(theEnv,STDERR,"Illegal use of the module specifier.\n"); } /*********************************************/ /* GetNumberOfDefmodules: Returns the number */ /* of defmodules currently defined. */ /*********************************************/ unsigned short GetNumberOfDefmodules( Environment *theEnv) { #if DEFMODULE_CONSTRUCT && (! RUN_TIME) && (! BLOAD_ONLY) return DefmoduleData(theEnv)->NumberOfDefmodules; #else return 1; #endif }