|
|
1.1 root 1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
2:
3: /* $Header: b2gen.c,v 1.4 85/08/27 10:57:31 timo Exp $ */
4:
5: /* Code generation */
6:
7: #include "b.h"
8: #include "b0fea.h"
9: #include "b1obj.h"
10: #include "b2exp.h"
11: #include "b2nod.h"
12: #include "b2gen.h" /* Must be after b2nod.h */
13: #include "b3err.h"
14: #include "b3env.h"
15: #include "b3int.h"
16: #include "b3sem.h"
17: #include "b3sou.h"
18:
19: Visible Procedure fix_nodes(pt, code) parsetree *pt; parsetree *code; {
20: context c; value *setup(), *su;
21: sv_context(&c);
22: curline= *pt; curlino= one;
23: su= setup(*pt);
24: if (su) analyze(*pt, su);
25: curline= *pt; curlino= one;
26: inithreads();
27: fix(pt, su ? 'x' : 'v');
28: endthreads(code);
29: cleanup();
30: #ifdef TYPE_CHECK
31: if (cntxt != In_prmnv) type_check(*pt);
32: #endif
33: set_context(&c);
34: }
35:
36: /* ******************************************************************** */
37:
38: /* Utilities used by threading. */
39:
40: /* A 'threaded tree' is, in our case, a fixed(*) parse tree with extra links
41: that are used by the interpreter to determine the execution order.
42: __________
43: (*) 'Fixed' means: processed by 'fix_nodes', which removes UNPARSED
44: nodes and distinguishes TAG nodes into local, global tags etc.
45: fix_nodes also creates the threads, but this is accidental, not
46: essential. For UNPARSED nodes, the threads are actually laid
47: in a second pass through the subtree that was UNPARSED.
48: __________
49:
50: A small example: the parse tree for the expression 'a+b*c' looks like
51:
52: (DYOP,
53: (TAGlocal, "a"),
54: "+",
55: (DYOP,
56: (TAGlocal, "b"),
57: "*",
58: (TAGlocal, "c"))).
59:
60: The required execution order is here:
61:
62: 1) (TAGlocal, "a")
63: 2) (TAGlocal, "b")
64: 3) (TAGlocal, "c")
65: 4) (DYOP, ..., "*", ...)
66: 5) (DYOP, ..., "+", ...)
67:
68: Of course, the result of each operation (if it has a result) is pushed
69: on a stack, and the operands are popped from this same stack. Think of
70: reversed polish notation (well-known by owners of HP pocket calculators).
71:
72: The 'threads' are explicit links from each node to its successor in this
73: execution order. Conditional operations like IF and AND have two threads,
74: one for success and one for failure. Loops can be made by having the
75: thread from the last node of the loop body point to the head of the loop.
76:
77: Threading expressions, locations and simple-commands is easy: recursively
78: thread each of the subtrees, then lay a thread from the last threaded
79: to the current node. Nodes occurring in a 'location' context are
80: marked, so that the interpreter knows when to push a 'location' on
81: the stack.
82:
83: Tests and looping commands cause most of the complexity of the threading
84: utilities. The basic technique is 'backpatching'.
85: Nodes that need a conditional forward jump are chained together in a
86: linked list, and when their destination is reached, all nodes in the
87: chain get its 'address' patched into their secondary thread. There is
88: one such chain, called 'bpchain', which at all times contains those nodes
89: whose secondary destination would be the next generated instruction.
90: This is used by IF, WHILE, test-suites, AND and OR.
91:
92: To generate a loop, both this chain and the last normal instruction
93: (if any) are diverted to the node where the loop continues.
94:
95: For test-suites, we also need to be capable of jumping unconditionally
96: forward (over the remainder of the SELECT-command). This is done by
97: saving both the backpatch chain and the last node visited, and restoring
98: them after the remainder has been processed.
99: */
100:
101: /* Implementation tricks: in order not to show circular lists to 'release',
102: parse tree nodes are generated as compounds where there is room for two
103: more fields than their length indicates.
104: */
105:
106: #define Flag (MkSmallInt(1))
107: /* Flag used to indicate Location or TestRefinement node */
108:
109: Hidden parsetree start; /* First instruction. Picked up by endthreads() */
110:
111: Hidden parsetree last; /* Last visited node */
112:
113: Hidden parsetree bpchain; /* Backpatch chain for conditional goto's */
114: Hidden parsetree *wanthere; /* Chain of requests to return next tree */
115:
116: extern string opcodes[];
117:
118:
119: /* Start threading */
120:
121: Hidden Procedure inithreads() {
122: bpchain= NilTree;
123: wanthere= 0;
124: last= 0;
125: here(&start);
126: }
127:
128: /* Finish threading */
129:
130: Hidden Procedure endthreads(code) parsetree *code; {
131: jumpto(Stop);
132: if (!still_ok) start= NilTree;
133: *code= start;
134: }
135:
136:
137: /* Fill 't' as secondary thread for all nodes in the backpatch chain,
138: leaving the chain empty. */
139:
140: Hidden Procedure backpatch(t) parsetree t; {
141: parsetree u;
142: while (bpchain != NilTree) {
143: u= Thread2(bpchain);
144: Thread2(bpchain)= t;
145: bpchain= u;
146: }
147: }
148:
149: Visible Procedure jumpto(t) parsetree t; {
150: parsetree u;
151: if (!still_ok) return;
152: while (wanthere != 0) {
153: u= *wanthere;
154: *wanthere= t;
155: wanthere= (parsetree*)u;
156: }
157: while (last != NilTree) {
158: u= Thread(last);
159: Thread(last)= t;
160: last= u;
161: }
162: backpatch(t);
163: }
164:
165: Hidden parsetree seterr(n) int n; {
166: return (parsetree)MkSmallInt(n);
167: }
168:
169: /* Visit node 't', and set its secondary thread to 't2'. */
170:
171: Hidden Procedure visit2(t, t2) parsetree t, t2; {
172: if (!still_ok) return;
173: jumpto(t);
174: Thread2(t)= t2;
175: #ifdef DEBUG
176: fprintf(stderr, "\tvisit %s %s\n", opcodes[Nodetype(t)],
177: t2 == NilTree ? "" : "[*]");
178: #endif DEBUG
179: Thread(t)= NilTree;
180: last= t;
181: }
182:
183: /* Visit node 't' */
184:
185: Hidden Procedure visit(t) parsetree t; {
186: visit2(t, NilTree);
187: }
188:
189: /* Visit node 't' and flag it as a location (or test-refinement). */
190:
191: Hidden Procedure lvisit(t) parsetree t; {
192: visit2(t, Flag);
193: }
194:
195: #ifdef NOT_USED
196: Hidden Procedure jumphere(t) parsetree t; {
197: Thread(t)= last;
198: last= t;
199: }
200: #endif
201:
202: /* Add node 't' to the backpatch chain. */
203:
204: Hidden Procedure jump2here(t) parsetree t; {
205: if (!still_ok) return;
206: Thread2(t)= bpchain;
207: bpchain= t;
208: }
209:
210: Hidden Procedure here(pl) parsetree *pl; {
211: if (!still_ok) return;
212: *pl= (parsetree) wanthere;
213: wanthere= pl;
214: }
215:
216: Visible Procedure hold(pl) struct state *pl; {
217: if (!still_ok) return;
218: pl->h_last= last; pl->h_bpchain= bpchain; pl->h_wanthere= wanthere;
219: last= bpchain= NilTree; wanthere= 0;
220: }
221:
222: Visible Procedure let_go(pl) struct state *pl; {
223: parsetree p, *w;
224: if (!still_ok) return;
225: if (last) {
226: for (p= last; Thread(p) != NilTree; p= Thread(p))
227: ;
228: Thread(p)= pl->h_last;
229: }
230: else last= pl->h_last;
231: if (bpchain) {
232: for (p= bpchain; Thread2(p) != NilTree; p= Thread2(p))
233: ;
234: Thread2(p)= pl->h_bpchain;
235: }
236: else bpchain= pl->h_bpchain;
237: if (wanthere) {
238: for (w= wanthere; *w != 0; w= (parsetree*) *w)
239: ;
240: *w= (parsetree) pl->h_wanthere;
241: }
242: else wanthere= pl->h_wanthere;
243: }
244:
245: Hidden bool reachable() {
246: return last != NilTree || bpchain != 0 || wanthere != 0;
247: }
248:
249:
250: /* ******************************************************************** */
251: /* *********************** code generation **************************** */
252: /* ******************************************************************** */
253:
254: Forward bool is_variable();
255: Forward bool is_cmd_ref();
256: Forward value copydef();
257:
258: Visible Procedure fix(pt, flag) parsetree *pt; char flag; {
259: struct state st; value v, function; parsetree t, l1= NilTree;
260: typenode nt; string s; char c; int n, k, len;
261:
262: t= *pt;
263: if (!Is_node(t) || !still_ok) return;
264: nt= Nodetype(t);
265: if (nt < 0 || nt >= NTYPES) syserr(MESS(2200, "fix bad tree"));
266: s= gentab[nt];
267: if (s == NULL) return;
268: n= First_fieldnr;
269: if (flag == 'x') curline= t;
270: while ((c= *s++) != '\0' && still_ok) {
271: switch (c) {
272: case '0':
273: case '1':
274: case '2':
275: case '3':
276: case '4':
277: case '5':
278: case '6':
279: case '7':
280: case '8':
281: case '9':
282: n= (c - '0') + First_fieldnr;
283: break;
284: case 'c':
285: v= *Branch(t, n);
286: if (v != Vnil) {
287: len= Nfields(v);
288: for (k= 0; k < len; ++k)
289: fix(Field(v, k), flag);
290: }
291: ++n;
292: break;
293: case '#':
294: curlino= *Branch(t, n);
295: ++n;
296: break;
297: case 'g':
298: case 'h':
299: ++n;
300: break;
301: case 'a':
302: case 'l':
303: if (flag == 'v' || flag == 't')
304: c= flag;
305: /* Fall through */
306: case '!':
307: case 't':
308: case 'u':
309: case 'v':
310: case 'x':
311: fix(Branch(t, n), c);
312: ++n;
313: break;
314: case 'f':
315: f_fpr_formals(*Branch(t, n));
316: ++n;
317: break;
318:
319: case '?':
320: if (flag == 'v')
321: f_eunparsed(pt);
322: else if (flag == 't')
323: f_cunparsed(pt);
324: else
325: syserr(MESS(2201, "fix unparsed with bad flag"));
326: fix(pt, flag);
327: break;
328: case 'C':
329: v= *Branch(t, REL_LEFT);
330: if (Comparison(Nodetype(v)))
331: jump2here(v);
332: break;
333: case 'D':
334: v= (value)*Branch(t, DYA_NAME);
335: if (!is_dyafun(v, &function))
336: fixerr2(v, MESS(2202, " isn't a dyadic function"));
337: else
338: *Branch(t, DYA_FCT)= copydef(function);
339: break;
340: case 'E':
341: v= (value)*Branch(t, DYA_NAME);
342: if (!is_dyaprd(v, &function))
343: fixerr2(v, MESS(2203, " isn't a dyadic predicate"));
344: else
345: *Branch(t, DYA_FCT)= copydef(function);
346: break;
347: case 'G':
348: jumpto(l1);
349: break;
350: case 'H':
351: here(&l1);
352: break;
353: case 'I':
354: if (*Branch(t, n) == NilTree)
355: break;
356: /* Else fall through */
357: case 'J':
358: jump2here(t);
359: break;
360: case 'K':
361: hold(&st);
362: break;
363: case 'L':
364: let_go(&st);
365: break;
366: case 'M':
367: v= (value)*Branch(t, MON_NAME);
368: if (is_variable(v) || !is_monfun(v, &function))
369: fixerr2(v, MESS(2204, " isn't a monadic function"));
370: else
371: *Branch(t, MON_FCT)= copydef(function);
372: break;
373: case 'N':
374: v= (value)*Branch(t, MON_NAME);
375: if (is_variable(v) || !is_monprd(v, &function))
376: fixerr2(v, MESS(2205, " isn't a monadic predicate"));
377: else
378: *Branch(t, MON_FCT)= copydef(function);
379: break;
380: #ifdef REACH
381: case 'R':
382: if (*Branch(t, n) != NilTree && !reachable())
383: fixerr(MESS(2206, "command cannot be reached"));
384: break;
385: #endif
386: case 'S':
387: jumpto(Stop);
388: break;
389: case 'T':
390: if (flag == 't')
391: f_ctag(pt);
392: else if (flag == 'v' || flag == 'x')
393: f_etag(pt);
394: else
395: f_ttag(pt);
396: break;
397: case 'U':
398: f_ucommand(pt);
399: break;
400: case 'V':
401: visit(t);
402: break;
403: case 'X':
404: if (flag == 'a' || flag == 'l' || flag == '!')
405: lvisit(t);
406: else
407: visit(t);
408: break;
409: case 'W':
410: /*!*/ visit2(t, seterr(1));
411: break;
412: case 'Y':
413: if (still_ok && reachable()) {
414: if (nt == YIELD)
415: fixerr(MESS(2207, "YIELD-unit returns no value"));
416: else
417: fixerr(MESS(2208, "TEST-unit reports no outcome"));
418: }
419: break;
420: case 'Z':
421: if (!is_cmd_ref(t) && still_ok && reachable())
422: fixerr(MESS(2209, "refinement returns no value c.q. reports no outcome"));
423: *Branch(t, REF_START)= copy(l1);
424: break;
425: }
426: }
427: }
428:
429: /* ******************************************************************** */
430:
431: Hidden bool is_cmd_ref(t) parsetree t; { /* HACK */
432: value name= *Branch(t, REF_NAME);
433: string s= strval(name);
434: /* return isupper(*s); */
435: return *s <= 'Z' && *s >= 'A';
436: }
437:
438: Visible value copydef(f) value f; {
439: funprd *fpr= Funprd(f);
440: if (fpr->pre == Use) return Vnil;
441: return copy(f);
442: }
443:
444: Hidden bool is_basic_target(v) value v; {
445: return envassoc(formals, v) ||
446: locals != Vnil && envassoc(locals, v) ||
447: envassoc(globals, v) ||
448: envassoc(mysteries, v);
449: }
450:
451: Hidden bool is_variable(v) value v; {
452: value f;
453: return is_basic_target(v) ||
454: envassoc(refinements, v) ||
455: is_zerfun(v, &f);
456: }
457:
458: Hidden bool is_target(p) parsetree p; {
459: value v= *Branch(p, First_fieldnr); int k, len;
460: switch (Nodetype(p)) {
461:
462: case TAG:
463: return is_basic_target(v);
464:
465: case SELECTION:
466: case BEHEAD:
467: case CURTAIL:
468: case COMPOUND:
469: return is_target(v);
470:
471: case COLLATERAL:
472: len= Nfields(v);
473: k_Overfields {
474: if (!is_target(*Field(v, k))) return No;
475: }
476: return Yes;
477:
478: default:
479: return No;
480:
481: }
482: }
483:
484: /* ******************************************************************** */
485:
486: Hidden Procedure f_actuals(formals, pactuals) parsetree formals, *pactuals; {
487: /* name, actual, next */
488: value actuals= *pactuals, act, form, next_a, next_f, kw, *pact;
489: kw= *Branch(actuals, ACT_KEYW);
490: pact= Branch(actuals, ACT_EXPR); act= *pact;
491: form= *Branch(formals, FML_TAG);
492: next_a= *Branch(actuals, ACT_NEXT); next_f= *Branch(formals, FML_NEXT);
493: if (compare(*Branch(formals, FML_KEYW), kw) != 0)
494: fixerr3(MESS(2210, "wrong keyword "), kw, 0);
495: else if (act == Vnil && form != Vnil)
496: fixerr3(MESS(2211, "missing actual after "), kw, 0);
497: else if (next_a == Vnil && next_f != Vnil)
498: fixerr3(MESS(2212, "can't find expected "),
499: *Branch(next_f, FML_KEYW), 0);
500: else if (act != Vnil && form == Vnil)
501: fixerr3(MESS(2213, "unexpected actual after "), kw, 0);
502: else if (next_a != Vnil && next_f == Vnil)
503: fixerr3(MESS(2214, "unexpected keyword "),
504: *Branch(next_a, ACT_KEYW), 0);
505: else {
506: if (act != Vnil) {
507: parsetree st; struct state save;
508: hold(&save); here(&st);
509: if (is_target(act)) f_targ(pact);
510: else f_expr(pact);
511: jumpto(Stop); let_go(&save);
512: *Branch(actuals, ACT_START)= copy(st);
513: }
514: if (still_ok && next_a != Vnil)
515: f_actuals(next_f, Branch(actuals, ACT_NEXT));
516: }
517: }
518:
519: Hidden Procedure f_ucommand(pt) parsetree *pt; {
520: value t= *pt, *aa;
521: parsetree u, *f1= Branch(t, UCMD_NAME), *f2= Branch(t, UCMD_ACTUALS);
522: release(*Branch(t, UCMD_DEF));
523: *Branch(t, UCMD_DEF)= Vnil;
524: if ((aa= envassoc(refinements, *f1)) != Pnil) {
525: if (*Branch(*f2, ACT_EXPR) != Vnil
526: || *Branch(*f2, ACT_NEXT) != Vnil)
527: fixerr(MESS(2215, "refinement with parameters"));
528: else *Branch(t, UCMD_DEF)= copy(*aa);
529: }
530: else if (is_unit(*f1, How, &aa)) {
531: u= How_to(*aa)->unit;
532: f_actuals(*Branch(u, HOW_FORMALS), f2);
533: }
534: else if (still_ok)
535: fixerr3(MESS(2216, "you haven't told me HOW'TO "), *f1, 0);
536: }
537:
538: Hidden Procedure f_fpr_formals(t) parsetree t; {
539: switch (Nodetype(t)) {
540: case TAG:
541: break;
542: case MONF: case MONPRD:
543: f_targ(Branch(t, MON_RIGHT));
544: break;
545: case DYAF: case DYAPRD:
546: f_targ(Branch(t, DYA_LEFT));
547: f_targ(Branch(t, DYA_RIGHT));
548: break;
549: default:
550: syserr(MESS(2217, "f_fpr_formals"));
551: }
552: }
553:
554: Visible bool modify_tag(name, tag) parsetree *tag; value name; {
555: value *aa, function;
556: *tag= NilTree;
557: if (aa= envassoc(formals, name))
558: *tag= node3(TAGformal, name, copy(*aa));
559: else if (locals != Vnil && (aa= envassoc(locals, name)))
560: *tag= node3(TAGlocal, name, copy(*aa));
561: else if (aa= envassoc(globals, name))
562: *tag= node2(TAGglobal, name);
563: else if (aa= envassoc(mysteries, name))
564: *tag= node3(TAGmystery, name, copy(*aa));
565: else if (aa= envassoc(refinements, name))
566: *tag= node3(TAGrefinement, name, copy(*aa));
567: else if (is_zerfun(name, &function))
568: *tag= node3(TAGzerfun, name, copydef(function));
569: else if (is_zerprd(name, &function))
570: *tag= node3(TAGzerprd, name, copydef(function));
571: else return No;
572: return Yes;
573: }
574:
575: Hidden Procedure f_etag(pt) parsetree *pt; {
576: parsetree t= *pt; value name= copy(*Branch(t, TAG_NAME));
577: if (modify_tag(name, &t)) {
578: release(*pt);
579: *pt= t;
580: if (Nodetype(t) == TAGzerprd)
581: fixerr2(name, MESS(2218, " cannot be used in an expression"));
582: else
583: visit(t);
584: } else {
585: fixerr2(name, MESS(2219, " has not yet received a value"));
586: release(name);
587: }
588: }
589:
590: Hidden Procedure f_ttag(pt) parsetree *pt; {
591: parsetree t= *pt; value name= copy(*Branch(t, TAG_NAME));
592: if (modify_tag(name, &t)) {
593: release(*pt);
594: *pt= t;
595: switch (Nodetype(t)) {
596: case TAGrefinement:
597: fixerr(MESS(2220, "a refinement may not be used as a target"));
598: break;
599: case TAGzerfun:
600: case TAGzerprd:
601: fixerr2(name, MESS(2221, " hasn't been initialised or defined"));
602: break;
603: default:
604: lvisit(t);
605: break;
606: }
607: } else {
608: fixerr2(name, MESS(2222, " hasn't been initialised or defined"));
609: release(name);
610: }
611: }
612:
613: Hidden Procedure f_ctag(pt) parsetree *pt; {
614: parsetree t= *pt; value name= copy(*Branch(t, TAG_NAME));
615: if (modify_tag(name, &t)) {
616: release(*pt);
617: *pt= t;
618: switch (Nodetype(t)) {
619: case TAGrefinement:
620: lvisit(t); /* 'Loc' flag here means 'Test' */
621: break;
622: case TAGzerprd:
623: visit(t);
624: break;
625: default:
626: fixerr2(name, MESS(2223, " is neither a refined test nor a zeroadic predicate"));
627: break;
628: }
629: } else {
630: fixerr2(name, MESS(2224, " is neither a refined test nor a zeroadic predicate"));
631: release(name);
632: }
633: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.