aboutsummaryrefslogtreecommitdiff
path: root/buildtools/codegen/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'buildtools/codegen/main.cpp')
-rw-r--r--buildtools/codegen/main.cpp212
1 files changed, 179 insertions, 33 deletions
diff --git a/buildtools/codegen/main.cpp b/buildtools/codegen/main.cpp
index 74acd1c..ed8cbbe 100644
--- a/buildtools/codegen/main.cpp
+++ b/buildtools/codegen/main.cpp
@@ -76,6 +76,7 @@ BSTR_LUT_DECL(CppKeyword, 0, CKw_COUNT) {
BSTR_LUT_MAP_FOR(CppKeyword);
BSTR_LUT_MAP(CKw_Struct, "struct");
BSTR_LUT_MAP(CKw_Class, "class");
+ BSTR_LUT_MAP(CKw_Enum, "enum");
}
enum CodegenDirective {
@@ -161,6 +162,10 @@ PeekDirectiveArgumentList(const std::vector<StbLexerToken>& tokens, size_t curre
}
}
+ if (!currentArg.empty()) {
+ result.push_back(std::move(currentArg));
+ }
+
return { result, i };
}
@@ -223,21 +228,95 @@ BSTR_LUT_DECL(StructMetaGenOptions, 0, SMGO_COUNT) {
}
enum EnumMetaGenOptions {
- EMGO_Basic,
+ EMGO_ToString,
+ EMGO_ExcludeUseHeuristics,
EMGO_COUNT,
};
BSTR_LUT_DECL(EnumMetaGenOptions, 0, EMGO_COUNT) {
BSTR_LUT_MAP_FOR(EnumMetaGenOptions);
- BSTR_LUT_MAP(EMGO_Basic, "GenBasic");
+ BSTR_LUT_MAP(EMGO_ToString, "ToString");
+ BSTR_LUT_MAP(EMGO_ExcludeUseHeuristics, "ExcludeHeuristics");
+}
+
+// I give up, hopefully nothing overflows this buffer
+#define APPEND_SPRINTF(out, format, ...) \
+ { \
+ char buffer[65536]; \
+ snprintf(buffer, sizeof(buffer), format, __VA_ARGS__); \
+ out += buffer; \
+ }
+
+std::string GenerateEnumStringArray(CodegenOutput& out, const DeclEnum& decl, bool useHeruistics) {
+ std::string arrayName;
+ APPEND_SPRINTF(arrayName, "gCG_%s_StringTable", decl.name.c_str());
+
+ CodegenOutputThing thing;
+ APPEND_SPRINTF(thing.text, "const char* %s[] = {\n", arrayName.c_str());
+ for (auto& elm : decl.elements) {
+ if (useHeruistics && elm.name.ends_with("COUNT")) {
+ continue;
+ }
+
+ APPEND_SPRINTF(thing.text, "\"%s\",\n", elm.name.c_str());
+ }
+ thing.text += "};\n";
+ out.AddOutputThing(std::move(thing));
+
+ return arrayName;
+}
+
+std::string GenerateEnumStringMap(CodegenOutput& out, const DeclEnum& decl, bool useHeruistics) {
+ std::string mapName;
+ // TODO
+
+ return mapName;
}
void GenerateForEnum(CodegenOutput& out, const DeclEnum& decl, EnumFlags<EnumMetaGenOptions> options) {
+ bool useExcludeHeuristics = options.IsSet(EMGO_ExcludeUseHeuristics);
+
+ if (options.IsSet(EMGO_ToString)) {
+ // Generate name lookup table
+
+ switch (decl.CalcPattern()) {
+ case EVP_Continuous: {
+ auto arrayName = GenerateEnumStringArray(out, decl, useExcludeHeuristics);
+ int minVal = decl.elements.front().value;
+ int maxVal = decl.elements.back().value;
+ if (useExcludeHeuristics &&
+ decl.elements.back().name.ends_with("COUNT") &&
+ decl.elements.size() >= 2)
+ {
+ // Skip the last *_COUNT element if instructed to use heuristics
+ maxVal = decl.elements[decl.elements.size() - 2].value;
+ }
+
+ CodegenOutputThing lookupFunction;
+ APPEND_SPRINTF(lookupFunction.text, "std::string_view Stringify%s(%s value) {\n", decl.name.c_str(), decl.name.c_str());
+ APPEND_SPRINTF(lookupFunction.text, " if (value < 0 || value >= %d) return {};\n", maxVal);
+ APPEND_SPRINTF(lookupFunction.text, " return %s[value - %d];\n", arrayName.c_str(), minVal);
+ lookupFunction.text += "}\n";
+
+ out.AddOutputThing(std::move(lookupFunction));
+ } break;
+
+ case EVP_Bits: {
+ auto arrayName = GenerateEnumStringArray(out, decl, useExcludeHeuristics);
+ } break;
+
+ case EVP_Random: {
+ auto mapName = GenerateEnumStringMap(out, decl, useExcludeHeuristics);
+ } break;
+
+ case EVP_COUNT: break;
+ }
+ }
}
void HandleInputFile(AppState& state, std::string_view source) {
auto tokens = RecordTokens(source);
- size_t tokenIdx = 0;
+ size_t idx = 0;
#if CODEGEN_DEBUG_PRINT
printf("BEGIN tokens\n");
@@ -247,12 +326,12 @@ void HandleInputFile(AppState& state, std::string_view source) {
printf("END tokens\n");
#endif
- CodegenInput input;
- CodegenOutput output;
+ CodegenInput fileInput;
+ CodegenOutput fileOutput;
int bracePairDepth = 0;
- while (tokenIdx < tokens.size()) {
- auto& token = tokens[tokenIdx];
+ while (idx < tokens.size()) {
+ auto& token = tokens[idx];
bool incrementTokenIdx = true;
@@ -265,25 +344,77 @@ void HandleInputFile(AppState& state, std::string_view source) {
if (iter != map.end()) {
keyword = iter->second;
} else {
- break;
+ keyword = CKw_COUNT; // Skip keyword section
}
}
switch (keyword) {
case CKw_Struct:
case CKw_Class: {
- auto& idenTok = tokens[tokenIdx + 1]; // TODO handle end of list
+ auto& idenTok = tokens[idx + 1]; // TODO handle end of list
DEBUG_PRINTF("[DEBUG] found struct named %s\n", idenTok.text.c_str());
- } break;
+ goto endIdenCase;
+ }
case CKw_Enum: {
- StbLexerToken* idenTok = &token + 1; // TODO handle end of list
- if (idenTok->text == "class") {
- idenTok += 1;
- DEBUG_PRINTF("[DEBUG] found enum class named %s\n", idenTok->text.c_str());
+ // Consume the "enum" keyword
+ ++idx;
+ incrementTokenIdx = false;
+
+ DeclEnum enumDecl;
+ enumDecl.underlyingType = EUT_Int32; // TODO
+
+ if (tokens[idx].text == "class") {
+ // Consume the "class" keyword
+ ++idx;
+ DEBUG_PRINTF("[DEBUG] found enum class named %s\n", tokens[idx].text.c_str());
} else {
- DEBUG_PRINTF("[DEBUG] found enum named %s\n", idenTok->text.c_str());
+ DEBUG_PRINTF("[DEBUG] found enum named %s\n", tokens[idx].text.c_str());
+ }
+
+ // Consume the enum name identifier
+ enumDecl.name = tokens[idx].text;
+ ++idx;
+
+ int enumClosingBraceCount = 0;
+ int enumBraceDepth = 0;
+ while (enumClosingBraceCount == 0 && idx < tokens.size()) {
+ auto& token = tokens[idx];
+ switch (token.type) {
+ case CLEX_id: {
+ auto& vec = enumDecl.elements;
+ // Set to the previous enum element's value + 1, or starting from 0 if this is the first
+ // Also overridden in the CLEX_intlit branch
+ auto value = vec.empty() ? 0 : vec.back().value + 1;
+ vec.push_back(DeclEnumElement{
+ .name = token.text,
+ .value = value,
+ });
+ } break;
+
+ case CLEX_intlit: {
+
+ } break;
+
+ case CLEX_ext_single_char: {
+ switch (token.text[0]) {
+ case '{': {
+ ++enumBraceDepth;
+ } break;
+
+ case '}': {
+ --enumBraceDepth;
+ ++enumClosingBraceCount;
+ } break;
+ }
+ } break;
+ }
+
+ ++idx;
}
- } break;
+
+ fileInput.AddEnum(std::move(enumDecl));
+ goto endIdenCase;
+ }
case CKw_COUNT: break;
}
@@ -295,24 +426,33 @@ void HandleInputFile(AppState& state, std::string_view source) {
if (iter != map.end()) {
directive = iter->second;
} else {
- break;
+ directive = CD_COUNT; // Skip directive section
}
}
switch (directive) {
case CD_ClassInfo: {
// TODO
- } break;
+ goto endIdenCase;
+ }
case CD_EnumInfo: {
+ // Consume the directive
+ ++idx;
+ incrementTokenIdx = false;
+
auto& optionsStrMap = BSTR_LUT_S2V(EnumMetaGenOptions);
- auto [argList, newIdx] = PeekDirectiveArgumentList(tokens, tokenIdx);
+ auto [argList, newIdx] = PeekDirectiveArgumentList(tokens, idx);
if (argList.size() < 1) {
printf("[ERROR] invalid syntax for BRUSSEL_ENUM\n");
- break;
+ break; // TODO handle this error case gracefully (advance to semicolon?)
}
auto& enumName = argList[0][0]->text;
- auto enumDecl = input.FindEnumByName(enumName);
+ auto enumDecl = fileInput.FindEnumByName(enumName);
+ if (!enumDecl) {
+ printf("[ERROR] BRUSSEL_ENUM: referring to non-existent enum '%s'\n", enumName.c_str());
+ break;
+ }
auto& directiveOptions = argList[1];
EnumFlags<EnumMetaGenOptions> options;
@@ -321,19 +461,23 @@ void HandleInputFile(AppState& state, std::string_view source) {
if (iter != optionsStrMap.end()) {
options |= iter->second;
} else {
- printf("[ERROR] invalid option '%s' for BRUSSEL_ENUM", optionTok->text.c_str());
+ printf("[ERROR] BRUSSEL_ENUM: invalid option '%s'\n", optionTok->text.c_str());
}
}
- GenerateForEnum(output, *enumDecl, options);
+ GenerateForEnum(fileOutput, *enumDecl, options);
- tokenIdx = newIdx;
+ idx = newIdx;
incrementTokenIdx = false;
- } break;
+ goto endIdenCase;
+ }
case CD_COUNT: break;
}
- } break;
+
+ endIdenCase:
+ break;
+ }
case '{': {
bracePairDepth++;
@@ -347,13 +491,15 @@ void HandleInputFile(AppState& state, std::string_view source) {
}
if (incrementTokenIdx) {
- ++tokenIdx;
+ ++idx;
}
}
if (bracePairDepth != 0) {
printf("[WARNING] unbalanced brace at end of file.");
}
+
+ state.mainOutput.MergeContents(std::move(fileOutput));
}
std::string ReadFileAtOnce(const fs::path& path) {
@@ -436,12 +582,12 @@ int main(int argc, char* argv[]) {
if (argc < 2) {
// NOTE: keep in sync with various enum options and parser code
printf(&R"""(
-USAGE: codegen.exe <output path> [<opcode>:<input path>]...
-where <output path>: the _file_ to write generated contents to
- <opcode> is one of:
- "single" process this <input path> file only
- "rec" starting at the given directory <input path>, recursively process all .h .c .hpp .cpp files
-)"""[1]);
+ USAGE: codegen.exe <output path> [<opcode>:<input path>]...
+ where <output path>: the _file_ to write generated contents to
+ <opcode> is one of:
+ "single" process this <input path> file only
+ "rec" starting at the given directory <input path>, recursively process all .h .c .hpp .cpp files
+ )"""[1]);
return -1;
}