|
|
1.1 root 1: /*
2: * File: omisc.c
3: * Contents: random, refresh, size, tabmat, toby
4: */
5:
6:
7: #include "../h/rt.h"
8: #define RandVal (RanScale*(k_random=(RandA*k_random+RandC)&MaxLong))
9:
10: /*
11: * ?x - produce a randomly selected element of x.
12: */
13:
14: OpDclV(random,1,"?")
15: {
16: register word val, i, j;
17: register union block *bp;
18: long r1;
19: char sbuf[MaxCvtLen];
20: union block *ep;
21: struct descrip *dp;
22: double rval;
23: extern char *alcstr();
24:
25: Arg2 = Arg1;
26: DeRef(Arg1);
27:
28: if (Qual(Arg1)) {
29: /*
30: * x is a string, produce a random character in it as the result.
31: * Note that a substring trapped variable is returned.
32: */
33: if ((val = StrLen(Arg1)) <= 0)
34: Fail;
35: blkreq((word)sizeof(struct b_tvsubs));
36: rval = RandVal; /* This form is used to get around */
37: rval *= val; /* a bug in a certain C compiler */
38: mksubs(&Arg2, &Arg1, (word)rval + 1, (word)1, &Arg0);
39: Return;
40: }
41:
42: switch (Type(Arg1)) {
43: case T_Cset:
44: /*
45: * x is a cset. Convert it to a string, select a random character
46: * of that string and return it. Note that a substring trapped
47: * variable is not needed.
48: */
49: cvstr(&Arg1, sbuf);
50: if ((val = StrLen(Arg1)) <= 0)
51: Fail;
52: strreq((word)1);
53: StrLen(Arg0) = 1;
54: rval = RandVal;
55: rval *= val;
56: StrLoc(Arg0) = alcstr(StrLoc(Arg1)+(word)rval, (word)1);
57: Return;
58:
59:
60: case T_List:
61: /*
62: * x is a list. Set i to a random number in the range [1,*x],
63: * failing if the list is empty.
64: */
65: bp = BlkLoc(Arg1);
66: val = bp->list.size;
67: if (val <= 0)
68: Fail;
69: rval = RandVal;
70: rval *= val;
71: i = (word)rval + 1;
72: j = 1;
73: /*
74: * Work down chain list of list blocks and find the block that
75: * contains the selected element.
76: */
77: bp = BlkLoc(BlkLoc(Arg1)->list.listhead);
78: while (i >= j + bp->lelem.nused) {
79: j += bp->lelem.nused;
80: if ((bp->lelem.listnext).dword != D_Lelem)
81: syserr("list reference out of bounds in random");
82: bp = BlkLoc(bp->lelem.listnext);
83: }
84: /*
85: * Locate the appropriate element and return a variable
86: * that points to it.
87: */
88: i += bp->lelem.first - j;
89: if (i >= bp->lelem.nelem)
90: i -= bp->lelem.nelem;
91: dp = &bp->lelem.lslots[i];
92: Arg0.dword = D_Var + ((word *)dp - (word *)bp);
93: VarLoc(Arg0) = dp;
94: Return;
95:
96: case T_Table:
97: /*
98: * x is a table. Set i to a random number in the range [1,*x],
99: * failing if the table is empty.
100: */
101: bp = BlkLoc(Arg1);
102: val = bp->table.size;
103: if (val <= 0)
104: Fail;
105: rval = RandVal;
106: rval *= val;
107: i = (word)rval + 1;
108: /*
109: * Work down the chain of elements in each bucket and return
110: * a variable that points to the i'th element encountered.
111: */
112: for (j = 0; j < TSlots; j++) {
113: for (ep = BlkLoc(bp->table.buckets[j]); ep != NULL;
114: ep = BlkLoc(ep->telem.clink)) {
115: if (--i <= 0) {
116: dp = &ep->telem.tval;
117: Arg0.dword = D_Var + ((word *)dp - (word *)bp);
118: VarLoc(Arg0) = dp;
119: Return;
120: }
121: }
122: }
123: case T_Set:
124: /*
125: * x is a set. Set i to a random number in the range [1,*x],
126: * failing if the set is empty.
127: */
128: bp = BlkLoc(Arg1);
129: val = bp->set.size;
130: if (val <= 0)
131: Fail;
132: rval = RandVal;
133: rval *= val;
134: i = (word)rval + 1;
135: /*
136: * Work down the chain of elements in each bucket and return
137: * the value of the ith element encountered.
138: */
139: for (j = 0; j < SSlots; j++) {
140: for (ep = BlkLoc(bp->set.sbucks[j]); ep != NULL;
141: ep = BlkLoc(ep->selem.clink)) {
142: if (--i <= 0) {
143: Arg0 = ep->selem.setmem;
144: Return;
145: }
146: }
147: }
148:
149: case T_Record:
150: /*
151: * x is a record. Set val to a random number in the range [1,*x]
152: * (*x is the number of fields), failing if the record has no
153: * fields.
154: */
155: bp = BlkLoc(Arg1);
156: val = BlkLoc(bp->record.recdesc)->proc.nfields;
157: if (val <= 0)
158: Fail;
159: /*
160: * Locate the selected element and return a variable
161: * that points to it
162: */
163: rval = RandVal;
164: rval *= val;
165: dp = &bp->record.fields[(word)rval];
166: Arg0.dword = D_Var + ((word *)dp - (word *)bp);
167: VarLoc(Arg0) = dp;
168: Return;
169:
170: default:
171: /*
172: * Try converting it to an integer
173: */
174: switch (cvint(&Arg1, &r1)) {
175:
176: case T_Longint:
177: runerr(205, &Arg1);
178:
179: case T_Integer:
180: /*
181: * x is an integer, be sure that it's non-negative.
182: */
183: val = (word)r1;
184: if (val < 0)
185: runerr(205, &Arg1);
186: getrand:
187: /*
188: * val contains the integer value of x. If val is 0, return
189: * a real in the range [0,1), else return an integer in the
190: * range [1,val].
191: */
192: if (val == 0) {
193: rval = RandVal;
194: mkreal(rval, &Arg0);
195: }
196: else {
197: rval = RandVal;
198: rval *= val;
199: Mkint((long)rval + 1, &Arg0);
200: }
201: Return;
202:
203: default:
204: /*
205: * x is of a type for which random generation is not supported
206: */
207: runerr(113, &Arg1);
208: }
209: }
210: }
211:
212:
213: /*
214: * ^x - return an entry block for co-expression x from the refresh block.
215: */
216:
217: OpDcl(refresh,1,"^")
218: {
219: register struct b_coexpr *sblkp;
220: register struct b_refresh *rblkp;
221: register struct descrip *dp, *dsp;
222: register word *newsp;
223: int na, nl, i;
224: extern struct b_coexpr *alcstk();
225: extern struct b_refresh *alceblk();
226:
227: /*
228: * Be sure a co-expression is being refreshed.
229: */
230: if (Qual(Arg1) || Arg1.dword != D_Coexpr)
231: runerr(118, &Arg1);
232:
233: /*
234: * Get a new co-expression stack and initialize.
235: */
236: sblkp = alcstk();
237: sblkp->activator = nulldesc;
238: sblkp->size = 0;
239: sblkp->nextstk = stklist;
240: stklist = sblkp;
241: sblkp->freshblk = BlkLoc(Arg1)->coexpr.freshblk;
242: /*
243: * Icon stack starts at word after co-expression stack block. C stack
244: * starts at end of stack region on machines with down-growing C stacks
245: * and somewhere in the middle of the region.
246: *
247: * The C stack is aligned on a doubleword boundary. For upgrowing
248: * stacks, the C stack starts in the middle of the stack portion
249: * of the static block. For downgrowing stacks, the C stack starts
250: * at the last word of the static block.
251: */
252: newsp = (word *)((char *)sblkp + sizeof(struct b_coexpr));
253: #ifdef UpStack
254: sblkp->cstate[0] =
255: ((word)((char *)sblkp + (stksize - sizeof(*sblkp))/2)
256: &~(WordSize*2-1));
257: #else
258: sblkp->cstate[0] =
259: ((word)((char *)sblkp + stksize - WordSize)&~(WordSize*2-1));
260: #endif UpStack
261: sblkp->es_argp = (struct descrip *)newsp;
262: /*
263: * Get pointer to refresh block and get number of arguments and locals.
264: */
265: rblkp = (struct b_refresh *)BlkLoc(sblkp->freshblk);
266: na = (rblkp->pfmkr).pf_nargs + 1;
267: nl = rblkp->numlocals;
268:
269: /*
270: * Copy arguments onto new stack.
271: */
272: dp = &rblkp->elems[0];
273: dsp = (struct descrip *)newsp;
274: for (i = 1; i <= na; i++)
275: *dsp++ = *dp++;
276:
277: /*
278: * Copy procedure frame to new stack and point dsp to word after frame.
279: */
280: *((struct pf_marker *)dsp) = rblkp->pfmkr;
281: sblkp->es_pfp = (struct pf_marker *)dsp;
282: dsp = (struct descrip *)((word *)dsp + Vwsizeof(*pfp));
283: sblkp->es_ipc = rblkp->ep;
284: sblkp->es_gfp = 0;
285: sblkp->es_efp = 0;
286: sblkp->tvalloc = NULL;
287: sblkp->es_ilevel = 0;
288:
289: /*
290: * Copy locals to new stack and refresh block.
291: */
292: for (i = 1; i <= nl; i++)
293: *dsp++ = *dp++;
294:
295: /*
296: * Push two null descriptors on the stack.
297: */
298: *dsp++ = nulldesc;
299: *dsp++ = nulldesc;
300:
301: sblkp->es_sp = (word *)dsp - 1;
302:
303: /*
304: * Establish line and file values and clear location for transmitted value.
305: */
306: sblkp->es_line = line;
307:
308: /*
309: * Return the new co-expression.
310: */
311: Arg0.dword = D_Coexpr;
312: BlkLoc(Arg0) = (union block *) sblkp;
313: Return;
314: }
315:
316:
317: /*
318: * *x - return size of string or object x.
319: */
320:
321: /* >size */
322: OpDcl(size,1,"*")
323: {
324: char sbuf[MaxCvtLen];
325:
326: Arg0.dword = D_Integer;
327: if (Qual(Arg1)) {
328: /*
329: * If Arg1 is a string, return the length of the string.
330: */
331: IntVal(Arg0) = StrLen(Arg1);
332: }
333: else {
334: /*
335: * Arg1 is not a string. For most types, the size is in the size
336: * field of the block. For records, it is in an auxiliary
337: * structure.
338: */
339: switch (Type(Arg1)) {
340: case T_List:
341: IntVal(Arg0) = BlkLoc(Arg1)->list.size;
342: break;
343:
344: case T_Table:
345: IntVal(Arg0) = BlkLoc(Arg1)->table.size;
346: break;
347:
348: case T_Set:
349: IntVal(Arg0) = BlkLoc(Arg1)->set.size;
350: break;
351:
352: case T_Cset:
353: IntVal(Arg0) = BlkLoc(Arg1)->cset.size;
354: break;
355:
356: case T_Record:
357: IntVal(Arg0) = BlkLoc(BlkLoc(Arg1)->record.recdesc)->proc.nfields;
358: break;
359:
360: case T_Coexpr:
361: IntVal(Arg0) = BlkLoc(Arg1)->coexpr.size;
362: break;
363:
364: default:
365: /*
366: * Try to convert it to a string.
367: */
368: if (cvstr(&Arg1, sbuf) == NULL)
369: runerr(112, &Arg1); /* no notion of size */
370: IntVal(Arg0) = StrLen(Arg1);
371: }
372: }
373: Return;
374: }
375: /* <size */
376:
377: /*
378: * =x - tab(match(x)).
379: * Reverses effects if resumed.
380: */
381:
382: OpDcl(tabmat,1,"=")
383: {
384: register word l;
385: register char *s1, *s2;
386: word i, j;
387: char sbuf[MaxCvtLen];
388:
389: /*
390: * x must be a string.
391: */
392: if (cvstr(&Arg1,sbuf) == NULL)
393: runerr(103, &Arg1);
394:
395: /*
396: * Make a copy of &pos.
397: */
398: i = k_pos;
399:
400: /*
401: * Fail if &subject[&pos:0] is not of sufficient length to contain x.
402: */
403: j = StrLen(k_subject) - i + 1;
404: if (j < StrLen(Arg1))
405: Fail;
406:
407: /*
408: * Get pointers to x (s1) and &subject (s2). Compare them on a bytewise
409: * basis and fail if s1 doesn't match s2 for *s1 characters.
410: */
411: s1 = StrLoc(Arg1);
412: s2 = StrLoc(k_subject) + i - 1;
413: l = StrLen(Arg1);
414: while (l-- > 0) {
415: if (*s1++ != *s2++)
416: Fail;
417: }
418:
419: /*
420: * Increment &pos to tab over the matched string and suspend the
421: * matched string.
422: */
423: l = StrLen(Arg1);
424: k_pos += l;
425: Arg0 = Arg1;
426: Suspend;
427:
428: /*
429: * tabmat has been resumed, restore &pos and fail.
430: */
431: k_pos = i;
432: if (k_pos > StrLen(k_subject) + 1)
433: runerr(205, &tvky_pos.kyval);
434: Fail;
435: }
436:
437:
438: /*
439: * i to j by k - generate successive values.
440: */
441:
442: /* >toby */
443: OpDcl(toby,3,"toby")
444: {
445: long from, to, by;
446:
447: /*
448: * Arg1 (from), Arg2 (to), and Arg3 (by) must be integers.
449: * Also, Arg3 must not be zero.
450: */
451: if (cvint(&Arg1, &from) == NULL)
452: runerr(101, &Arg1);
453: if (cvint(&Arg2, &to) == NULL)
454: runerr(101, &Arg2);
455: if (cvint(&Arg3, &by) == NULL)
456: runerr(101, &Arg3);
457: if (by == 0)
458: runerr(211, &Arg3);
459:
460: /*
461: * Count up or down (depending on relationship of from and to) and
462: * suspend each value in sequence, failing when the limit has been
463: * exceeded.
464: */
465: while ((from <= to && by > 0) || (from >= to && by < 0)) {
466: Mkint(from, &Arg0);
467: Suspend;
468: from += by;
469: }
470: Fail;
471: }
472: /* <toby */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.