/*******************************************************/ /* "C" Language Integrated Production System */ /* */ /* CLIPS Version 6.40 02/08/18 */ /* */ /* CONSTRUCT COMPILER MODULE */ /*******************************************************/ /*************************************************************/ /* Purpose: Provides core routines for the constructs-to-c */ /* command. */ /* */ /* Principal Programmer(s): */ /* Gary D. Riley */ /* Brian L. Dantes */ /* Barry Cameron */ /* */ /* Contributing Programmer(s): */ /* */ /* Revision History: */ /* */ /* 6.23: Modifications to use the system constant */ /* FILENAME_MAX to check file name lengths. */ /* DR0856 */ /* */ /* Corrected compilation errors for files */ /* generated by constructs-to-c. DR0861 */ /* */ /* 6.24: Used EnvClear rather than Clear in */ /* InitCImage initialization code. */ /* */ /* Added environment parameter to GenClose. */ /* Added environment parameter to GenOpen. */ /* */ /* Removed SHORT_LINK_NAMES code as this option */ /* is no longer supported. */ /* */ /* Support for run-time programs directly passing */ /* the hash tables for initialization. */ /* */ /* 6.30: Added path name argument to constructs-to-c. */ /* */ /* Changed integer type/precision. */ /* */ /* Support for long long integers. */ /* */ /* Removed conditional code for unsupported */ /* compilers/operating systems (IBM_MCW, MAC_MCW, */ /* IBM_TBC, IBM_MSC, IBM_ICB, IBM_ZTC, and */ /* IBM_SC). */ /* */ /* Use genstrcpy instead of strcpy. */ /* */ /* Added const qualifiers to remove C++ */ /* deprecation warnings. */ /* */ /* 6.40: Changed restrictions from char * to */ /* CLIPSLexeme * to support strings */ /* originating from sources that are not */ /* statically allocated. */ /* */ /* Pragma once and other inclusion changes. */ /* */ /* Added support for booleans with . */ /* */ /* Removed use of void pointers for specific */ /* data structures. */ /* */ /* Removed VAX_VMS support. */ /* */ /* Callbacks must be environment aware. */ /* */ /* UDF redesign. */ /* */ /* Eval support for run time and bload only. */ /* */ /*************************************************************/ #include "setup.h" #if CONSTRUCT_COMPILER && (! RUN_TIME) #include #include #include #include "argacces.h" #include "constant.h" #include "constrct.h" #include "cstrccom.h" #include "cstrncmp.h" #include "exprnpsr.h" #include "envrnmnt.h" #include "memalloc.h" #include "modulcmp.h" #include "prntutil.h" #include "router.h" #include "symbol.h" #include "sysdep.h" #include "utility.h" #if DEFRULE_CONSTRUCT #include "network.h" #endif #if DEFFUNCTION_CONSTRUCT #include "dffnxcmp.h" #endif #if DEFTEMPLATE_CONSTRUCT #include "tmpltcmp.h" #endif #if DEFGLOBAL_CONSTRUCT #include "globlcmp.h" #endif #if DEFGENERIC_CONSTRUCT #include "genrccmp.h" #endif #if OBJECT_SYSTEM #include "objcmp.h" #endif #include "conscomp.h" /***************/ /* DEFINITIONS */ /***************/ #define EXTRA_FILE_NAME 20 /**********************************************/ /* CONSTRUCT CODES DEFINITIONS: The codes F, */ /* I, B, S, E, P, L, and C are not included */ /* because those are already taken. */ /* */ /* B: BitMap hash nodes */ /* C: Constraint hash nodes */ /* E: Expression hash nodes */ /* F: Float hash nodes */ /* I: Integer hash nodes */ /* L: Bitmaps */ /* P: Functions */ /* S: Symbol hash nodes */ /**********************************************/ #define PRIMARY_CODES "ADGHJKMNOQRTUVWXYZ" #define PRIMARY_LEN 18 const char *SecondaryCodes[] = { "A" , "B", "C", "D", "E" , "F" , "G" , "H", "I", "J" , "K", "L" , "M", "N", "O", "P" , "Q" , "R" , "S", "T", "U" , "V", "W" , "X", "Y", "Z", "AA", "BB", "CC", "DD", "EE" , "FF" }; #define SECONDARY_LEN 32 /***************************************/ /* LOCAL INTERNAL FUNCTION DEFINITIONS */ /***************************************/ void ConstructsToCCommand(Environment *,UDFContext *,UDFValue *); static bool ConstructsToC(Environment *,const char *,const char *,char *,long long,long long); static void WriteFunctionExternDeclarations(Environment *,FILE *); static bool FunctionsToCode(Environment *theEnv,const char *,const char *,char *); static bool WriteInitializationFunction(Environment *,const char *,const char *,char *); static void DumpExpression(Environment *,struct expr *); static void MarkConstruct(Environment *,ConstructHeader *,void *); static void HashedExpressionsToCode(Environment *); static void DeallocateConstructCompilerData(Environment *); /**********************************************************/ /* InitializeConstructCompilerData: Allocates environment */ /* data for the constructs-to-c command. */ /**********************************************************/ void InitializeConstructCompilerData( Environment *theEnv) { AllocateEnvironmentData(theEnv,CONSTRUCT_COMPILER_DATA,sizeof(struct constructCompilerData),DeallocateConstructCompilerData); ConstructCompilerData(theEnv)->MaxIndices = 2000; ConstructCompilerData(theEnv)->CodeGeneratorCount = 0; } /************************************************************/ /* DeallocateConstructCompilerData: Deallocates environment */ /* data for the constructs-to-c command. */ /************************************************************/ static void DeallocateConstructCompilerData( Environment *theEnv) { struct CodeGeneratorItem *tmpPtr, *nextPtr; unsigned int i; tmpPtr = ConstructCompilerData(theEnv)->ListOfCodeGeneratorItems; while (tmpPtr != NULL) { nextPtr = tmpPtr->next; for (i = 0; i < tmpPtr->arrayCount ; i++) { rm(theEnv,tmpPtr->arrayNames[i],strlen(tmpPtr->arrayNames[i]) + 1); } if (tmpPtr->arrayCount != 0) { rm(theEnv,tmpPtr->arrayNames,sizeof(char *) * tmpPtr->arrayCount); } rtn_struct(theEnv,CodeGeneratorItem,tmpPtr); tmpPtr = nextPtr; } } /**********************************************/ /* ConstructsToCCommand: H/L access routine */ /* for the constructs-to-c command. */ /**********************************************/ void ConstructsToCCommand( Environment *theEnv, UDFContext *context, UDFValue *returnValue) { const char *fileName; char *fileNameBuffer; const char *pathName; UDFValue theArg; long long id, max; size_t nameLength, pathLength; #if WIN_MVC int i; #endif /*====================================================*/ /* Get the name of the file in which to place C code. */ /*====================================================*/ if (! UDFFirstArgument(context,LEXEME_BITS,&theArg)) { return; } fileName = theArg.lexemeValue->contents; nameLength = strlen(fileName); /*================================*/ /* File names for the VAX and IBM */ /* PCs can't contain a period. */ /*================================*/ #if WIN_MVC for (i = 0 ; *(fileName+i) ; i++) { if (*(fileName+i) == '.') { PrintErrorID(theEnv,"CONSCOMP",1,false); WriteString(theEnv,STDERR,"Invalid file name "); WriteString(theEnv,STDERR,fileName); WriteString(theEnv,STDERR," contains \'.\'\n"); return; } } #endif /*==========================================================*/ /* The maximum file name size that can be passed into fopen */ /* is specified by FILENAME_MAX. Assume that the most */ /* characters that will be appended to the file prefix will */ /* be 20 and check that the prefix plus the additional */ /* characters is less than the supported maximum. */ /*==========================================================*/ if ((nameLength + EXTRA_FILE_NAME) > FILENAME_MAX) { PrintErrorID(theEnv,"CONSCOMP",2,false); WriteString(theEnv,STDERR,"Aborting because the base file name may cause the fopen maximum of "); WriteInteger(theEnv,STDERR,FILENAME_MAX); WriteString(theEnv,STDERR," to be violated when file names are generated.\n"); return; } /*====================================*/ /* Get the runtime image ID argument. */ /*====================================*/ if (! UDFNextArgument(context,INTEGER_BIT,&theArg)) { return; } id = theArg.integerValue->contents; if (id < 0) { ExpectedTypeError1(theEnv,"constructs-to-c",2,"'positive integer'"); return; } /*==================================================*/ /* Get the path name argument if one was specified. */ /*==================================================*/ if (UDFHasNextArgument(context)) { if (! UDFNextArgument(context,LEXEME_BITS,&theArg)) { return; } pathName = theArg.lexemeValue->contents; pathLength = strlen(pathName); } else { pathName = ""; pathLength = 0; } /*===========================================*/ /* Get the maximum number of data structures */ /* to store per file argument (if supplied). */ /*===========================================*/ if (UDFHasNextArgument(context)) { if (! UDFNextArgument(context,INTEGER_BIT,&theArg)) { return; } max = theArg.integerValue->contents; if (max < 0) { ExpectedTypeError1(theEnv,"constructs-to-c",4,"'positive integer'"); return; } } else { max = 10000; } /*============================*/ /* Call the driver routine to */ /* generate the C code. */ /*============================*/ fileNameBuffer = (char *) genalloc(theEnv,nameLength + pathLength + EXTRA_FILE_NAME); ConstructsToC(theEnv,fileName,pathName,fileNameBuffer,id,max); genfree(theEnv,fileNameBuffer,nameLength + pathLength + EXTRA_FILE_NAME); } /***************************************/ /* ConstructsToC: C access routine for */ /* the constructs-to-c command. */ /***************************************/ static bool ConstructsToC( Environment *theEnv, const char *fileName, const char *pathName, char *fileNameBuffer, long long theImageID, long long max) { unsigned fileVersion; struct CodeGeneratorItem *cgPtr; /*===============================================*/ /* Set the global MaxIndices variable indicating */ /* the maximum number of data structures to save */ /* in each file. */ /*===============================================*/ ConstructCompilerData(theEnv)->MaxIndices = (unsigned) max; /* TBD */ /*=====================================================*/ /* Open a header file for dumping general information. */ /*=====================================================*/ gensprintf(fileNameBuffer,"%s%s.h",pathName,fileName); if ((ConstructCompilerData(theEnv)->HeaderFP = GenOpen(theEnv,fileNameBuffer,"w")) == NULL) { OpenErrorMessage(theEnv,"constructs-to-c",fileNameBuffer); return false; } /*============================================*/ /* Open a file for dumping fixup information. */ /*============================================*/ gensprintf(fileNameBuffer,"%s%s_init.c",pathName,fileName); if ((ConstructCompilerData(theEnv)->FixupFP = GenOpen(theEnv,fileNameBuffer,"w")) == NULL) { OpenErrorMessage(theEnv,"constructs-to-c",fileNameBuffer); return false; } /*==================================*/ /* Call the list of functions to be */ /* executed before generating code. */ /*==================================*/ for (cgPtr = ConstructCompilerData(theEnv)->ListOfCodeGeneratorItems; cgPtr != NULL; cgPtr = cgPtr->next) { if (cgPtr->beforeFunction != NULL) (*cgPtr->beforeFunction)(theEnv); } /*=====================================*/ /* Initialize some global information. */ /*=====================================*/ ConstructCompilerData(theEnv)->FilePrefix = fileName; ConstructCompilerData(theEnv)->PathName = pathName; ConstructCompilerData(theEnv)->FileNameBuffer = fileNameBuffer; ConstructCompilerData(theEnv)->ImageID = (unsigned) theImageID; /* TBD */ ConstructCompilerData(theEnv)->ExpressionFP = NULL; ConstructCompilerData(theEnv)->ExpressionVersion = 1; ConstructCompilerData(theEnv)->ExpressionHeader = true; ConstructCompilerData(theEnv)->ExpressionCount = 0; fprintf(ConstructCompilerData(theEnv)->HeaderFP,"#ifndef _CONSTRUCT_COMPILER_HEADER_\n"); fprintf(ConstructCompilerData(theEnv)->HeaderFP,"#define _CONSTRUCT_COMPILER_HEADER_\n\n"); fprintf(ConstructCompilerData(theEnv)->HeaderFP,"#include \n"); fprintf(ConstructCompilerData(theEnv)->HeaderFP,"#include \"setup.h\"\n"); fprintf(ConstructCompilerData(theEnv)->HeaderFP,"#include \"expressn.h\"\n"); fprintf(ConstructCompilerData(theEnv)->HeaderFP,"#include \"extnfunc.h\"\n"); fprintf(ConstructCompilerData(theEnv)->HeaderFP,"#include \"%s\"\n",API_HEADER); fprintf(ConstructCompilerData(theEnv)->HeaderFP,"\n#define VS (void *)\n"); fprintf(ConstructCompilerData(theEnv)->HeaderFP,"\n"); /*=========================================================*/ /* Give extern declarations for user and system functions. */ /*=========================================================*/ WriteFunctionExternDeclarations(theEnv,ConstructCompilerData(theEnv)->HeaderFP); fprintf(ConstructCompilerData(theEnv)->HeaderFP,"\n#endif\n\n"); fprintf(ConstructCompilerData(theEnv)->HeaderFP,"/****************************/\n"); fprintf(ConstructCompilerData(theEnv)->HeaderFP,"/* EXTERN ARRAY DEFINITIONS */\n"); fprintf(ConstructCompilerData(theEnv)->HeaderFP,"/****************************/\n\n"); /*================================================*/ /* Write out the first portion of the fixup file. */ /*================================================*/ fprintf(ConstructCompilerData(theEnv)->FixupFP,"#include \"%s.h\"\n",fileName); fprintf(ConstructCompilerData(theEnv)->FixupFP,"\n"); fprintf(ConstructCompilerData(theEnv)->FixupFP,"\n"); fprintf(ConstructCompilerData(theEnv)->FixupFP,"/**********************************/\n"); fprintf(ConstructCompilerData(theEnv)->FixupFP,"/* CONSTRUCT IMAGE FIXUP FUNCTION */\n"); fprintf(ConstructCompilerData(theEnv)->FixupFP,"/**********************************/\n"); fprintf(ConstructCompilerData(theEnv)->FixupFP,"\nvoid FixupCImage_%d(\n",ConstructCompilerData(theEnv)->ImageID); fprintf(ConstructCompilerData(theEnv)->FixupFP," Environment *theEnv)\n"); fprintf(ConstructCompilerData(theEnv)->FixupFP," {\n"); /*==================================*/ /* Generate code for atomic values, */ /* function definitions, hashed */ /* expressions, and constructs. */ /*==================================*/ AtomicValuesToCode(theEnv,fileName,pathName,fileNameBuffer); FunctionsToCode(theEnv,fileName,pathName,fileNameBuffer); HashedExpressionsToCode(theEnv); ConstraintsToCode(theEnv,fileName,pathName,fileNameBuffer,4, ConstructCompilerData(theEnv)->HeaderFP, ConstructCompilerData(theEnv)->ImageID, ConstructCompilerData(theEnv)->MaxIndices); /*===============================*/ /* Call each code generator item */ /* for the various constructs. */ /*===============================*/ fileVersion = 5; for (cgPtr = ConstructCompilerData(theEnv)->ListOfCodeGeneratorItems; cgPtr != NULL; cgPtr = cgPtr->next) { if (cgPtr->generateFunction != NULL) { (*cgPtr->generateFunction)(theEnv,fileName,pathName,fileNameBuffer,fileVersion,ConstructCompilerData(theEnv)->HeaderFP,ConstructCompilerData(theEnv)->ImageID,ConstructCompilerData(theEnv)->MaxIndices); fileVersion++; } } /*=========================================*/ /* Restore the atomic data bucket values */ /* (which were set to an index reference). */ /*=========================================*/ RestoreAtomicValueBuckets(theEnv); /*============================*/ /* Close the expression file. */ /*============================*/ if (ConstructCompilerData(theEnv)->ExpressionFP != NULL) { fprintf(ConstructCompilerData(theEnv)->ExpressionFP,"};\n"); GenClose(theEnv,ConstructCompilerData(theEnv)->ExpressionFP); } /*=======================*/ /* Close the fixup file. */ /*=======================*/ if (ConstructCompilerData(theEnv)->FixupFP != NULL) { fprintf(ConstructCompilerData(theEnv)->FixupFP," }\n"); GenClose(theEnv,ConstructCompilerData(theEnv)->FixupFP); } /*====================================*/ /* Write the initialization function. */ /*====================================*/ WriteInitializationFunction(theEnv,fileName,pathName,fileNameBuffer); /*========================*/ /* Close the header file. */ /*========================*/ GenClose(theEnv,ConstructCompilerData(theEnv)->HeaderFP); /*==================================================*/ /* Return true to indicate that the constructs-to-c */ /* command was successfully executed. */ /*==================================================*/ return true; } /*******************************************************/ /* WriteFunctionExternDeclarations: Loop through the */ /* list of function definitions and generates extern */ /* declarations for them in the specified file. */ /*******************************************************/ static void WriteFunctionExternDeclarations( Environment *theEnv, FILE *fp) { struct functionDefinition *theFunction; fprintf(fp,"\n"); fprintf(fp,"/************************************/\n"); fprintf(fp,"/* EXTERNAL FUNCTION DEFINITIONS */\n"); fprintf(fp,"/************************************/\n\n"); for (theFunction = GetFunctionList(theEnv); theFunction != NULL; theFunction = theFunction->next) { fprintf(fp,"extern "); fprintf(fp,"void "); fprintf(fp,"%s(",theFunction->actualFunctionName); fprintf(fp,"Environment *,UDFContext *,UDFValue *"); fprintf(fp,");\n"); } } /****************************************************/ /* FunctionsToCode: Generates C code to represent */ /* the function declaration data structures (used */ /* to declare system and user defined functions). */ /****************************************************/ static bool FunctionsToCode( Environment *theEnv, const char *fileName, const char *pathName, char *fileNameBuffer) { unsigned short i = 0; FILE *fp; unsigned version = 1; bool newHeader = true; struct functionDefinition *fctnPtr; /*=============================*/ /* Assign a reference index to */ /* each of the functions. */ /*=============================*/ for (fctnPtr = GetFunctionList(theEnv); fctnPtr != NULL; fctnPtr = fctnPtr->next) { fctnPtr->bsaveIndex = i++; } /*=======================================*/ /* Create the file in which to store the */ /* function definition data structures. */ /*=======================================*/ if ((fp = NewCFile(theEnv,fileName,pathName,fileNameBuffer,2,version,false)) == NULL) { return false; } /*===============================================*/ /* Construct the definition of the function list */ /* from the definitions of the functions. */ /*===============================================*/ fprintf(fp,"\n\n"); fprintf(fp,"/************************************/\n"); fprintf(fp,"/* FUNCTION LIST DEFINITION */\n"); fprintf(fp,"/************************************/\n\n"); i = 1; fctnPtr = GetFunctionList(theEnv); while (fctnPtr != NULL) { if (newHeader) { fprintf(fp,"struct functionDefinition P%d_%d[] = {\n",ConstructCompilerData(theEnv)->ImageID,version); fprintf(ConstructCompilerData(theEnv)->HeaderFP,"extern struct functionDefinition P%d_%d[];\n",ConstructCompilerData(theEnv)->ImageID,version); newHeader = false; } fprintf(fp,"{"); PrintSymbolReference(theEnv,fp,fctnPtr->callFunctionName); fprintf(fp,",\"%s\",",fctnPtr->actualFunctionName); fprintf(fp,"%u,",fctnPtr->unknownReturnValueType); fprintf(fp,"%s,",fctnPtr->actualFunctionName); fprintf(fp,"NULL,"); PrintSymbolReference(theEnv,fp,fctnPtr->restrictions); fprintf(fp,",%d,%d,0,0,0,0,",fctnPtr->minArgs,fctnPtr->maxArgs); PrintFunctionReference(theEnv,fp,fctnPtr->next); i++; fctnPtr = fctnPtr->next; if ((i > ConstructCompilerData(theEnv)->MaxIndices) || (fctnPtr == NULL)) { fprintf(fp,"}};\n"); GenClose(theEnv,fp); i = 1; version++; if (fctnPtr != NULL) { if ((fp = NewCFile(theEnv,fileName,pathName,fileNameBuffer,2,version,false)) == NULL) return false; newHeader = true; } } else { fprintf(fp,"},\n"); } } return true; } /************************************************************/ /* PrintFunctionReference: Writes the C code representation */ /* of a pointer to a function definition data structure. */ /************************************************************/ void PrintFunctionReference( Environment *theEnv, FILE *fp, struct functionDefinition *funcPtr) { if (funcPtr == NULL) fprintf(fp,"NULL"); else fprintf(fp,"&P%d_%lu[%lu]",ConstructCompilerData(theEnv)->ImageID, (funcPtr->bsaveIndex / ConstructCompilerData(theEnv)->MaxIndices) + 1, funcPtr->bsaveIndex % ConstructCompilerData(theEnv)->MaxIndices); } /******************************************/ /* WriteInitializationFunction: Generates */ /* the C initialization function for */ /* this constructs-to-c module. */ /******************************************/ static bool WriteInitializationFunction( Environment *theEnv, const char *fileName, const char *pathName, char *fileNameBuffer) { FILE *fp; struct CodeGeneratorItem *cgPtr; /*===============================*/ /* Open the initialization file. */ /*===============================*/ gensprintf(fileNameBuffer,"%s%s.c",pathName,fileName); if ((fp = GenOpen(theEnv,fileNameBuffer,"w")) == NULL) { OpenErrorMessage(theEnv,"constructs-to-c",fileNameBuffer); return false; } /*=====================================*/ /* Write out #includes and prototypes. */ /*=====================================*/ fprintf(fp,"#include \"%s.h\"\n",fileName); fprintf(fp,"\n"); fprintf(fp,"#include \"utility.h\"\n"); fprintf(fp,"#include \"generate.h\"\n"); fprintf(fp,"#include \"envrnmnt.h\"\n"); fprintf(fp,"#include \"expressn.h\"\n"); fprintf(fp,"#include \"extnfunc.h\"\n"); fprintf(fp,"#include \"objrtmch.h\"\n"); fprintf(fp,"#include \"rulebld.h\"\n\n"); fprintf(ConstructCompilerData(theEnv)->HeaderFP," Environment *InitCImage_%d(void);\n",ConstructCompilerData(theEnv)->ImageID); fprintf(ConstructCompilerData(theEnv)->HeaderFP," void FixupCImage_%d(Environment *);\n",ConstructCompilerData(theEnv)->ImageID); /*============================================*/ /* Begin writing the initialization function. */ /*============================================*/ fprintf(fp,"\n"); fprintf(fp,"/*******************************************/\n"); fprintf(fp,"/* CONSTRUCT IMAGE INITIALIZATION FUNCTION */\n"); fprintf(fp,"/*******************************************/\n"); fprintf(fp,"\nEnvironment *InitCImage_%d()\n",ConstructCompilerData(theEnv)->ImageID); fprintf(fp," {\n"); fprintf(fp," static Environment *theEnv = NULL;\n\n"); fprintf(fp," if (theEnv != NULL) return NULL;\n\n"); fprintf(fp," theEnv = CreateRuntimeEnvironment(sht%d,fht%d,iht%d,bmht%d,P%d_1);\n\n", ConstructCompilerData(theEnv)->ImageID,ConstructCompilerData(theEnv)->ImageID, ConstructCompilerData(theEnv)->ImageID,ConstructCompilerData(theEnv)->ImageID, ConstructCompilerData(theEnv)->ImageID); fprintf(fp," Clear(theEnv);\n"); fprintf(fp," RefreshSpecialSymbols(theEnv);\n"); fprintf(fp," InitExpressionPointers(theEnv);\n"); fprintf(fp," FixupCImage_%d(theEnv);\n\n",ConstructCompilerData(theEnv)->ImageID); /*==========================================*/ /* Write construct specific initialization. */ /*==========================================*/ cgPtr = ConstructCompilerData(theEnv)->ListOfCodeGeneratorItems; while (cgPtr != NULL) { if (cgPtr->initFunction != NULL) { (*cgPtr->initFunction)(theEnv,fp,ConstructCompilerData(theEnv)->ImageID,ConstructCompilerData(theEnv)->MaxIndices); fprintf(fp,"\n"); } cgPtr = cgPtr->next; } /*================================*/ /* Close the initialization file. */ /*================================*/ fprintf(fp," return(theEnv);\n"); fprintf(fp," }\n"); GenClose(theEnv,fp); /*========================================*/ /* Return true to indicate initialization */ /* file was successfully written. */ /*========================================*/ return true; } /**************************************************/ /* NewCFile: Opens a new file for writing C code. */ /**************************************************/ FILE *NewCFile( Environment *theEnv, const char *fileName, const char *pathName, char *fileNameBuffer, unsigned id, unsigned version, bool reopenOldFile) { FILE *newFP; gensprintf(fileNameBuffer,"%s%s%d_%d.c",pathName,fileName,id,version); if (reopenOldFile) { newFP = GenOpen(theEnv,fileNameBuffer,"a"); } else { newFP = GenOpen(theEnv,fileNameBuffer,"w"); } if (newFP == NULL) { OpenErrorMessage(theEnv,"constructs-to-c",fileNameBuffer); return NULL; } if (reopenOldFile == false) { fprintf(newFP,"#include \"%s.h\"\n",fileName); fprintf(newFP,"\n"); } return(newFP); } /**********************************************************/ /* HashedExpressionsToCode: Traverses the expression hash */ /* table and calls ExpressionToCode to write the C */ /* code representation to a file of every expression in */ /* the table. */ /**********************************************************/ static void HashedExpressionsToCode( Environment *theEnv) { unsigned i; EXPRESSION_HN *exphash; for (i = 0; i < EXPRESSION_HASH_SIZE; i++) { for (exphash = ExpressionData(theEnv)->ExpressionHashTable[i]; exphash != NULL; exphash = exphash->next) { exphash->bsaveID = ConstructCompilerData(theEnv)->ExpressionCount + (ConstructCompilerData(theEnv)->MaxIndices * ConstructCompilerData(theEnv)->ExpressionVersion); ExpressionToCode(theEnv,NULL,exphash->exp); } } } /*****************************************************/ /* PrintHashedExpressionReference: Writes the C code */ /* representation of a pointer to an expression */ /* stored in the expression hash table. */ /*****************************************************/ void PrintHashedExpressionReference( Environment *theEnv, FILE *theFile, struct expr *theExpression, unsigned imageID, unsigned maxIndices) { unsigned long theIDValue; if (theExpression == NULL) { fprintf(theFile,"NULL"); } else { theIDValue = HashedExpressionIndex(theEnv,theExpression); fprintf(theFile,"&E%d_%ld[%ld]", imageID, theIDValue / maxIndices, theIDValue % maxIndices); } } /**************************************************************/ /* ExpressionToCode: Writes the C code reference of a pointer */ /* to an expression and then calls DumpExpression to write */ /* the C code for the expression to the expression file. */ /**************************************************************/ int ExpressionToCode( Environment *theEnv, FILE *fp, struct expr *exprPtr) { /*========================================*/ /* Print the reference to the expression. */ /*========================================*/ if (exprPtr == NULL) { if (fp != NULL) fprintf(fp,"NULL"); return 0; } else if (fp != NULL) { fprintf(fp,"&E%d_%d[%ld]",ConstructCompilerData(theEnv)->ImageID,ConstructCompilerData(theEnv)->ExpressionVersion,ConstructCompilerData(theEnv)->ExpressionCount); } /*==================================================*/ /* Create a new expression code file, if necessary. */ /*==================================================*/ if (ConstructCompilerData(theEnv)->ExpressionHeader == true) { if ((ConstructCompilerData(theEnv)->ExpressionFP = NewCFile(theEnv,ConstructCompilerData(theEnv)->FilePrefix, ConstructCompilerData(theEnv)->PathName, ConstructCompilerData(theEnv)->FileNameBuffer, 3,ConstructCompilerData(theEnv)->ExpressionVersion,false)) == NULL) { return(-1); } fprintf(ConstructCompilerData(theEnv)->ExpressionFP,"struct expr E%d_%d[] = {\n",ConstructCompilerData(theEnv)->ImageID,ConstructCompilerData(theEnv)->ExpressionVersion); fprintf(ConstructCompilerData(theEnv)->HeaderFP,"extern struct expr E%d_%d[];\n",ConstructCompilerData(theEnv)->ImageID,ConstructCompilerData(theEnv)->ExpressionVersion); ConstructCompilerData(theEnv)->ExpressionHeader = false; } else { fprintf(ConstructCompilerData(theEnv)->ExpressionFP,",\n"); } /*===========================*/ /* Dump the expression code. */ /*===========================*/ DumpExpression(theEnv,exprPtr); /*=========================================*/ /* Close the expression file if necessary. */ /*=========================================*/ if (ConstructCompilerData(theEnv)->ExpressionCount >= ConstructCompilerData(theEnv)->MaxIndices) { ConstructCompilerData(theEnv)->ExpressionCount = 0; ConstructCompilerData(theEnv)->ExpressionVersion++; fprintf(ConstructCompilerData(theEnv)->ExpressionFP,"};\n"); GenClose(theEnv,ConstructCompilerData(theEnv)->ExpressionFP); ConstructCompilerData(theEnv)->ExpressionFP = NULL; ConstructCompilerData(theEnv)->ExpressionHeader = true; } /*==========================================*/ /* Return 1 to indicate the expression */ /* reference and expression data structures */ /* were succcessfully written to the file. */ /*==========================================*/ return 1; } /**********************************************************/ /* DumpExpression: Writes the C code representation of an */ /* expression data structure to the expression file. */ /**********************************************************/ static void DumpExpression( Environment *theEnv, struct expr *exprPtr) { while (exprPtr != NULL) { fprintf(ConstructCompilerData(theEnv)->ExpressionFP,"{"); fprintf(ConstructCompilerData(theEnv)->ExpressionFP,"%d,",exprPtr->type); fprintf(ConstructCompilerData(theEnv)->ExpressionFP,"{ "); switch (exprPtr->type) { case FCALL: PrintFunctionReference(theEnv,ConstructCompilerData(theEnv)->ExpressionFP,exprPtr->functionValue); break; case INTEGER_TYPE: PrintIntegerReference(theEnv,ConstructCompilerData(theEnv)->ExpressionFP,exprPtr->integerValue); break; case FLOAT_TYPE: PrintFloatReference(theEnv,ConstructCompilerData(theEnv)->ExpressionFP,exprPtr->floatValue); break; case PCALL: #if DEFFUNCTION_CONSTRUCT PrintDeffunctionReference(theEnv,ConstructCompilerData(theEnv)->ExpressionFP,(Deffunction *) exprPtr->value, ConstructCompilerData(theEnv)->ImageID,ConstructCompilerData(theEnv)->MaxIndices); #else fprintf(ConstructCompilerData(theEnv)->ExpressionFP,"NULL"); #endif break; case GCALL: #if DEFGENERIC_CONSTRUCT PrintGenericFunctionReference(theEnv,ConstructCompilerData(theEnv)->ExpressionFP,(Defgeneric *) exprPtr->value, ConstructCompilerData(theEnv)->ImageID,ConstructCompilerData(theEnv)->MaxIndices); #else fprintf(ConstructCompilerData(theEnv)->ExpressionFP,"NULL"); #endif break; case DEFTEMPLATE_PTR: #if DEFTEMPLATE_CONSTRUCT DeftemplateCConstructReference(theEnv,ConstructCompilerData(theEnv)->ExpressionFP, (Deftemplate *) exprPtr->value,ConstructCompilerData(theEnv)->ImageID,ConstructCompilerData(theEnv)->MaxIndices); #else fprintf(ConstructCompilerData(theEnv)->ExpressionFP,"NULL"); #endif break; case DEFGLOBAL_PTR: #if DEFGLOBAL_CONSTRUCT DefglobalCConstructReference(theEnv,ConstructCompilerData(theEnv)->ExpressionFP, (Defglobal *) exprPtr->value,ConstructCompilerData(theEnv)->ImageID,ConstructCompilerData(theEnv)->MaxIndices); #else fprintf(ConstructCompilerData(theEnv)->ExpressionFP,"NULL"); #endif break; case DEFCLASS_PTR: #if OBJECT_SYSTEM PrintClassReference(theEnv,ConstructCompilerData(theEnv)->ExpressionFP, (Defclass *) exprPtr->value,ConstructCompilerData(theEnv)->ImageID, ConstructCompilerData(theEnv)->MaxIndices); #else fprintf(ConstructCompilerData(theEnv)->ExpressionFP,"NULL"); #endif break; case FACT_ADDRESS_TYPE: #if DEFTEMPLATE_CONSTRUCT fprintf(ConstructCompilerData(theEnv)->ExpressionFP,"NULL"); fprintf(ConstructCompilerData(theEnv)->FixupFP, " E%d_%d[%ld].value = &FactData(theEnv)->DummyFact;\n", ConstructCompilerData(theEnv)->ImageID, ConstructCompilerData(theEnv)->ExpressionVersion, ConstructCompilerData(theEnv)->ExpressionCount); #else fprintf(ConstructCompilerData(theEnv)->ExpressionFP,"NULL"); #endif break; case INSTANCE_ADDRESS_TYPE: #if OBJECT_SYSTEM fprintf(ConstructCompilerData(theEnv)->ExpressionFP,"NULL"); fprintf(ConstructCompilerData(theEnv)->FixupFP, " E%d_%d[%ld].value = &InstanceData(theEnv)->DummyInstance;\n", ConstructCompilerData(theEnv)->ImageID, ConstructCompilerData(theEnv)->ExpressionVersion, ConstructCompilerData(theEnv)->ExpressionCount); #else fprintf(ConstructCompilerData(theEnv)->ExpressionFP,"NULL"); #endif break; case STRING_TYPE: case SYMBOL_TYPE: case INSTANCE_NAME_TYPE: case GBL_VARIABLE: PrintSymbolReference(theEnv,ConstructCompilerData(theEnv)->ExpressionFP,exprPtr->lexemeValue); break; case VOID_TYPE: fprintf(ConstructCompilerData(theEnv)->ExpressionFP,"NULL"); break; default: if (EvaluationData(theEnv)->PrimitivesArray[exprPtr->type] == NULL) { fprintf(ConstructCompilerData(theEnv)->ExpressionFP,"NULL"); } else if (EvaluationData(theEnv)->PrimitivesArray[exprPtr->type]->bitMap) { PrintBitMapReference(theEnv,ConstructCompilerData(theEnv)->ExpressionFP,(CLIPSBitMap *) exprPtr->value); } else { fprintf(ConstructCompilerData(theEnv)->ExpressionFP,"NULL"); } break; } fprintf(ConstructCompilerData(theEnv)->ExpressionFP,"},"); ConstructCompilerData(theEnv)->ExpressionCount++; if (exprPtr->argList == NULL) { fprintf(ConstructCompilerData(theEnv)->ExpressionFP,"NULL,"); } else { fprintf(ConstructCompilerData(theEnv)->ExpressionFP,"&E%d_%d[%ld],",ConstructCompilerData(theEnv)->ImageID,ConstructCompilerData(theEnv)->ExpressionVersion, ConstructCompilerData(theEnv)->ExpressionCount); } if (exprPtr->nextArg == NULL) { fprintf(ConstructCompilerData(theEnv)->ExpressionFP,"NULL}"); } else { fprintf(ConstructCompilerData(theEnv)->ExpressionFP,"&E%d_%d[%ld]}",ConstructCompilerData(theEnv)->ImageID,ConstructCompilerData(theEnv)->ExpressionVersion, ConstructCompilerData(theEnv)->ExpressionCount + ExpressionSize(exprPtr->argList)); } if (exprPtr->argList != NULL) { fprintf(ConstructCompilerData(theEnv)->ExpressionFP,",\n"); DumpExpression(theEnv,exprPtr->argList); } exprPtr = exprPtr->nextArg; if (exprPtr != NULL) fprintf(ConstructCompilerData(theEnv)->ExpressionFP,",\n"); } } /***********************************************/ /* ConstructsToCCommandDefinition: Initializes */ /* the constructs-to-c command. */ /***********************************************/ void ConstructsToCCommandDefinition( Environment *theEnv) { AddUDF(theEnv,"constructs-to-c","v",2,4,"*;sy;l;sy;l",ConstructsToCCommand,"ConstructsToCCommand",NULL); } /*********************************************************/ /* AddCodeGeneratorItem: Adds another code generator */ /* item to the list of items for which code is */ /* generated bythe constructs-to-c function. Typically */ /* each construct has its own code generator item. */ /*********************************************************/ struct CodeGeneratorItem *AddCodeGeneratorItem( Environment *theEnv, const char *name, int priority, void (*beforeFunction)(Environment *), void (*initFunction)(Environment *,FILE *,unsigned,unsigned), bool (*generateFunction)(Environment *,const char *,const char *,char *, unsigned int,FILE *,unsigned int,unsigned int), unsigned arrayCount) { struct CodeGeneratorItem *newPtr, *currentPtr, *lastPtr = NULL; unsigned int i; char theBuffer[4]; /*======================================*/ /* Create the code generator item data */ /* structure and initialize its values. */ /*======================================*/ newPtr = get_struct(theEnv,CodeGeneratorItem); newPtr->name = name; newPtr->beforeFunction = beforeFunction; newPtr->initFunction = initFunction; newPtr->generateFunction = generateFunction; newPtr->priority = priority; newPtr->arrayCount = arrayCount; /*================================================*/ /* Create the primary and secondary codes used to */ /* provide names for the C data structure arrays. */ /* (The maximum number of arrays is currently */ /* limited to 47. */ /*================================================*/ if (arrayCount != 0) { if ((arrayCount + ConstructCompilerData(theEnv)->CodeGeneratorCount) > (PRIMARY_LEN + SECONDARY_LEN)) { SystemError(theEnv,"CONSCOMP",3); ExitRouter(theEnv,EXIT_FAILURE); } newPtr->arrayNames = (char **) gm2(theEnv,(sizeof(char *) * arrayCount)); for (i = 0 ; i < arrayCount ; i++) { if (ConstructCompilerData(theEnv)->CodeGeneratorCount < PRIMARY_LEN) { gensprintf(theBuffer,"%c",PRIMARY_CODES[ConstructCompilerData(theEnv)->CodeGeneratorCount]); } else { gensprintf(theBuffer,"%s_",SecondaryCodes[ConstructCompilerData(theEnv)->CodeGeneratorCount - PRIMARY_LEN]); } ConstructCompilerData(theEnv)->CodeGeneratorCount++; newPtr->arrayNames[i] = (char *) gm2(theEnv,(strlen(theBuffer) + 1)); genstrcpy(newPtr->arrayNames[i],theBuffer); } } else { newPtr->arrayNames = NULL; } /*===========================================*/ /* Add the new item in the appropriate place */ /* in the code generator item list. */ /*===========================================*/ if (ConstructCompilerData(theEnv)->ListOfCodeGeneratorItems == NULL) { newPtr->next = NULL; ConstructCompilerData(theEnv)->ListOfCodeGeneratorItems = newPtr; return(newPtr); } currentPtr = ConstructCompilerData(theEnv)->ListOfCodeGeneratorItems; while ((currentPtr != NULL) ? (priority < currentPtr->priority) : false) { lastPtr = currentPtr; currentPtr = currentPtr->next; } if (lastPtr == NULL) { newPtr->next = ConstructCompilerData(theEnv)->ListOfCodeGeneratorItems; ConstructCompilerData(theEnv)->ListOfCodeGeneratorItems = newPtr; } else { newPtr->next = currentPtr; lastPtr->next = newPtr; } /*=========================*/ /* Return a pointer to the */ /* code generator item. */ /*=========================*/ return(newPtr); } /************************************************************/ /* CloseFileIfNeeded: Determines if a C file to which data */ /* structures have been written should be closed. The */ /* file is closed either when all data structures of */ /* that specific type are written to files or the maximum */ /* number of array entries for a single file has been */ /* exceeded. */ /************************************************************/ FILE *CloseFileIfNeeded( Environment *theEnv, FILE *theFile, unsigned int *theCount, unsigned int *arrayVersion, unsigned int maxIndices, bool *canBeReopened, struct CodeGeneratorFile *codeFile) { /*==========================================*/ /* If the maximum number of entries for the */ /* file hasn't been exceeded, then... */ /*==========================================*/ if (*theCount < maxIndices) { /*====================================*/ /* If the file can be reopened later, */ /* close it. Otherwise, keep it open. */ /*====================================*/ if (canBeReopened != NULL) { *canBeReopened = true; GenClose(theEnv,theFile); return NULL; } return theFile; } /*===========================================*/ /* Otherwise, the number of entries allowed */ /* in a file has been reached. Indicate that */ /* the file can't be reopened. */ /*===========================================*/ if (canBeReopened != NULL) { *canBeReopened = false; } /*===============================================*/ /* If the file is closed, then we need to reopen */ /* it to print the final closing right brace. */ /*===============================================*/ if (theFile == NULL) { if ((canBeReopened == NULL) || (codeFile == NULL)) { SystemError(theEnv,"CONSCOMP",4); ExitRouter(theEnv,EXIT_FAILURE); } if (codeFile->filePrefix == NULL) { return NULL; } theFile = NewCFile(theEnv,codeFile->filePrefix,codeFile->pathName, codeFile->fileNameBuffer, codeFile->id,codeFile->version,true); if (theFile == NULL) { SystemError(theEnv,"CONSCOMP",5); ExitRouter(theEnv,EXIT_FAILURE); } } /*================================*/ /* Print the final closing brace. */ /*================================*/ fprintf(theFile,"};\n"); GenClose(theEnv,theFile); /*============================================*/ /* Update index values for subsequent writing */ /* of data structures to files. */ /*============================================*/ *theCount = 0; (*arrayVersion)++; /*=========================*/ /* Return NULL to indicate */ /* the file is closed. */ /*=========================*/ return NULL; } /**************************************************************/ /* OpenFileIfNeeded: Determines if a C file to which data */ /* structures have been written should be closed. The */ /* file is closed either when all data structures of */ /* that specific type are written to files or the maximum */ /* number of array entries for a single file has been */ /* exceeded. */ /******************************************************************/ FILE *OpenFileIfNeeded( Environment *theEnv, FILE *theFile, const char *fileName, const char *pathName, char *fileNameBuffer, unsigned fileID, unsigned int imageID, unsigned *fileCount, unsigned int arrayVersion, FILE *headerFP, const char *structureName, char *structPrefix, bool reopenOldFile, struct CodeGeneratorFile *codeFile) { char arrayName[80]; const char *newName; unsigned int newID, newVersion; /*===========================================*/ /* If a file is being reopened, use the same */ /* version number, name, and ID as before. */ /*===========================================*/ if (reopenOldFile) { if (codeFile == NULL) { SystemError(theEnv,"CONSCOMP",6); ExitRouter(theEnv,EXIT_FAILURE); } newName = codeFile->filePrefix; newID = codeFile->id; newVersion = codeFile->version; } /*=====================================================*/ /* Otherwise, use the specified version number, name, */ /* and ID. If the appropriate argument is supplied, */ /* remember these values for later reopening the file. */ /*=====================================================*/ else { newName = fileName; newVersion = *fileCount; newID = fileID; if (codeFile != NULL) { codeFile->version = newVersion; codeFile->filePrefix = newName; codeFile->id = newID; } } /*=========================================*/ /* If the file is already open, return it. */ /*=========================================*/ if (theFile != NULL) { fprintf(theFile,",\n"); return(theFile); } /*================*/ /* Open the file. */ /*================*/ if ((theFile = NewCFile(theEnv,newName,pathName,fileNameBuffer,newID,newVersion,reopenOldFile)) == NULL) { return NULL; } /*=========================================*/ /* If this is the first time the file has */ /* been opened, write out the beginning of */ /* the array variable definition. */ /*=========================================*/ if (reopenOldFile == false) { (*fileCount)++; gensprintf(arrayName,"%s%d_%d",structPrefix,imageID,arrayVersion); fprintf(theFile,"%s %s[] = {\n",structureName,arrayName); fprintf(headerFP,"extern %s %s[];\n",structureName,arrayName); } else { fprintf(theFile,",\n"); } /*==================*/ /* Return the file. */ /*==================*/ return(theFile); } /*************************************************/ /* MarkConstructBsaveIDs: Mark all occurences of */ /* a specific construct with a unique ID. */ /*************************************************/ void MarkConstructBsaveIDs( Environment *theEnv, unsigned int constructModuleIndex) { long theCount = 0; DoForAllConstructs(theEnv,MarkConstruct,constructModuleIndex,false,&theCount); } /*************************************************************/ /* MarkConstruct: Sets the bsaveID for a specific construct. */ /* Used with the MarkConstructBsaveIDs function to mark all */ /* occurences of a specific construct with a unique ID. */ /*************************************************************/ static void MarkConstruct( Environment *theEnv, ConstructHeader *theConstruct, void *vTheBuffer) { unsigned long *count = (unsigned long *) vTheBuffer; #if MAC_XCD #pragma unused(theEnv) #endif theConstruct->bsaveID = (*count)++; } /***********************************************************/ /* ConstructHeaderToCode: Writes the C code representation */ /* of a single construct header to the specified file. */ /***********************************************************/ void ConstructHeaderToCode( Environment *theEnv, FILE *theFile, ConstructHeader *theConstruct, unsigned int imageID, unsigned int maxIndices, unsigned int moduleCount, const char *constructModulePrefix, const char *constructPrefix) { /*================*/ /* Construct Name */ /*================*/ fprintf(theFile,"{"); switch (theConstruct->constructType) { case DEFMODULE: fprintf(theFile,"DEFMODULE,"); break; case DEFRULE: fprintf(theFile,"DEFRULE,"); break; case DEFTEMPLATE: fprintf(theFile,"DEFTEMPLATE,"); break; case DEFFACTS: fprintf(theFile,"DEFFACTS,"); break; case DEFGLOBAL: fprintf(theFile,"DEFGLOBAL,"); break; case DEFFUNCTION: fprintf(theFile,"DEFFUNCTION,"); break; case DEFGENERIC: fprintf(theFile,"DEFGENERIC,"); break; case DEFMETHOD: fprintf(theFile,"DEFMETHOD,"); break; case DEFCLASS: fprintf(theFile,"DEFCLASS,"); break; case DEFMESSAGE_HANDLER: fprintf(theFile,"DEFMESSAGE_HANDLER,"); break; case DEFINSTANCES: fprintf(theFile,"DEFINSTANCES,"); break; } PrintSymbolReference(theEnv,theFile,theConstruct->name); /*===================*/ /* Pretty Print Form */ /*===================*/ fprintf(theFile,",NULL,"); /*==================*/ /* Construct Module */ /*==================*/ if (theConstruct->whichModule != NULL) { fprintf(theFile,"MIHS &%s%d_%d[%d],", constructModulePrefix, imageID, (moduleCount / maxIndices) + 1, moduleCount % maxIndices); } else { fprintf(theFile,"NULL,"); } /*==========*/ /* Bsave ID */ /*==========*/ fprintf(theFile,"0,"); /*================*/ /* Next Construct */ /*================*/ if (theConstruct->next == NULL) { fprintf(theFile,"NULL}"); } else { fprintf(theFile,"CHS &%s%d_%ld[%ld]}", constructPrefix, imageID, (theConstruct->next->bsaveID / maxIndices) + 1, theConstruct->next->bsaveID % maxIndices); } } /***********************************************************/ /* ConstructModuleToCode: Writes the C code representation */ /* of a single construct module to the specified file. */ /***********************************************************/ void ConstructModuleToCode( Environment *theEnv, FILE *theFile, Defmodule *theModule, unsigned int imageID, unsigned int maxIndices, unsigned int constructIndex, const char *constructPrefix) { struct defmoduleItemHeader *theModuleItem; /*======================*/ /* Associated Defmodule */ /*======================*/ fprintf(theFile,"{"); theModuleItem = (struct defmoduleItemHeader *) GetModuleItem(theEnv,theModule,constructIndex); PrintDefmoduleReference(theEnv,theFile,theModule); fprintf(theFile,","); /*=============================*/ /* First Construct Module Item */ /*=============================*/ if (theModuleItem->firstItem == NULL) fprintf(theFile,"NULL,"); else fprintf(theFile,"CHS &%s%d_%ld[%ld],", constructPrefix, imageID, (theModuleItem->firstItem->bsaveID / maxIndices) + 1, theModuleItem->firstItem->bsaveID % maxIndices); /*============================*/ /* Last Construct Module Item */ /*============================*/ if (theModuleItem->lastItem == NULL) fprintf(theFile,"NULL"); else fprintf(theFile,"CHS &%s%d_%ld[%ld]", constructPrefix, imageID, (theModuleItem->lastItem->bsaveID / maxIndices) + 1, theModuleItem->lastItem->bsaveID % maxIndices); fprintf(theFile,"}"); } #else /* CONSTRUCT_COMPILER && (! RUN_TIME) */ void ConstructsToCCommand(Environment *,UDFContext *,UDFValue *); /************************************/ /* ConstructsToCCommand: Definition */ /* for rule compiler stub. */ /************************************/ void ConstructsToCCommand( Environment *theEnv, UDFContext *context, UDFValue *returnValue) { #if MAC_XCD #pragma unused(theEnv) #endif } #endif /* CONSTRUCT_COMPILER && (! RUN_TIME) */