Add _Generic

This commit is contained in:
Rui Ueyama 2020-07-24 16:18:03 +09:00
parent 1433b404d6
commit 1faab48ecf
2 changed files with 59 additions and 0 deletions

47
parse.c
View File

@ -2605,12 +2605,56 @@ static Node *funcall(Token **rest, Token *tok, Node *fn) {
return node;
}
// generic-selection = "(" assign "," generic-assoc ("," generic-assoc)* ")"
//
// generic-assoc = type-name ":" assign
// | "default" ":" assign
static Node *generic_selection(Token **rest, Token *tok) {
Token *start = tok;
tok = skip(tok, "(");
Node *ctrl = assign(&tok, tok);
add_type(ctrl);
Type *t1 = ctrl->ty;
if (t1->kind == TY_FUNC)
t1 = pointer_to(t1);
else if (t1->kind == TY_ARRAY)
t1 = pointer_to(t1->base);
Node *ret = NULL;
while (!consume(rest, tok, ")")) {
tok = skip(tok, ",");
if (equal(tok, "default")) {
tok = skip(tok->next, ":");
Node *node = assign(&tok, tok);
if (!ret)
ret = node;
continue;
}
Type *t2 = typename(&tok, tok);
tok = skip(tok, ":");
Node *node = assign(&tok, tok);
if (is_compatible(t1, t2))
ret = node;
}
if (!ret)
error_tok(start, "controlling expression type not compatible with"
" any generic association type");
return ret;
}
// primary = "(" "{" stmt+ "}" ")"
// | "(" expr ")"
// | "sizeof" "(" type-name ")"
// | "sizeof" unary
// | "_Alignof" "(" type-name ")"
// | "_Alignof" unary
// | "_Generic" generic-selection
// | "__builtin_types_compatible_p" "(" type-name, type-name, ")"
// | "__builtin_reg_class" "(" type-name ")"
// | ident
@ -2657,6 +2701,9 @@ static Node *primary(Token **rest, Token *tok) {
return new_ulong(node->ty->align, tok);
}
if (equal(tok, "_Generic"))
return generic_selection(rest, tok->next);
if (equal(tok, "__builtin_types_compatible_p")) {
tok = skip(tok->next, "(");
Type *t1 = typename(&tok, tok);

12
test/generic.c Normal file
View File

@ -0,0 +1,12 @@
#include "test.h"
int main() {
ASSERT(1, _Generic(100.0, double: 1, int *: 2, int: 3, float: 4));
ASSERT(2, _Generic((int *)0, double: 1, int *: 2, int: 3, float: 4));
ASSERT(2, _Generic((int[3]){}, double: 1, int *: 2, int: 3, float: 4));
ASSERT(3, _Generic(100, double: 1, int *: 2, int: 3, float: 4));
ASSERT(4, _Generic(100f, double: 1, int *: 2, int: 3, float: 4));
printf("OK\n");
return 0;
}