|
|
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.