https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f...
The way I've seen most languages do it is something like this:
switch (c[0]) {
case 'c':
if (strcmp(c, "case") == 0) return CASE;
if (strcmp(c, "continue") == 0) return CONTINUE;
...
case 'f':
if (strcmp(c, "for") == 0) return FOR;
if (strcmp(c, "friend") == 0) return FRIEND;
...
}
I suspect that's good enough if you have a typical keyword list of say 20-100.I just looked at Clang and it appears to build the list at runtime, using a regular hash table. I think this is because it has to handle C, C++, and Objective C, and they have different sets of keywords.
It seems like they could change it to use something like perfect hashing, and if that's even a 1% win, it would be worth it for the extra build complexity, since C and C++ compilation take up so many CPU cycles in the world.
See lib/Basic/IdentifierTable.cpp.
Although another problem is that the list of keywords depends on whether you're compiling C89, C99, C++98, C++11, etc. But that is a finite list so it seems like it still can be done with code generation ahead of time like PostGres does.
In Oil [1] I use re2c [1] recognize keywords, along with the rest of the complex lexing process, and it works well. It builds a DFA expressed in C code. The slower parts are elsewhere :)
EDIT: In theory, the DFA seems better than perfect hashing because you can bail on the second character if you get "xzoo" and no keyword starts with "xz". I think with perfect hashing yo still have to look at every byte.
The switch statement above also avoids looking at every byte in certain cases.
[2] http://re2c.org/