patterncMinor
Using case and switch macros for strings
Viewed 0 times
casemacrosusingforandswitchstrings
Problem
I'd like this reviewed.
#include
#include
#include
#define SWITCH(S) char *_S = S; if (0)
#define CASE(S) } else if (strcmp(_S, S) == 0) {switch(1) { case 1
#define BREAK }
#define DEFAULT } else {switch(1) { case 1
int main()
{
char buf[256];
printf("\nString - Enter your string: ");
scanf ("%s", buf);
SWITCH (buf) {
CASE ("abcdef"):
printf ("B1!\n");
BREAK;
CASE ("ghijkl"):
printf ("C1!\n");
BREAK;
DEFAULT:
printf ("D1!\n");
BREAK;
}
}Solution
switch is usually assumed to have nearly O(1). I'm suggesting to introduce additional level for parsing. It is known as lexical analysis. You parse you fixed set of cases to enum values and then switch as you want.enum { B1, C1, D1 } token_t;
token_t lexer(const char *s)
{
// TODO: consider hash table here
static struct entry_s {
const char *key;
token_t token;
} token_table[] = {
{ "abcdef", B1 },
{ "ghijkl", C1 },
{ NULL, D1 },
};
struct entry_s *p = token_table;
for(; p->key != NULL && strcmp(p->key, s) != 0; ++p);
return p->token;
}
int main()
{
char buf[256];
printf("\nString - Enter your string: ");
scanf ("%s", buf);
switch(lexer(buf)) {
case B1:
printf ("B1!\n");
break;
case C1:
printf ("C1!\n");
break;
case D1:
printf ("D1!\n");
break;
}
}Note that your
SWITCH(S) will work only in C++ since C doesn't allow variables definition in the middle of blocks. Usually such macro uses something like:#define BEGIN_SEPARATION(S, T) { const char *_tail = (T), *_sep = (S); \
size_t _sep_len = strlen(_token); \
for(const char *_next = strstr(_tail); _tail != NULL; _tail = (_next != NULL) ? _next + _sep_len : NULL) {
#define SEPARATION_TOKEN() (_next == NULL ? strdup(_tail) : strndup(_tail, _next - _tail))
#define END_SEPARATION } }And as far as I know it's common practice to wrap macro arguments (i.e
_S = (S);).Code Snippets
enum { B1, C1, D1 } token_t;
token_t lexer(const char *s)
{
// TODO: consider hash table here
static struct entry_s {
const char *key;
token_t token;
} token_table[] = {
{ "abcdef", B1 },
{ "ghijkl", C1 },
{ NULL, D1 },
};
struct entry_s *p = token_table;
for(; p->key != NULL && strcmp(p->key, s) != 0; ++p);
return p->token;
}
int main()
{
char buf[256];
printf("\nString - Enter your string: ");
scanf ("%s", buf);
switch(lexer(buf)) {
case B1:
printf ("B1!\n");
break;
case C1:
printf ("C1!\n");
break;
case D1:
printf ("D1!\n");
break;
}
}#define BEGIN_SEPARATION(S, T) { const char *_tail = (T), *_sep = (S); \
size_t _sep_len = strlen(_token); \
for(const char *_next = strstr(_tail); _tail != NULL; _tail = (_next != NULL) ? _next + _sep_len : NULL) {
#define SEPARATION_TOKEN() (_next == NULL ? strdup(_tail) : strndup(_tail, _next - _tail))
#define END_SEPARATION } }Context
StackExchange Code Review Q#20314, answer score: 7
Revisions (0)
No revisions yet.