Creating a new TableGen tool – The TableGen Language-3
- Next, the function declarations are emitted. This is only a constant string, so nothing exciting happens. This finishes emitting the declarations: OS << ” const char *getTokenName(TokenKind Kind) “
“LLVM_READNONE;\n”
<< ” const char *getPunctuatorSpelling(TokenKind “
“Kind) LLVM_READNONE;\n”
<< ” const char *getKeywordSpelling(TokenKind “
“Kind) “
“LLVM_READNONE;\n”
<< “}\n”
<< “endif\n”; - Now, let’s turn to emitting the definitions. Again, this generated code is guarded by a macro called GET_TOKEN_KIND_DEFINITION. First, the token names are emitted into a TokNames array, and the getTokenName() function uses that array to retrieve the name. Please note that the quote symbol must be escaped as \” when used inside a string: OS << “ifdef GET_TOKEN_KIND_DEFINITION\n”; OS << “undef GET_TOKEN_KIND_DEFINITION\n”; OS << “static const char * const TokNames[] = {\n”; for (Record *CC : Records.getAllDerivedDefinitions(“Token”)) { OS << ” \”” << CC->getValueAsString(“Name”)
<< “\”,\n”;
}
OS << “};\n\n”;
OS << “const char *tok::getTokenName(TokenKind Kind) “
“{\n”
<< ” if (Kind <= tok::NUM_TOKENS)\n”
<< ” return TokNames[Kind];\n”
<< ” llvm_unreachable(\”unknown TokenKind\”);\n”
<< ” return nullptr;\n”
<< “};\n\n”; - Next, the getPunctuatorSpelling() function is emitted. The only notable difference to the other parts is that the loop goes over all records derived from the Punctuator class. Also, a switch statement is generated instead of an array: OS << “const char ” “*tok::getPunctuatorSpelling(TokenKind ” “Kind) {\n” << ” switch (Kind) {\n”; for (Record *CC : Records.getAllDerivedDefinitions(“Punctuator”)) { OS << ” ” << CC->getValueAsString(“Name”)
<< “: return \”” << CC->getValueAsString(“Spelling”) << “\”;\n”;
}
OS << ” default: break;\n”
<< ” }\n”
<< ” return nullptr;\n”
<< “};\n\n”; - And finally, the getKeywordSpelling() function is emitted. The coding is similar to emitting getPunctuatorSpelling(). This time, the loop goes over all records of the Keyword class, and the name is again prefixed with kw_: OS << “const char *tok::getKeywordSpelling(TokenKind ” “Kind) {\n” << ” switch (Kind) {\n”; for (Record *CC : Records.getAllDerivedDefinitions(“Keyword”)) { OS << ” kw_” << CC->getValueAsString(“Name”)
<< “: return \”” << CC->getValueAsString(“Name”)
<< “\”;\n”;
}
OS << ” default: break;\n”
<< ” }\n”
<< ” return nullptr;\n”
<< «};\n\n»;
OS << «endif\n»;
} - The emitKeywordFilter() method is more complex than the previous methods since emitting the filter requires collecting some data from the records. The generated source code uses the std::lower_bound() function, thus implementing a binary search.
Now, let’s make a shortcut. There can be several records of the TokenFilter class defined in the TableGen file. For demonstration purposes, just emit at most one token filter method: std::vector AllTokenFilter =
Records.getAllDerivedDefinitionsIfDefined(
“TokenFilter”);
if (AllTokenFilter.empty())
return;
Leave a Reply