HiveBrain v1.2.0
Get Started
← Back to all entries
patterncMinor

Using case and switch macros for strings

Submitted by: @import:stackexchange-codereview··
0
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.