aboutsummaryrefslogtreecommitdiff
path: root/src/compiler/expr.zc
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/expr.zc')
-rw-r--r--src/compiler/expr.zc25
1 files changed, 19 insertions, 6 deletions
diff --git a/src/compiler/expr.zc b/src/compiler/expr.zc
index 4c77ceb..e449508 100644
--- a/src/compiler/expr.zc
+++ b/src/compiler/expr.zc
@@ -647,7 +647,7 @@ word closure_layout(int closure_index, int count) {
// variable in. ctx_push / ctx_pop save and restore the enclosing function's
// compiler state around the body.
int closure() {
- int np = 0; char*[20] pn; word[20] pty; int hop, entry, i, t, envl, ncap, c, result, declared = 0, tags = 0, tag, lt, lfl = tline; word[20] ptags;
+ int np = 0; char*[24] pn; word[24] pty; int hop, entry, i, t, envl, ncap, c, result, declared = 0, tags = 0, tag, lt, lfl = tline; word[24] ptags;
word expected = closure_expected; closure_expected = 0;
reserve_closures(nclo + 1);
if (o3on) serr("closures can't be made inside an o3 region");
@@ -668,8 +668,8 @@ int closure() {
if (expected && expected[0] == TY_FN && !tag && (isptr(pty[np]) || pty[np][0] == TY_DYN || pty[np][0] == TY_FN)) ptags[np] = 1;
pnoffs[np] = toff; pnplaces[np] = tpack(); rs_note(RS_PARAM, toff); pn[np] = name();
np++;
- if (np >= 20) { die("too many parameters"); break; }
if (!accept(s_comma)) break;
+ if (np >= 24) { die("too many parameters"); break; } // 24, like a function
}
}
expect(s_rp);
@@ -1561,12 +1561,17 @@ int postfix_tail(int c) {
}
return c;
}
+// a global variable or array named u, m or d: then u*x is a multiplication (spec 1.6.3)
+int tag_is_global(int n) {
+ int s = lookup(n);
+ return s >= 0 && (skind[s] == K_GVAR || skind[s] == K_GARR);
+}
// prefix operators: the u*x / d*x / m*x recasts (the star has to touch the
// tag), casts like (int)x and (node*)x, dereference, address-of, prefix ++ and
// --, and any unary operator a program added (- ! ~ built in).
int unary() {
int c, un, t, place, constant, value; word storage, dependency;
- if (tk == T_ID && (tv == s_u || tv == s_m || tv == s_d) && findloc(tv) < 0) { // u*x, d*x, m*x: recast only when * is glued and the tag is not a local's name
+ if (tk == T_ID && (tv == s_u || tv == s_m || tv == s_d) && findloc(tv) < 0 && !tag_is_global(tv)) { // u*x, d*x, m*x: recast only when * is glued and the tag is not a local's name
peek();
if (pk_tk == T_OP && pk_tv == s_star && pq_gl[0]) {
t = S_M; if (tv == s_u) t = S_U; if (tv == s_d) t = S_D;
@@ -1777,7 +1782,7 @@ int storekeep(int t) {
// restored for the second side) and then joined, so a variable can't be given
// away on one side only. both sides are fresh objects, or neither is.
int ternary(int c) {
- int a, b, s0, sa, livea, live0 = live, n0 = nloc, ca, cb, ta, ba, bb; word temp_a, temp_b, mask_a, mask_b;
+ int a, b, s0, sa, livea, live0 = live, n0 = nloc, ca, cb, ta, ba, bb, conv, skip, back; word temp_a, temp_b, mask_a, mask_b;
rval(); plainuse(c);
ftest();
next();
@@ -1785,6 +1790,7 @@ int ternary(int c) {
s0 = snap_push();
ca = expr(); rval(); ta = xty; ba = xbor; temp_a = xaf; mask_a = effect_mask(ca);
if (ca != C_FRESH) plainuse(ca);
+ conv = -1; if (isnum(ta) && !isfl(ta) && ta != tword) { conv = hole(); op(O_JMP); back = here; setlit(conv, back); } // a jump to the next word, redirected below if the other side is a float (appendix b.2.5)
livea = live; sa = snap_push();
b = hole(); op(O_JMP);
expect(s_colon);
@@ -1792,11 +1798,14 @@ int ternary(int c) {
snap_restore(s0); live = live0;
cb = expr(); rval(); bb = xbor; temp_b = xaf; mask_b = effect_mask(cb);
if (cb != C_FRESH) plainuse(cb);
+ if (isfl(ta) && !isfl(xty)) { op(OP_I2F); xfloat = 1; xty = tfloat; } // on the second side's path only
join2(sa, livea, b, live, n0, "ends the two sides of ?: in different states");
snap_pop(s0);
- if (isfl(ta) && !isfl(xty)) { op(OP_I2F); xfloat = 1; xty = tfloat; }
+ if (conv >= 0 && isfl(xty)) { // the first side was an integer: convert it out of line
+ skip = hole(); op(O_JMP); setlit(conv, here); op(OP_I2F); lit(back); op(O_JMP); setlit(skip, here);
+ }
if (!compat(ta, xty) && !compat(xty, ta)) tcerr("the two sides of ?:", ta, xty);
- if (ta != tword && !isfl(ta)) xty = ta;
+ if (ta != tword && !isfl(ta) && !(conv >= 0 && isfl(xty))) xty = ta;
else if (isfl(ta) || isfl(xty)) { xty = tfloat; xfloat = 1; }
if_value = 0;
effect_value = mask_a | mask_b;
@@ -1950,6 +1959,10 @@ word cprim() {
}
}
}
+ if (tk == T_ID && enum_open >= 0) { // an earlier member of the enum being read (spec 2.8.1)
+ mc = npm - 1;
+ while (mc > enum_open) { mc--; if (pm_name[mc] == tv && !pm_nf[mc]) { next(); return pm_val[mc]; } }
+ }
die("expected a constant");
return 0;
}