|
|
1.1 root 1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
2:
3: /*
4: $Header: b3int.c,v 1.4 85/08/22 16:58:27 timo Exp $
5: */
6:
7: /* B interpreter using theaded trees */
8:
9: #include "b.h"
10: #include "b0fea.h"
11: #include "b1mem.h"
12: #include "b1obj.h"
13: #include "b2nod.h"
14: #include "b3err.h"
15: #include "b3sem.h"
16: #include "b3env.h"
17: #include "b3int.h"
18: #include "b3in2.h"
19: #include "b3sta.h"
20:
21:
22: /* Relicts from old system: */
23:
24: Visible value resval;
25: Visible bool terminated;
26:
27:
28: /* Shorthands: */
29:
30: #define Pop2(fun) (w = pop(), v = pop(), fun(v, w), release(v), release(w))
31: #define Pop1(fun) (v = pop(), fun(v), release(v))
32: #define Dyop(funvw) \
33: (w = pop(), v = pop(), push(funvw), release(v), release(w))
34: #define Monop(funv) (v = pop(), push(funv), release(v))
35: #define Flagged() (Thread2(pc) != NilTree)
36: #define LocFlagged() (Thread2(pc) != NilTree && !noloc)
37: #define ValOrLoc(feval, floc) (LocFlagged() ? (floc) : (feval))
38: #define Jump() (tracing && tr_jump(), next = Thread2(pc))
39: #define Comp(op) (w = pop(), v = pop(), report = (compare(v, w) op 0), Comp2())
40: #define Comp2() (release(v), !Flagged() ? release(w) : Comp3())
41: #define Comp3() (report ? push(w) : (Jump(), release(w)))
42: #define F(n) ((value)*Branch(pc, (n)))
43:
44:
45: /* Execute a threaded tree until the end or until a terminating-command.
46: The boolean argument 'wantvalue' tells whether it must deliver
47: a value or not.
48: */
49:
50: Hidden value
51: run(start, wantvalue) parsetree start; bool wantvalue; {
52: value u, v, w; int k; bool X, Y; int call_stop= call_level;
53: #ifdef IBMPC
54: int loopcnt= 0;
55: #endif
56: parsetree old_next= next;
57: /* While run can be used recursively, save some state info */
58:
59: next= start;
60: for (;;) {
61: #ifdef IBMPC
62: if (loopcnt++ == 100) {
63: bdos(0x2c, 0, 0);
64: /* forcing a DOS function call (get time) */
65: /* so that a break interrupt can be executed */
66: loopcnt= 0;
67: }
68: #endif
69: if (!still_ok) break;
70: pc= next;
71: if (pc == Halt) {
72: error(MESS(3500, "unexpected program halt"));
73: break;
74: }
75: if (!Is_parsetree(pc)) {
76: if (pc == Stop) {
77: if (call_level == call_stop) break;
78: ret();
79: continue;
80: }
81: if (!Is_number(pc)) syserr(MESS(3501, "run: bad thread"));
82: switch (intval(pc)) {
83: case 0:
84: pc= Stop;
85: break;
86: case 1:
87: error(
88: MESS(3502, "none of the alternative tests of SELECT succeeds"));
89: break;
90: case 2:
91: if (resexp == Rep)
92: error(MESS(3503, "TEST-unit reports no outcome"));
93: else
94: error(MESS(3504, "YIELD-unit returns no value"));
95: break;
96: case 3:
97: if (resexp == Rep)
98: error(MESS(3505, "test-refinement reports no outcome"));
99: else
100: error(MESS(3506, "refinement returns no value"));
101: /* "expression-" seems superfluous here */
102: break;
103: default:
104: v= convert(pc, No, No);
105: error3(MESS(3507, "run-time error "), v, 0);
106: release(v);
107: }
108: continue;
109: }
110: next = Thread(pc);
111: if (tracing) tr_node(pc);
112: /* <<<<<<<<<<<<<<<< */
113: switch (Nodetype(pc)) {
114:
115: case HOW_TO:
116: case REFINEMENT:
117: error(MESS(3508, "run: cannot execute unit-definition"));
118: break;
119:
120: case YIELD:
121: case TEST:
122: switch (Nodetype(F(FPR_FORMALS))) {
123: case TAG:
124: break;
125: case MONF: case MONPRD:
126: w= pop(); v= pop();
127: put(v, w); release(v); release(w);
128: break;
129: case DYAF: case DYAPRD:
130: w= pop(); v= pop(); u= pop();
131: put(u, w); release(u); release(w);
132: u= pop();
133: put(u, v); release(u); release(v);
134: break;
135: default:
136: syserr(MESS(3509, "bad FPR_FORMAL"));
137: }
138: break;
139:
140: /* Commands */
141:
142: case SUITE:
143: curlino = F(SUI_LINO);
144: curline = F(SUI_CMD);
145: break;
146:
147: case IF:
148: case AND:
149: case WHILE:
150: case TEST_SUITE:
151: if (!report) Jump(); break;
152:
153: case OR: if (report) Jump(); break;
154:
155: case FOR:
156: w= pop(); v= pop();
157: if (!in_ranger(v, &w)) { release(v); release(w); Jump(); }
158: else { push(v); push(w); }
159: break;
160:
161: case PUT: Pop2(put_with_check); break;
162: case INSERT: Pop2(l_insert); break;
163: case REMOVE: Pop2(l_remove); break;
164: case CHOOSE: Pop2(choose); break;
165: case DRAW: Pop1(draw); break;
166: case SET_RANDOM: Pop1(set_random); break;
167: case DELETE: Pop1(l_delete); break;
168: case CHECK: if (!report) checkerr(); break;
169:
170: case WRITE:
171: nl(F(WRT_L_LINES));
172: if (F(WRT_EXPR)) { v = pop(); writ(v); release(v); }
173: nl(F(WRT_R_LINES));
174: break;
175:
176: case READ: Pop2(read_eg); break;
177:
178: case READ_RAW: Pop1(read_raw); break;
179:
180: case QUIT:
181: if (resexp != Voi)
182: error(MESS(3510, "QUIT may only occur in a HOW'TO or command-refinement"));
183: if (call_level == 0 && still_ok) terminated= Yes;
184: next= Stop; break;
185: case RETURN:
186: if (resexp != Ret)
187: error(MESS(3511, "RETURN may only occur in a YIELD or expression-refinement"));
188: resval = pop(); next= Stop; break;
189: case REPORT:
190: if (resexp != Rep)
191: error(MESS(3512, "REPORT may only occur in a TEST-unit or test-refinement"));
192: next= Stop; break;
193: case SUCCEED:
194: if (resexp != Rep)
195: error(MESS(3513, "SUCCEED may only occur in a TEST-unit or test-refinement"));
196: report = Yes; next= Stop; break;
197: case FAIL:
198: if (resexp != Rep)
199: error(MESS(3514, "FAIL may only occur in a TEST-unit or test-refinement"));
200: report = No; next= Stop; break;
201:
202: case USER_COMMAND:
203: x_user_command(F(UCMD_NAME), F(UCMD_ACTUALS), F(UCMD_DEF));
204: break;
205:
206: case EXTENDED_COMMAND:
207: #ifdef EXT_COMMAND
208: x_extended_command(F(ECMD_NAME), F(ECMD_ACTUALS));
209: #endif
210: break;
211:
212: /* Expressions, targets */
213:
214: case COLLATERAL:
215: v = mk_compound(k= Nfields(F(COLL_SEQ)));
216: while (--k >= 0)
217: *Field(v, k) = pop();
218: push(v);
219: break;
220:
221: /* Expressions, targets */
222:
223: case SELECTION: Dyop(ValOrLoc(associate(v, w), tbsel_loc(v, w))); break;
224:
225: case BEHEAD:
226: w= pop(); v= pop();
227: push(LocFlagged() ? trim_loc(v, w, '@') : behead(v, w));
228: release(v); release(w);
229: break;
230:
231: case CURTAIL:
232: w= pop(); v= pop();
233: push(LocFlagged() ? trim_loc(v, w, '|') : curtail(v, w));
234: release(v); release(w);
235: break;
236:
237: case MONF:
238: v = pop();
239: formula(Vnil, F(MON_NAME), v, F(MON_FCT));
240: release(v);
241: break;
242:
243: case DYAF:
244: w = pop(); v = pop();
245: formula(v, F(DYA_NAME), w, F(DYA_FCT));
246: release(v); release(w);
247: break;
248:
249: case TEXT_LIT:
250: v= F(XLIT_TEXT);
251: if (F(XLIT_NEXT)) { w= pop(); v= concat(v, w); release(w); }
252: else copy(v);
253: push(v);
254: break;
255:
256: case TEXT_CONV:
257: if (F(XCON_NEXT)) w= pop();
258: u= pop();
259: v= convert(u, Yes, Yes);
260: release(u);
261: if (F(XCON_NEXT)) {
262: v= concat(u= v, w);
263: release(u);
264: release(w);
265: }
266: push(v);
267: break;
268:
269: case ELT_DIS: push(mk_elt()); break;
270:
271: case LIST_DIS:
272: u = mk_elt();
273: k= Nfields(F(LDIS_SEQ));
274: while (--k >= 0) {
275: insert(v = pop(), &u);
276: release(v);
277: }
278: push(u);
279: break;
280:
281: case RANGE_DIS: Dyop(mk_range(v, w)); break;
282:
283: case TAB_DIS:
284: u = mk_elt();
285: k= Nfields(F(TDIS_SEQ));
286: while ((k -= 2) >= 0) {
287: w = pop(); v = pop();
288: /* Should check for same key with different associate */
289: replace(w, &u, v);
290: release(v); release(w);
291: }
292: push(u);
293: break;
294:
295: /* Tests */
296:
297: case NOT: report = !report; break;
298:
299: /* Quantifiers can be described as follows:
300: Report X at first test which reports Y. If no test reports Y, report !X.
301: type X Y
302: SOME Yes Yes
303: EACH No No
304: NO No Yes. */
305:
306: case EACH_IN: X= Y= No; goto quant;
307: case NO_IN: X= No; Y= Yes; goto quant;
308: case SOME_IN: X= Y= Yes;
309: quant:
310: w= pop(); v= pop();
311: if (Is_compound(w) && report == Y) { report= X; Jump(); }
312: else if (!in_ranger(v, &w)) { report= !X; Jump(); }
313: else { push(v); push(w); break; }
314: release(v); release(w);
315: break;
316:
317: case EACH_PARSING: X= Y= No; goto parse;
318: case NO_PARSING: X= No; Y= Yes; goto parse;
319: case SOME_PARSING: X= Y= Yes;
320: parse:
321: w= pop(); v= pop();
322: if (Is_compound(w) && report == Y) { report= X; Jump(); }
323: else if (!pa_ranger(v, &w)) { report= !X; Jump(); }
324: else { push(v); push(w); break; }
325: release(v); release(w);
326: break;
327:
328: case MONPRD:
329: v = pop();
330: proposition(Vnil, F(MON_NAME), v, F(MON_FCT));
331: release(v);
332: break;
333:
334: case DYAPRD:
335: w = pop(); v = pop();
336: proposition(v, F(DYA_NAME), w, F(DYA_FCT));
337: release(v); release(w);
338: break;
339:
340: case LESS_THAN: Comp(<); break;
341: case AT_MOST: Comp(<=); break;
342: case GREATER_THAN: Comp(>); break;
343: case AT_LEAST: Comp(>=); break;
344: case EQUAL: Comp(==); break;
345: case UNEQUAL: Comp(!=); break;
346:
347: case TAGformal:
348: call_formal(F(TAG_NAME), F(TAG_ID), LocFlagged());
349: break;
350:
351: case TAGlocal:
352: push(ValOrLoc(v_local(F(TAG_NAME), F(TAG_ID)), local_loc(F(TAG_ID))));
353: break;
354:
355: case TAGglobal:
356: push(ValOrLoc(v_global(F(TAG_NAME)), global_loc(F(TAG_NAME))));
357: break;
358:
359: case TAGmystery:
360: if (LocFlagged()) push(l_mystery(F(TAG_NAME), F(TAG_ID)));
361: else v_mystery(F(TAG_NAME), F(TAG_ID));
362: break;
363:
364: case TAGrefinement:
365: call_refinement(F(TAG_NAME), F(TAG_ID), Flagged());
366: break;
367:
368: case TAGzerfun:
369: formula(Vnil, F(TAG_NAME), Vnil, F(TAG_ID));
370: break;
371:
372: case TAGzerprd:
373: proposition(Vnil, F(TAG_NAME), Vnil, F(TAG_ID));
374: break;
375:
376: case NUMBER:
377: push(copy(F(NUM_VALUE)));
378: break;
379:
380: default:
381: syserr(MESS(3515, "run: bad node type"));
382:
383: }
384: /* >>>>>>>>>>>>>>>> */
385: }
386: v = Vnil;
387: if (wantvalue && still_ok) v = pop();
388: /* Unwind stack when stopped by error: */
389: while (call_level != call_stop) ret();
390: next= old_next;
391: return v;
392: }
393:
394:
395: /* External interfaces: */
396:
397: Visible Procedure execthread(start) parsetree start; {
398: run(start, No);
399: }
400:
401: Visible value evalthread(start) parsetree start; {
402: return run(start, Yes);
403: }
404:
405: Visible Procedure initint() {
406: /* Dummy, relict */
407: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.