larmel / lacc

A simple, self-hosting C compiler
MIT License
872 stars 64 forks source link

support GNU extension of ##__VA_ARGS__ #20

Closed notwa closed 4 years ago

notwa commented 5 years ago

gcc's documentation specifies that a comma, a paste token, and the identifier __VA_ARGS__ in that order within a macro definition invokes a special behavior where the comma will be eaten if __VA_ARGS__ is empty.

I tried my hand at implementing this myself, but I figured you would have a better idea on how to go about this so I didn't make a pull request.

here is a silly example program. the tuple implementation is inspired by libCello.

/* Expected output to stderr:
hey
hey you
whoa!
whoa: whoa! whoa!
()
(1)
(1, 2, 3)
*/

#include <stdio.h>
#include <limits.h>

#define lament(msg, ...) fprintf(stderr, msg, ##__VA_ARGS__)
#define whoa(msg, ...) fprintf(stderr, msg, ##__VA_ARGS__, ##__VA_ARGS__)

#define TUPLE_END INT_MIN
#define tuple(...) tuple_im(_, ##__VA_ARGS__, TUPLE_END)
#define tuple_im(_, ...) (int[]){__VA_ARGS__}

void print_tuple(int *tuple)
{
    lament("(");
    for (; *tuple != TUPLE_END; tuple++) {
        lament("%i", *tuple);
        if (tuple[1] != TUPLE_END) {
            lament(", ");
        }
    }
    lament(")\n");
}

int main(int argc, char **argv)
{
    (void) argc;
    (void) argv;
    lament("hey\n");
    lament("hey %s\n", "you");
    whoa("whoa!\n");
    whoa("whoa: %s %s\n", "whoa!");
    print_tuple(tuple());
    print_tuple(tuple(1));
    print_tuple(tuple(1, 2, 3));
    return 0;
}
larmel commented 4 years ago

Thank you for suggesting this, and with such a clear explanation. I implemented it now with this commit, which passes your test case.

notwa commented 4 years ago

thanks! I didn't realize how much I used this feature, particularly with lament (or eprintf as others call it) until I began trying out other compilers, so it's very appreciated.