mirror of https://github.com/rui314/chibicc
Add _Generic
This commit is contained in:
parent
1433b404d6
commit
1faab48ecf
47
parse.c
47
parse.c
|
@ -2605,12 +2605,56 @@ static Node *funcall(Token **rest, Token *tok, Node *fn) {
|
||||||
return node;
|
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+ "}" ")"
|
// primary = "(" "{" stmt+ "}" ")"
|
||||||
// | "(" expr ")"
|
// | "(" expr ")"
|
||||||
// | "sizeof" "(" type-name ")"
|
// | "sizeof" "(" type-name ")"
|
||||||
// | "sizeof" unary
|
// | "sizeof" unary
|
||||||
// | "_Alignof" "(" type-name ")"
|
// | "_Alignof" "(" type-name ")"
|
||||||
// | "_Alignof" unary
|
// | "_Alignof" unary
|
||||||
|
// | "_Generic" generic-selection
|
||||||
// | "__builtin_types_compatible_p" "(" type-name, type-name, ")"
|
// | "__builtin_types_compatible_p" "(" type-name, type-name, ")"
|
||||||
// | "__builtin_reg_class" "(" type-name ")"
|
// | "__builtin_reg_class" "(" type-name ")"
|
||||||
// | ident
|
// | ident
|
||||||
|
@ -2657,6 +2701,9 @@ static Node *primary(Token **rest, Token *tok) {
|
||||||
return new_ulong(node->ty->align, 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")) {
|
if (equal(tok, "__builtin_types_compatible_p")) {
|
||||||
tok = skip(tok->next, "(");
|
tok = skip(tok->next, "(");
|
||||||
Type *t1 = typename(&tok, tok);
|
Type *t1 = typename(&tok, tok);
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
Loading…
Reference in New Issue