aboutsummaryrefslogtreecommitdiff
path: root/expr.c
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2019-02-22 13:46:07 -0800
committerMichael Forney <mforney@mforney.org>2019-02-22 13:50:49 -0800
commita056c878d1df67ff12e506d48653c48e9a1b001d (patch)
tree2b7d02df3e295155e94b1404fcad22ad10f2c569 /expr.c
parent430c38701375d7c3a8176218a8536fd83b52a446 (diff)
Separate out built-in handling from postfixexpr
Diffstat (limited to 'expr.c')
-rw-r--r--expr.c119
1 files changed, 65 insertions, 54 deletions
diff --git a/expr.c b/expr.c
index 8e8a7ca..8058523 100644
--- a/expr.c
+++ b/expr.c
@@ -398,13 +398,76 @@ primaryexpr(struct scope *s)
}
static struct expression *
+builtinfunc(struct scope *s, enum builtinkind kind)
+{
+ struct expression *e;
+ struct type *t;
+ char *name;
+ uint64_t offset;
+
+ switch (kind) {
+ case BUILTINVASTART:
+ e = mkexpr(EXPRBUILTIN, &typevoid, 0);
+ e->builtin.kind = BUILTINVASTART;
+ e->builtin.arg = exprconvert(assignexpr(s), &typevalistptr);
+ expect(TCOMMA, "after va_list");
+ free(expect(TIDENT, "after ','"));
+ // XXX: check that this was actually a parameter name?
+ break;
+ case BUILTINVAARG:
+ e = mkexpr(EXPRBUILTIN, NULL, 0);
+ e->builtin.kind = BUILTINVAARG;
+ e->builtin.arg = exprconvert(assignexpr(s), &typevalistptr);
+ expect(TCOMMA, "after va_list");
+ e->type = typename(s);
+ break;
+ case BUILTINVACOPY:
+ e = mkexpr(EXPRASSIGN, typevalist.base, 0);
+ e->assign.l = mkunaryexpr(TMUL, exprconvert(assignexpr(s), &typevalistptr));
+ expect(TCOMMA, "after target va_list");
+ e->assign.r = mkunaryexpr(TMUL, exprconvert(assignexpr(s), &typevalistptr));
+ e = exprconvert(e, &typevoid);
+ break;
+ case BUILTINVAEND:
+ e = mkexpr(EXPRBUILTIN, &typevoid, 0);
+ e->builtin.kind = BUILTINVAEND;
+ exprconvert(assignexpr(s), &typevalistptr);
+ break;
+ case BUILTINOFFSETOF:
+ t = typename(s);
+ expect(TCOMMA, "after type name");
+ name = expect(TIDENT, "after ','");
+ if (t->kind != TYPESTRUCT && t->kind != TYPEUNION)
+ error(&tok.loc, "type is not a struct/union type");
+ offset = 0;
+ if (!typemember(t, name, &offset))
+ error(&tok.loc, "struct/union has no member named '%s'", name);
+ e = mkconstexpr(&typeulong, offset);
+ free(name);
+ break;
+ case BUILTINALLOCA:
+ e = mkexpr(EXPRBUILTIN, mkpointertype(&typevoid), 0);
+ e->builtin.kind = BUILTINALLOCA;
+ e->builtin.arg = exprconvert(assignexpr(s), &typeulong);
+ break;
+ case BUILTININFF:
+ e = mkexpr(EXPRCONST, &typefloat, 0);
+ /* TODO: use INFINITY here when we can handle musl's math.h */
+ e->constant.f = strtod("inf", NULL);
+ break;
+ default:
+ fatal("internal error; unknown builtin");
+ }
+ return e;
+}
+
+static struct expression *
postfixexpr(struct scope *s, struct expression *r)
{
struct expression *e, *arr, *idx, *tmp, **end;
struct type *t;
enum typequalifier tq;
struct parameter *p;
- char *name;
uint64_t offset;
enum tokenkind op;
bool lvalue;
@@ -436,59 +499,7 @@ postfixexpr(struct scope *s, struct expression *r)
case TLPAREN: /* function call */
next();
if (r->kind == EXPRIDENT && r->ident.decl->kind == DECLBUILTIN) {
- switch (r->ident.decl->builtin) {
- case BUILTINVASTART:
- e = mkexpr(EXPRBUILTIN, &typevoid, 0);
- e->builtin.kind = BUILTINVASTART;
- e->builtin.arg = exprconvert(assignexpr(s), &typevalistptr);
- expect(TCOMMA, "after va_list");
- free(expect(TIDENT, "after ','"));
- // XXX: check that this was actually a parameter name?
- break;
- case BUILTINVAARG:
- e = mkexpr(EXPRBUILTIN, NULL, 0);
- e->builtin.kind = BUILTINVAARG;
- e->builtin.arg = exprconvert(assignexpr(s), &typevalistptr);
- expect(TCOMMA, "after va_list");
- e->type = typename(s);
- break;
- case BUILTINVACOPY:
- e = mkexpr(EXPRASSIGN, typevalist.base, 0);
- e->assign.l = mkunaryexpr(TMUL, exprconvert(assignexpr(s), &typevalistptr));
- expect(TCOMMA, "after target va_list");
- e->assign.r = mkunaryexpr(TMUL, exprconvert(assignexpr(s), &typevalistptr));
- e = exprconvert(e, &typevoid);
- break;
- case BUILTINVAEND:
- e = mkexpr(EXPRBUILTIN, &typevoid, 0);
- e->builtin.kind = BUILTINVAEND;
- exprconvert(assignexpr(s), &typevalistptr);
- break;
- case BUILTINOFFSETOF:
- t = typename(s);
- expect(TCOMMA, "after type name");
- name = expect(TIDENT, "after ','");
- if (t->kind != TYPESTRUCT && t->kind != TYPEUNION)
- error(&tok.loc, "type is not a struct/union type");
- offset = 0;
- if (!typemember(t, name, &offset))
- error(&tok.loc, "struct/union has no member named '%s'", name);
- e = mkconstexpr(&typeulong, offset);
- free(name);
- break;
- case BUILTINALLOCA:
- e = mkexpr(EXPRBUILTIN, mkpointertype(&typevoid), 0);
- e->builtin.kind = BUILTINALLOCA;
- e->builtin.arg = exprconvert(assignexpr(s), &typeulong);
- break;
- case BUILTININFF:
- e = mkexpr(EXPRCONST, &typefloat, 0);
- /* TODO: use INFINITY here when we can handle musl's math.h */
- e->constant.f = strtod("inf", NULL);
- break;
- default:
- fatal("internal error; unknown builtin");
- }
+ e = builtinfunc(s, r->ident.decl->builtin);
expect(TRPAREN, "after builtin parameters");
break;
}