Parse Certain C++ Headers and Dynamically Generate Other Headers Containing Boilerplate Code
A link to the pull request in question.
I maintain a C++ DLL / Game Maker library that constructs an environment that allows one to call any game maker script/function from within the C++ dll directly. It does this by placing all DLL function calls in a second thread that then communicates function calls to the original thread at which point game maker executes the calls and sends back any return values.
The main thorn this resulted in was a plethora of wrapper functions and other boilerplate. Every time I added support for a game maker function, I would have to go and write a header declaration, write a function to import the Game Maker function ID, and write the actual function declaration which is a somewhat confusing call to add a function call struct to the thread communications. Similarly there were other wrappers to export data for the ACTUAL DLL calls and then call them in the DLL thread when the message was received.
This was all just background to my problem that my recent code changes have solved. I don’t expect anyone to review that DLL interfacing code (though I am always open to improvements!).
To solve this problem I wrote a program called "dynamicWrapperGeneration.cpp" that when ran parses various headers that used to contain all that boilerplate but now contain nothing but function declarations. It then generates the needed boilerplate files. This file specifically is the one I would like reviewed.
Normally I wouldn’t post here for a small-ish task like this (not gonna lie at one point I considered posting the entire 3000 line library here at one point), but this executable is the first of its kind for me. I have never written anything like this before, so I don’t even know what to call this thing let alone whether my methods are overly crude and clumsy. At some point this executable will actually be expanded to generate the Game Maker side scripts as well, so I want to make sure I am going down a good path with what I currently made so that way I can start to steer myself in a good direction.
Another thing to mention is that the person who primarily owns the repo I am pull requesting this to knows no C++ whatsoever, so anything that might help to make the code friendlier looking to a beginner to C++ software would be appreciated.
I have done code reviews in the past at previous and current jobs in software engineering with fellow devs on the same project, but I have never done one with random people unfamiliar with a project before. So I apologize in advance if I’m either over or under sharing.
#include <stdio.h>
#include <malloc.h>
#include <string.h>
//rs
int walk_function(FILE* inputFile, FILE* outputFile, FILE* outputFile2)
{
int began = 0;
int ended = 0;
int c = fgetc(inputFile);
while (!ended && c != EOF)
{
if (c == ' ')
{
ended = began;
began = 1;
}
c = fgetc(inputFile);
}
if (c == EOF)
return c == EOF;
began = 0;
ended = 0;
char* functionName = (char*)malloc(sizeof(char));
functionName[0] = 0;
int functionNameLength = 0;
while (!ended && c != EOF)
{
if (c == '(')
{
ended = 1;
} else
{
char* tempFunctionName = (char*)malloc((functionNameLength+2)*sizeof(char));
strcpy(tempFunctionName, functionName);
tempFunctionName[functionNameLength] = c;
tempFunctionName[functionNameLength+1] = 0;
free(functionName);
functionName = tempFunctionName;
functionNameLength++;
}
c = fgetc(inputFile);
}
fprintf(outputFile, "GMEXPORT double get_%s()\n", functionName);
fprintf(outputFile, "{\n");
fprintf(outputFile, " return (double)(int)%s;\n", functionName);
fprintf(outputFile, "}\n");
fprintf(outputFile2, "if (function_to_call == (void*)%s)\n", functionName);
fprintf(outputFile2, " function_return_value = %s(", functionName);
int argumentCount = 0;
int waitingTillComma = 0;
ended = 0;
while (!ended && c != EOF)
{
if (c == ')')
{
ended = 1;
} else if (c == 'd' && !waitingTillComma)
{
fprintf(outputFile2, "dll_input[%u].number", argumentCount);
waitingTillComma = 1;
argumentCount++;
} else if (c == 'c' && !waitingTillComma)
{
fprintf(outputFile2, "dll_input[%u].text", argumentCount);
waitingTillComma = 1;
argumentCount++;
} else if (c == ',' && waitingTillComma)
{
fprintf(outputFile2, ", ");
waitingTillComma = 0;
}
c = fgetc(inputFile);
}
fprintf(outputFile2, ");\n");
return c == EOF;
}
int walk_GML_function(FILE* inputFile, FILE* outputFile, FILE* outputFile2)
{
int ended = 0;
int functionType = 2;
int c = fgetc(inputFile);
while (!ended && c != EOF)
{
if (c == ' ')
{
ended = 1;
} else if (c == 'v' && functionType == 2)
{
functionType = 0;
} else if (c == 'd' && functionType == 2)
{
functionType = 1;
}
c = fgetc(inputFile);
}
if (c == EOF)
return c == EOF;
ended = 0;
char* functionName = (char*)malloc(sizeof(char));
functionName[0] = 0;
int functionNameLength = 0;
while (!ended && c != EOF)
{
if (c == '(')
{
ended = 1;
} else
{
char* tempFunctionName = (char*)malloc((functionNameLength+2)*sizeof(char));
strcpy(tempFunctionName, functionName);
tempFunctionName[functionNameLength] = c;
tempFunctionName[functionNameLength+1] = 0;
free(functionName);
functionName = tempFunctionName;
functionNameLength++;
}
c = fgetc(inputFile);
}
fprintf(outputFile, "ADD_FUNCTION(%s)\n", functionName);
int argumentCount = 0;
int* argumentType = NULL;
int waitingTillComma = 0;
ended = 0;
while (!ended && c != EOF)
{
if (c == ')')
{
ended = 1;
} else if (c == 'd' && !waitingTillComma)
{
int* argumentTypeTemp = (int*)malloc((argumentCount+1)*sizeof(int));
memcpy(argumentTypeTemp, argumentType, argumentCount*sizeof(int));
argumentTypeTemp[argumentCount] = 0;
free(argumentType);
argumentType = argumentTypeTemp;
waitingTillComma = 1;
argumentCount++;
} else if (c == 'c' && !waitingTillComma)
{
int* argumentTypeTemp = (int*)malloc((argumentCount+1)*sizeof(int));
memcpy(argumentTypeTemp, argumentType, argumentCount*sizeof(int));
argumentTypeTemp[argumentCount] = 1;
free(argumentType);
argumentType = argumentTypeTemp;
argumentCount++;
} else if (c == ',' && waitingTillComma)
{
waitingTillComma = 0;
}
c = fgetc(inputFile);
}
if (functionType == 0)
{
fprintf(outputFile2, "void %s(", functionName);
} else if (functionType == 1)
{
fprintf(outputFile2, "double %s(", functionName);
}
for (int i = 0; i < argumentCount; i++)
{
if (argumentType[i] == 0)
{
fprintf(outputFile2, "double input%u", i);
} else if (argumentType[i] == 1)
{
fprintf(outputFile2, "const char* input%u", i);
}
if (i+1 < argumentCount)
{
fprintf(outputFile2, ", ");
}
}
fprintf(outputFile2, ")\n");
fprintf(outputFile2, "{\n");
if (functionType == 0)
{
fprintf(outputFile2, " addDelayedFunctionCall(FP_%s, 0", functionName);
} else if (functionType == 1)
{
fprintf(outputFile2, " return addDelayedFunctionCall(FP_%s, 1", functionName);
}
for (int i = 0; i < argumentCount; i++)
{
fprintf(outputFile2, ", input%u", i);
}
fprintf(outputFile2, ");\n");
fprintf(outputFile2, "}\n");
return c == EOF;
}
void parse_GML_header(FILE* outputFile, char* inputFileName)
{
FILE* inputFile = fopen(inputFileName, "r");
while (1)
{
if (walk_GML_function(inputFile, outputFile, outputFile))
{
return;
}
}
}
void parse_GML_libraries()
{
char* outputFileName = "gameMakerGenLibrary.hpp";
FILE* outputFile = fopen(outputFileName, "w");
parse_GML_header(outputFile, "gameMakerFunctions\3円DGraphics\\d3d_model.hpp");
parse_GML_header(outputFile, "gameMakerFunctions\3円DGraphics\\d3d_primitive.hpp");
parse_GML_header(outputFile, "gameMakerFunctions\3円DGraphics\\d3d_shape.hpp");
parse_GML_header(outputFile, "gameMakerFunctions\3円DGraphics\\d3d_transform.hpp");
parse_GML_header(outputFile, "gameMakerFunctions\\gameGraphics\\fontsAndText.hpp");
parse_GML_header(outputFile, "gameMakerFunctions\\userInteraction\\mouse.hpp");
parse_GML_header(outputFile, "gameMakerFunctions\\userInteraction\\keyboard.hpp");
parse_GML_header(outputFile, "gameMakerFunctions\\userInteraction\\joystick.hpp");
parse_GML_header(outputFile, "gameMakerFunctions\\gamePlay\\rooms.hpp");
}
int main()
{
char* inputFileName = "gameLoop.hpp";
FILE* inputFile = fopen(inputFileName, "r");
char* outputFileName = "getGameLoop.hpp";
FILE* outputFile = fopen(outputFileName, "w");
char* outputFileName2 = "callGameLoop.hpp";
FILE* outputFile2 = fopen(outputFileName2, "w");
while (1)
{
if (walk_function(inputFile, outputFile, outputFile2))
{
break;
}
}
parse_GML_libraries();
}
- 113
- 7