/** * Frees a compiler object and all associated memory. * compiler: an instance of Compiler. * TODO: a lot of allocations don't have frees yet. These will be added in when * the program structure becomes final. */ void compiler_free(Compiler * compiler) { assert(compiler != NULL); if(compiler->compiledScripts != NULL) { set_free(compiler->compiledScripts); } if(compiler->symTableStk != NULL) { stk_free(compiler->symTableStk); } if(compiler->functionHT != NULL) { HTIter htIterator; ht_iter_get(compiler->functionHT, &htIterator); while(ht_iter_has_next(&htIterator)) { DSValue value; ht_iter_next(&htIterator, NULL, 0, &value, NULL, true); compilerfunc_free(value.pointerVal); } ht_free(compiler->functionHT); } if(compiler->outBuffer != NULL) { buffer_free(compiler->outBuffer); } free(compiler); }
/** * Run after gunderscript_build_file() to export the compiled bytecode to an * external bytecode file. * instance: a Gunderscript object. * fileName: The name of the file to export to. Caution: file will be overwritten * returns: true upon success, or false if file cannot be opened, * no code has been built, or there was an error building code. */ GSAPI bool gunderscript_export_bytecode(Gunderscript * instance, char * fileName) { FILE * outFile = fopen(fileName, "w"); GSByteCodeHeader header; HTIter functionHTIter; char * byteCodeBuffer; /* check if file open fails */ if(outFile == NULL) { instance->err = GUNDERSCRIPTERR_BAD_FILE_OPEN_WRITE; return false; } /* create header */ strcpy(header.header, GS_BYTECODE_HEADER); strcpy(header.buildDate, __DATE__); header.byteCodeLen = vm_bytecode_size(instance->vm); header.numFunctions = ht_size(vm_functions(instance->vm)); /* write header to file, return false on failure */ if(fwrite(&header, sizeof(GSByteCodeHeader), 1, outFile) != 1) { instance->err = GUNDERSCRIPTERR_BAD_FILE_WRITE; return false; } ht_iter_get(vm_functions(instance->vm), &functionHTIter); /* write exported functions to file */ while(ht_iter_has_next(&functionHTIter)) { DSValue value; char functionName[GS_MAX_FUNCTION_NAME_LEN]; size_t functionNameLen; char outLen; /* get the next item from hashtable */ ht_iter_next(&functionHTIter, functionName, GS_MAX_FUNCTION_NAME_LEN, &value, &functionNameLen, false); /* check if the function should be exported. if so, write it to the file */ if(((VMFunc*)value.pointerVal)->exported) { /* TODO: create an error handler case for this */ assert(functionNameLen < GS_MAX_FUNCTION_NAME_LEN); /* write it's name and length to the file */ outLen = functionNameLen; if(fwrite(&outLen, sizeof(char), 1, outFile) != 1 || fwrite(functionName, sizeof(char), functionNameLen, outFile) != functionNameLen) { instance->err = GUNDERSCRIPTERR_BAD_FILE_WRITE; return false; } /* write its CompilerFunc to the file (stores function call information) */ if(fwrite(value.pointerVal, sizeof(VMFunc), 1, outFile) != 1) { instance->err = GUNDERSCRIPTERR_BAD_FILE_WRITE; return false; } } } byteCodeBuffer = vm_bytecode(instance->vm); if(byteCodeBuffer == NULL) { instance->err = GUNDERSCRIPTERR_NO_SUCCESSFUL_BUILD; return false; } /* write bytecode */ if(fwrite(byteCodeBuffer, vm_bytecode_size(instance->vm), 1, outFile) != 1) { instance->err = GUNDERSCRIPTERR_BAD_FILE_WRITE; return false; } fclose(outFile); return true; }