diff options
author | Quentin Carbonneaux <quentin.carbonneaux@yale.edu> | 2017-02-15 20:17:13 -0500 |
---|---|---|
committer | Quentin Carbonneaux <quentin.carbonneaux@yale.edu> | 2017-02-15 20:17:13 -0500 |
commit | a9d81338b19f21f7220e340a1c50870b40587120 (patch) | |
tree | 509f8ec05d8b8da88b90630031cff5b52b2e5c54 /parse.c | |
parent | 249af91ff9d9ffbd8962efcad999de442e609658 (diff) | |
download | roux-a9d81338b19f21f7220e340a1c50870b40587120.tar.gz |
add support for closure calls
Compiling languages with closures often requires passing an extra environment parameter to the called function. One solution is to use a convention, and reserve, say, the first argument for that purpose. However, that makes binding to C a little less smooth. Alternatively, QBE now provides a way to remain fully ABI compatible with C by having a "hidden" environment argument (marked with the keyword 'env'). Calling a function expecting an environment from C will make the contents of the environment undefined, but the normal arguments will be passed without alteration. Conversely, calling a C function like it is a closure by passing it an environemnt will work smoothly.
Diffstat (limited to 'parse.c')
-rw-r--r-- | parse.c | 24 |
1 files changed, 21 insertions, 3 deletions
diff --git a/parse.c b/parse.c index a61ff1b..b911993 100644 --- a/parse.c +++ b/parse.c @@ -60,9 +60,11 @@ OpDesc opdesc[NOp] = { [Oxcmp] = { "xcmp", 1, {A(w,l,s,d), A(w,l,s,d)}, 1, 0, 0 }, [Oxtest] = { "xtest", 1, {A(w,l,e,e), A(w,l,e,e)}, 1, 0, 0 }, [Oaddr] = { "addr", 0, {A(m,m,e,e), A(x,x,e,e)}, 0, 1, 0 }, - [Opar] = { "parn", 0, {A(x,x,x,x), A(x,x,x,x)}, 0, 0, 0 }, + [Opar] = { "par", 0, {A(x,x,x,x), A(x,x,x,x)}, 0, 0, 0 }, + [Opare] = { "pare", 0, {A(x,x,x,x), A(x,x,x,x)}, 0, 0, 0 }, [Oparc] = { "parc", 0, {A(e,x,e,e), A(e,x,e,e)}, 0, 0, 0 }, [Oarg] = { "arg", 0, {A(w,l,s,d), A(x,x,x,x)}, 0, 0, 0 }, + [Oarge] = { "arge", 0, {A(w,l,s,d), A(x,x,x,x)}, 0, 0, 0 }, [Oargc] = { "argc", 0, {A(e,x,e,e), A(e,l,e,e)}, 0, 0, 0 }, [Ocall] = { "call", 0, {A(m,m,m,m), A(x,x,x,x)}, 0, 0, 0 }, [Ovacall] = { "vacall", 0, {A(m,m,m,m), A(x,x,x,x)}, 0, 0, 0 }, @@ -108,6 +110,7 @@ enum { Talloc2, Tcall, + Tenv, Tphi, Tjmp, Tjnz, @@ -156,6 +159,7 @@ static char *kwmap[Ntok] = { [Talloc1] = "alloc1", [Talloc2] = "alloc2", [Tcall] = "call", + [Tenv] = "env", [Tphi] = "phi", [Tjmp] = "jmp", [Tjnz] = "jnz", @@ -493,17 +497,25 @@ parsecls(int *tyn) static int parserefl(int arg) { - int k, ty; + int k, ty, env, hasenv; Ref r; + hasenv = 0; expect(Tlparen); while (peek() != Trparen && peek() != Tdots) { if (curi - insb >= NIns) err("too many instructions (1)"); + env = peek() == Tenv; + if (env) + next(); k = parsecls(&ty); r = parseref(); if (req(r, R)) - err("invalid reference argument"); + err("invalid argument"); + if (hasenv && env) + err("only one environment allowed"); + if (env && k != Kl) + err("environment must be of type l"); if (!arg && rtype(r) != RTmp) err("invalid function parameter"); if (k == 4) @@ -511,12 +523,18 @@ parserefl(int arg) *curi = (Ins){Oargc, R, {TYPE(ty), r}, Kl}; else *curi = (Ins){Oparc, r, {TYPE(ty)}, Kl}; + else if (env) + if (arg) + *curi = (Ins){Oarge, R, {r}, k}; + else + *curi = (Ins){Opare, r, {R}, k}; else if (arg) *curi = (Ins){Oarg, R, {r}, k}; else *curi = (Ins){Opar, r, {R}, k}; curi++; + hasenv |= env; if (peek() == Trparen) break; expect(Tcomma); |