Creating a new TableGen tool – The TableGen Language-2
- The run() method calls all the emitting methods. It also times the length of each phase. You specify the –time-phases option, and then the timing is shown after all code is generated:
void TokenAndKeywordFilterEmitter::run(raw_ostream &OS) {
// Emit Flag fragments.
Records.startTimer(“Emit flags”);
emitFlagsFragment(OS);
// Emit token kind enum and functions.
Records.startTimer(“Emit token kind”);
emitTokenKind(OS);
// Emit keyword filter code.
Records.startTimer(“Emit keyword filter”);
emitKeywordFilter(OS);
Records.stopTimer();
}
- The emitFlagsFragment() method shows the typical structure of a function emitting C++ source code. The generated code is guarded by the GET_TOKEN_FLAGS macro. To emit the C++ source fragment, you loop over all records that are derived from the Flag class in the TableGen file. Having such a record, it is easy to query the record for the name and the value. Please note that the names Flag, Name, and Val must be written exactly as in the TableGen file. If you rename Val to Value in the TableGen file, then you also need to change the string in this function. All the generated source code is written to the provided stream, OS:
void TokenAndKeywordFilterEmitter::emitFlagsFragment(
raw_ostream &OS) {
OS << “ifdef GET_TOKEN_FLAGS\n”; OS << “undef GET_TOKEN_FLAGS\n”; for (Record *CC : Records.getAllDerivedDefinitions(“Flag”)) { StringRef Name = CC->getValueAsString(“Name”);
int64_t Val = CC->getValueAsInt(“Val”);
OS << Name << ” = ” << format_hex(Val, 2) << “,\n”;
}
OS << “endif\n”;
}
- The emitTokenKind() method emits a declaration and definition of token classification functions. Let’s have a look at emitting the declarations first. The overall structure is the same as the previous method – only more C++ source code is emitted. The generated source fragment is guarded by the GET_TOKEN_KIND_DECLARATION macro. Please note that this method tries to generate nicely formatted C++ code, using new lines and indentation as a human developer would do. In case the emitted source code is not correct, and you need to examine it to find the error, this will be tremendously helpful. It is also easy to make such errors: after all, you are writing a C++ function that emits C++ source code.
First, the TokenKind enumeration is emitted. The name for a keyword should be prefixed with a kw_ string. The loop goes over all records of the Token class, and you can query the records if they are also a subclass of the Keyword class, which enables you to emit the prefix: OS << “ifdef GET_TOKEN_KIND_DECLARATION\n” << “undef GET_TOKEN_KIND_DECLARATION\n” << “namespace tok {\n” << ” enum TokenKind : unsigned short {\n”; for (Record *CC : Records.getAllDerivedDefinitions(“Token”)) { StringRef Name = CC->getValueAsString(“Name”);
OS << ” “; if (CC->isSubClassOf(“Keyword”))
OS << “kw_”;
OS << Name << “,\n”;
}
OS << „ NUM_TOKENS\n”
<< „ };\n”;