Skip to content

[NFC][TableGen] Refactor preprocessor directive handling #102967

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 13, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 43 additions & 54 deletions llvm/lib/TableGen/TGLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,18 @@ using namespace llvm;
namespace {
// A list of supported preprocessing directives with their
// internal token kinds and names.
struct {
struct PreprocessorDir {
tgtok::TokKind Kind;
const char *Word;
} PreprocessorDirs[] = {
{ tgtok::Ifdef, "ifdef" },
{ tgtok::Ifndef, "ifndef" },
{ tgtok::Else, "else" },
{ tgtok::Endif, "endif" },
{ tgtok::Define, "define" }
StringRef Word;
};
} // end anonymous namespace

constexpr PreprocessorDir PreprocessorDirs[] = {{tgtok::Ifdef, "ifdef"},
{tgtok::Ifndef, "ifndef"},
{tgtok::Else, "else"},
{tgtok::Endif, "endif"},
{tgtok::Define, "define"}};

TGLexer::TGLexer(SourceMgr &SM, ArrayRef<std::string> Macros) : SrcMgr(SM) {
CurBuffer = SrcMgr.getMainFileID();
CurBuf = SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer();
Expand Down Expand Up @@ -641,54 +641,43 @@ bool TGLexer::prepExitInclude(bool IncludeStackMustBeEmpty) {
}

tgtok::TokKind TGLexer::prepIsDirective() const {
for (const auto &PD : PreprocessorDirs) {
int NextChar = *CurPtr;
bool Match = true;
unsigned I = 0;
for (; I < strlen(PD.Word); ++I) {
if (NextChar != PD.Word[I]) {
Match = false;
break;
}

NextChar = peekNextChar(I + 1);
}
for (const auto [Kind, Word] : PreprocessorDirs) {
if (StringRef(CurPtr, Word.size()) != Word)
continue;
char NextChar = peekNextChar(Word.size());

// Check for whitespace after the directive. If there is no whitespace,
// Check for whitespace after the directive. If there is no whitespace,
// then we do not recognize it as a preprocessing directive.
if (Match) {
tgtok::TokKind Kind = PD.Kind;

// New line and EOF may follow only #else/#endif. It will be reported
// as an error for #ifdef/#define after the call to prepLexMacroName().
if (NextChar == ' ' || NextChar == '\t' || NextChar == EOF ||
NextChar == '\n' ||
// It looks like TableGen does not support '\r' as the actual
// carriage return, e.g. getNextChar() treats a single '\r'
// as '\n'. So we do the same here.
NextChar == '\r')
return Kind;

// Allow comments after some directives, e.g.:
// #else// OR #else/**/
// #endif// OR #endif/**/
//
// Note that we do allow comments after #ifdef/#define here, e.g.
// #ifdef/**/ AND #ifdef//
// #define/**/ AND #define//
//
// These cases will be reported as incorrect after calling
// prepLexMacroName(). We could have supported C-style comments
// after #ifdef/#define, but this would complicate the code
// for little benefit.
if (NextChar == '/') {
NextChar = peekNextChar(I + 1);
// New line and EOF may follow only #else/#endif. It will be reported
// as an error for #ifdef/#define after the call to prepLexMacroName().
if (NextChar == ' ' || NextChar == '\t' || NextChar == EOF ||
NextChar == '\n' ||
// It looks like TableGen does not support '\r' as the actual
// carriage return, e.g. getNextChar() treats a single '\r'
// as '\n'. So we do the same here.
NextChar == '\r')
return Kind;

if (NextChar == '*' || NextChar == '/')
return Kind;
// Allow comments after some directives, e.g.:
// #else// OR #else/**/
// #endif// OR #endif/**/
//
// Note that we do allow comments after #ifdef/#define here, e.g.
// #ifdef/**/ AND #ifdef//
// #define/**/ AND #define//
//
// These cases will be reported as incorrect after calling
// prepLexMacroName(). We could have supported C-style comments
// after #ifdef/#define, but this would complicate the code
// for little benefit.
if (NextChar == '/') {
NextChar = peekNextChar(Word.size() + 1);

if (NextChar == '*' || NextChar == '/')
return Kind;

// Pretend that we do not recognize the directive.
}
// Pretend that we do not recognize the directive.
}
}

Expand All @@ -698,10 +687,10 @@ tgtok::TokKind TGLexer::prepIsDirective() const {
bool TGLexer::prepEatPreprocessorDirective(tgtok::TokKind Kind) {
TokStart = CurPtr;

for (const auto &PD : PreprocessorDirs)
if (PD.Kind == Kind) {
for (const auto [PKind, PWord] : PreprocessorDirs)
if (PKind == Kind) {
// Advance CurPtr to the end of the preprocessing word.
CurPtr += strlen(PD.Word);
CurPtr += PWord.size();
return true;
}

Expand Down
Loading