1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 2: 3: /* 4: $Header: b3loc.c,v 1.4 85/08/27 10:56:45 timo Exp $ 5: */ 6: 7: /* B locations and environments */ 8: #include "b.h" 9: #include "b0con.h" 10: #include "b1obj.h" 11: #include "b3env.h" /* for bndtgs */ 12: #include "b3sem.h" 13: #include "b3sou.h" /* for tarvalue() */ 14: #include "b3err.h" /* for still_ok */ 15: 16: Hidden value* location(l) loc l; { 17: value *ll; 18: if (Is_locloc(l)) { 19: if (!in_env(curnv->tab, l, &ll)) 20: error(MESS(3600, "target not initialised")); 21: return ll; 22: } else if (Is_simploc(l)) { 23: simploc *sl= Simploc(l); 24: if (!in_env(sl->e->tab, sl->i, &ll)) 25: if (Is_locloc(sl->i)) 26: error(MESS(3601, "target not initialised")); 27: else error3(0, sl->i, 28: MESS(3602, " hasn't been initialised")); 29: return ll; 30: } else if (Is_tbseloc(l)) { 31: tbseloc *tl= Tbseloc(l); 32: ll= location(tl->R); 33: if (still_ok) { 34: ll= adrassoc(*ll, tl->K); 35: if (ll == Pnil && still_ok) error(MESS(3603, "key not in table")); 36: } 37: return ll; 38: } else { 39: syserr(MESS(3604, "call of location with improper type")); 40: return (value *) Dummy; 41: } 42: } 43: 44: Hidden Procedure uniquify(l) loc l; { 45: if (Is_simploc(l)) { 46: simploc *sl= Simploc(l); 47: value *ta= &(sl->e->tab), ke= sl->i; 48: uniql(ta); 49: check_location(l); 50: if (still_ok) { 51: if (Is_compound(*ta)) uniql(Field(*ta, intval(ke))); 52: else { value *aa, v; 53: VOID uniq_assoc(*ta, ke); 54: aa= adrassoc(*ta, ke); 55: v= copy(tarvalue(ke, *aa)); 56: release(*aa); 57: *aa= v; 58: uniql(aa); 59: } 60: } 61: } else if (Is_tbseloc(l)) { 62: tbseloc *tl= Tbseloc(l); 63: value t, ke; 64: uniquify(tl->R); 65: if (still_ok) { t= *location(tl->R); ke= tl->K; } 66: if (still_ok) { 67: if (!Is_table(t)) error(MESS(3605, "selection on non-table")); 68: else if (empty(t)) error(MESS(3606, "selection on empty table")); 69: else { 70: check_location(l); 71: if (still_ok) VOID uniq_assoc(t, ke); 72: } 73: } 74: } else if (Is_trimloc(l)) { syserr(MESS(3607, "uniquifying trimloc")); 75: } else if (Is_compound(l)) { syserr(MESS(3608, "uniquifying comploc")); 76: } else syserr(MESS(3609, "uniquifying non-location")); 77: } 78: 79: Visible Procedure check_location(l) loc l; { 80: VOID location(l); 81: /* location may produce an error message */ 82: } 83: 84: Visible value content(l) loc l; { 85: value *ll= location(l); 86: return still_ok ? copy(*ll) : Vnil; 87: } 88: 89: Visible loc trim_loc(l, v, sign) loc l; value v; char sign; { 90: loc root, res; value text, B, C; 91: if (Is_simploc(l) || Is_tbseloc(l)) { 92: uniquify(l); /* Call tarvalue at proper time */ 93: root= l; 94: B= zero; C= zero; 95: } else if (Is_trimloc(l)) { 96: trimloc *rr= Trimloc(l); 97: root= rr->R; 98: B= rr->B; C= rr->C; 99: } else { 100: error(MESS(3610, "trim (@ or |) on target of improper type")); 101: return Lnil; 102: } 103: text= content(root); 104: if (!still_ok); 105: else if (!Is_text(text)) { 106: error(MESS(3611, "in the target t@p or t|p, t does not contain a text")); 107: } else { 108: value s= size(text), w, x, b_plus_c; 109: if (sign == '@') B= sum(B, w=diff(v, one)); 110: else { C= sum(C, w=diff(x= diff(s, B), v)); release(x); } 111: release(w); 112: b_plus_c= sum(B, C); 113: if (still_ok && (compare(B,zero)<0 || compare(C,zero)<0 114: || compare(b_plus_c,s)>0)) 115: error(MESS(3612, "in the target t@p or t|p, p is out of bounds")); 116: else res= mk_trimloc(root, B, C); 117: if (sign == '@') release(B); 118: else release(C); 119: release(s); release(b_plus_c); 120: } 121: release(text); 122: if (still_ok) return res; else return Lnil; 123: } 124: 125: Visible loc tbsel_loc(R, K) loc R; value K; { 126: if (Is_simploc(R) || Is_tbseloc(R)) return mk_tbseloc(R, K); 127: else error(MESS(3613, "selection on target of improper type")); 128: return Lnil; 129: } 130: 131: Visible loc local_loc(i) basidf i; { return mk_simploc(i, curnv); } 132: 133: Visible loc global_loc(i) basidf i; { return mk_simploc(i, prmnv); } 134: 135: Hidden Procedure put_trim(v, tl) value v; trimloc *tl; { 136: value rr, nn, head, tail, part; 137: value B= tl->B, C= tl->C, len, len_minus_c, tail_start; 138: rr= *location(tl->R); 139: len= size(rr); 140: len_minus_c= diff(len, C); release(len); 141: tail_start= sum(len_minus_c, one); release(len_minus_c); 142: if (compare(B, zero)<0 || compare(C, zero)<0 143: || compare(B, tail_start)>=0) 144: error(MESS(3614, "trim (@ or |) on text location out of bounds")); 145: else { 146: head= curtail(rr, B); /* rr|B */ 147: tail= behead(rr, tail_start); /* rr@(#rr-C+1) */ 148: part= concat(head, v); release(head); 149: nn= concat(part, tail); release(part); release(tail); 150: put(nn, tl->R); release(nn); 151: } 152: release(tail_start); 153: } 154: 155: Visible Procedure put(v, l) value v; loc l; { 156: if (Is_locloc(l)) { 157: e_replace(v, &curnv->tab, l); 158: } else if (Is_simploc(l)) { 159: simploc *sl= Simploc(l); 160: e_replace(v, &(sl->e->tab), sl->i); 161: } else if (Is_trimloc(l)) { 162: if (!Is_text(v)) error(MESS(3615, "putting non-text in trim (@ or |)")); 163: else put_trim(v, Trimloc(l)); 164: } else if (Is_compound(l)) { 165: intlet k, len= Nfields(l); 166: if (!Is_compound(v)) 167: error(MESS(3616, "putting non-compound in compound location")); 168: else if (Nfields(v) != Nfields(l)) 169: error(MESS(3617, "putting compound in compound location of different length")); 170: else k_Overfields { put(*Field(v, k), *Field(l, k)); } 171: } else if (Is_tbseloc(l)) { 172: tbseloc *tl= Tbseloc(l); value *rootloc; 173: uniquify(tl->R); 174: if (still_ok) { 175: rootloc= location(tl->R); 176: if (still_ok && !Is_table(*rootloc)) 177: error(MESS(3621, "selection on non-table")); 178: if (still_ok) replace(v, rootloc, tl->K); 179: } 180: } else error(MESS(3618, "putting in non-target")); 181: } 182: 183: /* Check for correct effect of multiple put-command: catches PUT 1, 2 IN x, x. 184: The assignment cannot be undone, but this is not considered a problem. 185: For trimmed-texts, no checks are made because the language definition 186: itself causes problem (try PUT "abc", "" IN x@2|1, x@3|1). */ 187: 188: Hidden bool putck(v, l) value v; loc l; { 189: intlet k, len; value w; 190: if (!still_ok) return No; 191: if (Is_compound(l)) { 192: if (!Is_compound(v) || Nfields(v) != (len= Nfields(l))) 193: return No; /* Severe type error */ 194: k_Overfields 195: { if (!putck(*Field(v, k), *Field(l, k))) return No; } 196: return Yes; 197: } 198: if (Is_trimloc(l)) return Yes; /* Don't check trim locations */ 199: w= *location(l); 200: /* Unfortunately, this may already cause an error, e.g. after 201: PUT 1, {} IN t[1], t. This can't be helped unless we introduce 202: a flag so that location will shut up. */ 203: return still_ok && compare(v, w) == 0; 204: } 205: 206: /* The check can't be called from within put because put is recursive, 207: and so is the check: then, for the inner levels the check would be done 208: twice. Moreover, we don't want to clutter up put, which is called 209: internally in, many places. */ 210: 211: Visible Procedure put_with_check(v, l) value v; loc l; { 212: intlet i, k, len; bool ok; 213: put(v, l); 214: if (!still_ok || !Is_compound(l)) 215: return; /* Single target can't be wrong */ 216: len= Nfields(l); ok= Yes; 217: /* Quick check for putting in all different local targets: */ 218: k_Overfields { 219: if (!IsSmallInt(*Field(l, k))) { ok= No; break; } 220: for (i= k-1; i >= 0; --i) { 221: if (*Field(l, i) == *Field(l, k)) { ok= No; break; } 222: } 223: if (!ok) break; 224: } 225: if (ok) return; /* All different local basic-targets */ 226: if (!putck(v, l)) 227: error(MESS(3619, "putting different values in same location")); 228: } 229: 230: 231: Hidden bool l_exists(l) loc l; { 232: if (Is_simploc(l)) { 233: simploc *sl= Simploc(l); 234: return envassoc(sl->e->tab, sl->i) != Pnil; 235: } else if (Is_trimloc(l)) { 236: error(MESS(3620, "deleting trimmed (@ or |) target")); 237: return No; 238: } else if (Is_compound(l)) { 239: intlet k, len= Nfields(l); 240: k_Overfields { if (!l_exists(*Field(l, k))) return No; } 241: return Yes; 242: } else if (Is_tbseloc(l)) { 243: tbseloc *tl= Tbseloc(l); value *ll; 244: uniquify(tl->R); /* call tarvalue() at proper place */ 245: if (still_ok) ll= location(tl->R); 246: if (still_ok && !Is_table(*ll)) 247: error(MESS(3621, "selection on non-table")); 248: return still_ok && in_keys(tl->K, *ll); 249: } else { 250: error(MESS(3622, "deleting non-target")); 251: return No; 252: } 253: } 254: 255: /* Delete a location if it exists */ 256: 257: Hidden Procedure l_del(l) loc l; { 258: if (Is_simploc(l)) { 259: simploc *sl= Simploc(l); 260: e_delete(&(sl->e->tab), sl->i); 261: } else if (Is_trimloc(l)) { 262: error(MESS(3623, "deleting trimmed (@ or |) target")); 263: } else if (Is_compound(l)) { 264: intlet k, len= Nfields(l); 265: k_Overfields { l_del(*Field(l, k)); } 266: } else if (Is_tbseloc(l)) { 267: tbseloc *tl= Tbseloc(l); 268: value *lc; 269: uniquify(tl->R); 270: if (still_ok) { 271: lc= location(tl->R); 272: if (in_keys(tl->K, *lc)) delete(lc, tl->K); 273: } 274: } else error(MESS(3624, "deleting non-target")); 275: } 276: 277: Visible Procedure l_delete(l) loc l; { 278: if (l_exists(l)) l_del(l); 279: else if (still_ok) error(MESS(3625, "deleting non-existent target")); 280: } 281: 282: Visible Procedure l_insert(v, l) value v; loc l; { 283: value *ll; 284: uniquify(l); 285: if (still_ok) { 286: ll= location(l); 287: if (!Is_list(*ll)) error(MESS(3626, "inserting in non-list")); 288: else insert(v, ll); 289: } 290: } 291: 292: Visible Procedure l_remove(v, l) value v; loc l; { 293: value *ll; 294: uniquify(l); 295: if (still_ok) { 296: ll= location(l); 297: if (!Is_list(*ll)) error(MESS(3627, "removing from non-list")); 298: else if (empty(*ll)) error(MESS(3628, "removing from empty list")); 299: else remove(v, ll); 300: } 301: } 302: 303: /* Warning: choose is only as good as the accuracy of the random-number */ 304: /* generator. In particular, for very large values of v, elements will */ 305: /* be chosen unfairly. Choose should be rewritten to cope with this */ 306: 307: Visible Procedure choose(l, v) loc l; value v; { 308: value w, s, r; 309: if (!Is_tlt(v)) error(MESS(3629, "choosing from non-text, -list or -table")); 310: else if (empty(v)) error(MESS(3630, "choosing from empty text, list or table")); 311: else { 312: /* PUT (floor(random*#v) + 1) th'of v IN l */ 313: s= size(v); 314: r= prod(w= random(), s); release(w); release(s); 315: w= floorf(r); release(r); 316: r= sum(w, one); release(w); 317: put(w= th_of(r, v), l); release(w); release(r); 318: } 319: } 320: 321: Visible Procedure draw(l) loc l; { 322: value r= random(); 323: put(r, l); 324: release(r); 325: } 326: 327: Visible Procedure bind(l) loc l; { 328: if (*bndtgs != Vnil) { 329: if (Is_simploc(l)) { 330: simploc *ll= Simploc(l); 331: if (!in(ll->i, *bndtgs)) /* kludge */ /* what for? */ 332: insert(ll->i, bndtgs); 333: } else if (Is_compound(l)) { 334: intlet k, len= Nfields(l); 335: k_Overfields { bind(*Field(l, k)); } 336: } else error(MESS(3631, "binding non-identifier")); 337: } 338: l_del(l); 339: } 340: 341: Visible Procedure unbind(l) loc l; { 342: if (*bndtgs != Vnil) { 343: if (Is_simploc(l)) { 344: simploc *ll= Simploc(l); 345: if (in(ll->i, *bndtgs)) 346: remove(ll->i, bndtgs); 347: } else if (Is_compound(l)) { 348: intlet k, len= Nfields(l); 349: k_Overfields { unbind(*Field(l, k)); } 350: } else error(MESS(3632, "unbinding non-identifier")); 351: } 352: l_del(l); 353: }