Compile-time regex matcher using constexpr

12:10:00 PM 0 Comments A+ a-

With my growing constexpr fascination, I thought of using it for something that would be really hard using template meta-programs. How about implementing a compile-time regular expression matcher? Fortunately, a simple regular expression matcher has already been written by Rob Pike. I just rewrote it using constexpr: single return statement in functions, no modifications to the parameters, abundant ternery operators, and recursion. Here we go...

constexpr int match_c(const char *regexp, const char *text);
constexpr int matchhere_c(const char *regexp, const char *text);
constexpr int matchstar_c(int c, const char *regexp, const char *text);
constexpr int matchend_c(const char * regexp, const char * text);

constexpr int matchend_c(const char * regexp, const char * text)
{
  return matchhere_c(regexp, text) ? 1 : 
         (*text == '\0') ? 0 : matchend_c(regexp, text+1);
}

constexpr int match_c(const char *regexp, const char *text)
{
  return (regexp[0] == '^') ? matchhere_c(regexp+1, text) : 
                              matchend_c(regexp, text);
}

/* matchhere: search for regexp at beginning of text */
constexpr int matchhere_c(const char *regexp, const char *text)
{
  return (regexp[0] == '\0') ? 1 : 
         (regexp[1] == '*') ? matchstar_c(regexp[0], regexp+2, text) :
         (regexp[0] == '$' && regexp[1] == '\0') ? (*text == '\0') :
         (*text!='\0' && (regexp[0]=='.' || regexp[0]==*text)) ? 
          matchhere_c(regexp+1, text+1) : 0;
}

/* matchstar: search for c*regexp at beginning of text */
constexpr int matchstar_c(int c, const char * regexp, const char *text)
{
  return matchhere_c(regexp, text) ? 1 : 
         (*text != '\0' && (*text == c || c == '.')) ? 
           matchstar_c(c, regexp, text+1) : 0;
}

#define TO_STR_IMPL(R) #R
#define TO_STR(R) TO_STR_IMPL(R)

int main(void)
{
  static_assert(match_c(TO_STR(REGEX), TO_STR(TEXT)), "...");

  return 0;
}


To compile it, as of today, you need g++ 4.6 or better. You've to pass REGEX and TEXT as #defines while compilation. For instance, -D REGEX=o$ -D TEXT=Foo It matches!

I used two macros TO_STR and To_STR_IMPL to convert the REGEX and TEXT into string literals. #R is basically using the preprocessor stringification technique. For some reason I need two separate TO_STR macros for TEXT substitution and stringification. Seems like the gcc preprocessor can't do those two things in a single macro.

Have fun!