aboutsummaryrefslogtreecommitdiff
path: root/expr.c
diff options
context:
space:
mode:
Diffstat (limited to 'expr.c')
-rw-r--r--expr.c49
1 files changed, 48 insertions, 1 deletions
diff --git a/expr.c b/expr.c
index 0526b93..46d0fcd 100644
--- a/expr.c
+++ b/expr.c
@@ -322,6 +322,52 @@ unescape(char **p)
return c;
}
+static struct expr *
+generic(struct scope *s)
+{
+ struct expr *e, *match = NULL, *def = NULL;
+ struct type *t, *want;
+ enum typequal qual;
+
+ next();
+ expect(TLPAREN, "after '_Generic'");
+ e = assignexpr(s);
+ expect(TCOMMA, "after generic selector expression");
+ want = e->type;
+ delexpr(e);
+ do {
+ if (consume(TDEFAULT)) {
+ if (def)
+ error(&tok.loc, "multiple default expressions in generic association list");
+ expect(TCOLON, "after 'default'");
+ def = assignexpr(s);
+ } else {
+ qual = QUALNONE;
+ t = typename(s, &qual);
+ if (!t)
+ error(&tok.loc, "expected typename for generic association");
+ expect(TCOLON, "after type name");
+ e = assignexpr(s);
+ if (typecompatible(t, want) && qual == QUALNONE) {
+ if (match)
+ error(&tok.loc, "generic selector matches multiple associations");
+ match = e;
+ } else {
+ delexpr(e);
+ }
+ }
+ } while (consume(TCOMMA));
+ expect(TRPAREN, "after generic assocation list");
+ if (!match) {
+ if (!def)
+ error(&tok.loc, "generic selector matches no associations and no default was specified");
+ match = def;
+ } else if (def) {
+ delexpr(def);
+ }
+ return match;
+}
+
/* 6.5 Expressions */
static struct expr *
primaryexpr(struct scope *s)
@@ -407,7 +453,8 @@ primaryexpr(struct scope *s)
expect(TRPAREN, "after expression");
break;
case T_GENERIC:
- error(&tok.loc, "generic selection is not yet supported");
+ e = generic(s);
+ break;
default:
error(&tok.loc, "expected primary expression");
}