|
|
1.1 ! root 1: /* ! 2: * Routines for constructing and traversing parse trees and generating code. ! 3: */ ! 4: ! 5: #include "itran.h" ! 6: #include "token.h" ! 7: #include "tree.h" ! 8: #include "code.h" ! 9: #include "sym.h" ! 10: ! 11: static int nextlab; /* next label allocated by alclab() */ ! 12: ! 13: /* ! 14: * tree[1-7] construct parse tree nodes with specified values. tfree ! 15: * points at the next free word in the parse tree space. Nodes are ! 16: * built by copying argument values into successive locations starting ! 17: * at tfree. Parameters a and b are line and column information, ! 18: * while parameters c through f are values to be assigned to n_field[0-3]. ! 19: * Note that this could be done with a single routine; a separate routine ! 20: * for each node size is used for speed and simplicity. ! 21: */ ! 22: ! 23: nodeptr tree1(type) ! 24: int type; ! 25: { ! 26: register nodeptr t; ! 27: ! 28: t = tfree; ! 29: tfree = (nodeptr) ((int *)tfree + 1); ! 30: if (tfree > tend) ! 31: syserr("out of tree space"); ! 32: t->n_type = type; ! 33: return (t); ! 34: } ! 35: ! 36: nodeptr tree3(type, a, b) ! 37: int type, a, b; ! 38: { ! 39: register nodeptr t; ! 40: ! 41: t = tfree; ! 42: tfree = (nodeptr) ((int *)tfree + 3); ! 43: if (tfree > tend) ! 44: syserr("out of tree space"); ! 45: t->n_type = type; ! 46: t->n_line = a; ! 47: t->n_col = b; ! 48: return (t); ! 49: } ! 50: ! 51: nodeptr tree4(type, a, b, c) ! 52: int type, a, b, c; ! 53: { ! 54: register nodeptr t; ! 55: ! 56: t = tfree; ! 57: tfree = (nodeptr) ((int *)tfree + 4); ! 58: if (tfree > tend) ! 59: syserr("out of tree space"); ! 60: t->n_type = type; ! 61: t->n_line = a; ! 62: t->n_col = b; ! 63: t->n_field[0].n_val = c; ! 64: return (t); ! 65: } ! 66: ! 67: nodeptr tree5(type, a, b, c, d) ! 68: int type, a, b, c, d; ! 69: { ! 70: register nodeptr t; ! 71: ! 72: t = tfree; ! 73: tfree = (nodeptr) ((int *)tfree + 5); ! 74: if (tfree > tend) ! 75: syserr("out of tree space"); ! 76: t->n_type = type; ! 77: t->n_line = a; ! 78: t->n_col = b; ! 79: t->n_field[0].n_val = c; ! 80: t->n_field[1].n_val = d; ! 81: return (t); ! 82: } ! 83: ! 84: nodeptr tree6(type, a, b, c, d, e) ! 85: int type, a, b, c, d, e; ! 86: { ! 87: register nodeptr t; ! 88: ! 89: t = tfree; ! 90: tfree = (nodeptr) ((int *)tfree + 6); ! 91: if (tfree > tend) ! 92: syserr("out of tree space"); ! 93: t->n_type = type; ! 94: t->n_line = a; ! 95: t->n_col = b; ! 96: t->n_field[0].n_val = c; ! 97: t->n_field[1].n_val = d; ! 98: t->n_field[2].n_val = e; ! 99: return (t); ! 100: } ! 101: ! 102: nodeptr tree7(type, a, b, c, d, e, f) ! 103: int type, a, b, c, d, e, f; ! 104: { ! 105: register nodeptr t; ! 106: ! 107: t = tfree; ! 108: tfree = (nodeptr) ((int *)tfree + 7); ! 109: if (tfree > tend) ! 110: syserr("out of tree space"); ! 111: t->n_type = type; ! 112: t->n_line = a; ! 113: t->n_col = b; ! 114: t->n_field[0].n_val = c; ! 115: t->n_field[1].n_val = d; ! 116: t->n_field[2].n_val = e; ! 117: t->n_field[3].n_val = f; ! 118: return (t); ! 119: } ! 120: ! 121: /* ! 122: * Clear the tree space by setting the free pointer back to the first word ! 123: * of the tree space. ! 124: */ ! 125: ! 126: treeinit() ! 127: { ! 128: tfree = tree; ! 129: } ! 130: ! 131: /* ! 132: * codegen - traverse tree t, generating code. ! 133: */ ! 134: ! 135: codegen(t) ! 136: nodeptr t; ! 137: { ! 138: nextlab = 1; ! 139: traverse(t); ! 140: } ! 141: ! 142: /* ! 143: * traverse - traverse tree rooted at t and generate code. This is just ! 144: * plug and chug code for each of the node types. The tour goes into ! 145: * some detail about the code generation process, in particular, Appendix ! 146: * A describes the parse tree nodes. ! 147: */ ! 148: ! 149: traverse(t) ! 150: register nodeptr t; ! 151: { ! 152: register int lab, n; ! 153: struct loopstk loopsave; ! 154: static struct loopstk loopstk[LOOPDEPTH]; /* loop stack */ ! 155: static struct loopstk *loopsp; ! 156: static struct casestk casestk[CASEDEPTH]; /* case stack */ ! 157: static struct casestk *casesp; ! 158: static struct creatstk creatstk[CREATDEPTH]; /* create stack */ ! 159: static struct creatstk *creatsp; ! 160: ! 161: n = 1; ! 162: switch (TYPE(t)) { ! 163: ! 164: case N_ACTIVAT: /* co-expression activation */ ! 165: if (VAL0(TREE0(t)) == AUGACT) ! 166: emit("pnull"); ! 167: traverse(TREE2(t)); /* evaluate result expression */ ! 168: if (VAL0(TREE0(t)) == AUGACT) ! 169: emit("sdup"); ! 170: traverse(TREE1(t)); /* evaluate activate expression */ ! 171: setline(LINE(t)); ! 172: emit("coact"); ! 173: if (VAL0(TREE0(t)) == AUGACT) ! 174: emit("asgn"); ! 175: break; ! 176: ! 177: case N_ALT: /* alternation */ ! 178: lab = alclab(2); ! 179: emitl("mark", lab); ! 180: loopsp->markcount++; ! 181: traverse(TREE0(t)); /* evaluate first alternative */ ! 182: loopsp->markcount--; ! 183: emit("esusp"); /* and suspend with its result */ ! 184: emitl("goto", lab+1); ! 185: emitlab(lab); ! 186: traverse(TREE1(t)); /* evaluate second alternative */ ! 187: emitlab(lab+1); ! 188: break; ! 189: ! 190: case N_AUGOP: /* augmented assignment */ ! 191: case N_BINOP: /* or a binary operator */ ! 192: emit("pnull"); ! 193: traverse(TREE1(t)); ! 194: if (TYPE(t) == N_AUGOP) ! 195: emit("dup"); ! 196: traverse(TREE2(t)); ! 197: setline(LINE(t)); ! 198: binop(VAL0(TREE0(t))); ! 199: break; ! 200: ! 201: case N_BAR: /* repeated alternation */ ! 202: lab = alclab(1); ! 203: emitlab(lab); ! 204: emitl("mark", 0); /* fail if expr fails first time */ ! 205: loopsp->markcount++; ! 206: traverse(TREE0(t)); /* evaluate first alternative */ ! 207: loopsp->markcount--; ! 208: emitl("chfail", lab); /* change to loop on failure */ ! 209: emit("esusp"); /* suspend result */ ! 210: break; ! 211: ! 212: case N_BREAK: /* break expression */ ! 213: if (loopsp->breaklab <= 0) ! 214: lerr(LINE(t), "invalid context for break"); ! 215: else { ! 216: emitn("unmark", loopsp->markcount); ! 217: loopsave = *loopsp--; ! 218: traverse(TREE0(t)); ! 219: *++loopsp = loopsave; ! 220: emitl("goto", loopsp->breaklab); ! 221: } ! 222: break; ! 223: ! 224: case N_CASE: /* case expression */ ! 225: lab = alclab(1); ! 226: casesp++; ! 227: casesp->endlab = lab; ! 228: casesp->deftree = NULL; ! 229: emitl("mark", 0); ! 230: loopsp->markcount++; ! 231: traverse(TREE0(t)); /* evaluate control expression */ ! 232: loopsp->markcount--; ! 233: emit("eret"); ! 234: traverse(TREE1(t)); /* do rest of case (CLIST) */ ! 235: if (casesp->deftree != NULL) { /* evaluate default clause */ ! 236: emit("pop"); ! 237: traverse(casesp->deftree); ! 238: } ! 239: else ! 240: emit("efail"); ! 241: emitlab(lab); /* end label */ ! 242: casesp--; ! 243: break; ! 244: ! 245: case N_CCLS: /* case expression clause */ ! 246: if (TYPE(TREE0(t)) == N_RES && /* default clause */ ! 247: VAL0(TREE0(t)) == DEFAULT) { ! 248: if (casesp->deftree != NULL) ! 249: lerr(LINE(t), "more than one default clause"); ! 250: else ! 251: casesp->deftree = TREE1(t); ! 252: } ! 253: else { /* case clause */ ! 254: lab = alclab(1); ! 255: emitl("mark", lab); ! 256: loopsp->markcount++; ! 257: emit("ccase"); ! 258: traverse(TREE0(t)); /* evaluate selector */ ! 259: setline(LINE(t)); ! 260: emit("eqv"); ! 261: loopsp->markcount--; ! 262: emitn("unmark", 1); ! 263: emit("pop"); ! 264: traverse(TREE1(t)); /* evaluate expression */ ! 265: emitl("goto", casesp->endlab); /* goto end label */ ! 266: emitlab(lab); /* label for next clause */ ! 267: } ! 268: break; ! 269: ! 270: case N_CLIST: /* list of case clauses */ ! 271: traverse(TREE0(t)); ! 272: traverse(TREE1(t)); ! 273: break; ! 274: ! 275: case N_CONJ: /* conjunction */ ! 276: if (VAL0(TREE0(t)) == AUGAND) ! 277: emit("pnull"); ! 278: traverse(TREE1(t)); ! 279: if (VAL0(TREE0(t)) != AUGAND) ! 280: emit("pop"); ! 281: traverse(TREE2(t)); ! 282: if (VAL0(TREE0(t)) == AUGAND) ! 283: emit("asgn"); ! 284: break; ! 285: ! 286: case N_CREATE: /* create expression */ ! 287: creatsp++; ! 288: creatsp->nextlab = loopsp->nextlab; ! 289: creatsp->breaklab = loopsp->breaklab; ! 290: loopsp->nextlab = 0; /* make break and next illegal */ ! 291: loopsp->breaklab = 0; ! 292: lab = alclab(3); ! 293: emitl("goto", lab+2); /* skip over code for coexpression */ ! 294: emitlab(lab); /* entry point */ ! 295: emit("pop"); /* pop the result from activation */ ! 296: emitl("mark", lab+1); ! 297: loopsp->markcount++; ! 298: traverse(TREE0(t)); /* traverse code for coexpression */ ! 299: loopsp->markcount--; ! 300: emit("incres"); /* increment number of results */ ! 301: setline(LINE(t)); ! 302: emit("coret"); /* return to activator */ ! 303: emit("efail"); /* drive coexpression */ ! 304: emitlab(lab+1); /* loop on exhaustion */ ! 305: setline(0); ! 306: setline(LINE(t)); ! 307: emit("cofail"); /* and fail each time */ ! 308: emitl("goto", lab+1); ! 309: emitlab(lab+2); ! 310: setline(0); ! 311: setline(LINE(t)); ! 312: emitl("create", lab); /* create entry block */ ! 313: loopsp->nextlab = creatsp->nextlab; /* legalize break and next */ ! 314: loopsp->breaklab = creatsp->breaklab; ! 315: creatsp--; ! 316: break; ! 317: ! 318: case N_CSET: /* cset literal */ ! 319: emitn("cset", VAL0(t)); ! 320: break; ! 321: ! 322: case N_ELIST: /* expression list */ ! 323: n = traverse(TREE0(t)); ! 324: n += traverse(TREE1(t)); ! 325: break; ! 326: ! 327: case N_EMPTY: /* a missing expression */ ! 328: emit("pnull"); ! 329: break; ! 330: ! 331: case N_FIELD: /* field reference */ ! 332: emit("pnull"); ! 333: traverse(TREE0(t)); ! 334: setline(LINE(t)); ! 335: emits("field", STR0(TREE1(t))); ! 336: break; ! 337: ! 338: case N_ID: /* identifier */ ! 339: emitn("var", VAL0(t)); ! 340: break; ! 341: ! 342: case N_IF: /* if expression */ ! 343: if (TYPE(TREE2(t)) == N_EMPTY) ! 344: lab = 0; ! 345: else ! 346: lab = alclab(2); ! 347: emitl("mark", lab); ! 348: loopsp->markcount++; ! 349: traverse(TREE0(t)); ! 350: loopsp->markcount--; ! 351: emitn("unmark", 1); ! 352: traverse(TREE1(t)); ! 353: if (lab > 0) { ! 354: emitl("goto", lab+1); ! 355: emitlab(lab); ! 356: traverse(TREE2(t)); ! 357: emitlab(lab+1); ! 358: } ! 359: break; ! 360: ! 361: case N_INT: /* integer literal */ ! 362: emitn("int", VAL0(t)); ! 363: break; ! 364: ! 365: case N_INVOK: /* procedure call, possibly MGDE */ ! 366: if (TYPE(TREE0(t)) != N_EMPTY) ! 367: traverse(TREE0(t)); ! 368: else ! 369: emit("pushn1"); /* assume -1(e1,...,en) */ ! 370: n = traverse(TREE1(t)); ! 371: setline(LINE(t)); ! 372: emitn("invoke", n); ! 373: n = 1; ! 374: break; ! 375: ! 376: case N_KEY: /* keyword reference */ ! 377: setline(LINE(t)); ! 378: emitn("keywd", VAL0(t)); ! 379: break; ! 380: ! 381: case N_LIMIT: /* limitation */ ! 382: traverse(TREE1(t)); ! 383: setline(LINE(t)); ! 384: emit("limit"); ! 385: emitl("mark", 0); ! 386: loopsp->markcount++; ! 387: traverse(TREE0(t)); ! 388: loopsp->markcount--; ! 389: emit("lsusp"); ! 390: break; ! 391: ! 392: case N_LIST: /* list construction */ ! 393: emit("pnull"); ! 394: if (TYPE(TREE0(t)) == N_EMPTY) ! 395: n = 0; ! 396: else ! 397: n = traverse(TREE0(t)); ! 398: setline(LINE(t)); ! 399: emitn("llist", n); ! 400: n = 1; ! 401: break; ! 402: ! 403: case N_LOOP: /* loop */ ! 404: switch (VAL0(TREE0(t))) { ! 405: case EVERY: ! 406: lab = alclab(2); ! 407: loopsp++; ! 408: loopsp->ltype = EVERY; ! 409: loopsp->nextlab = lab; ! 410: loopsp->breaklab = lab + 1; ! 411: loopsp->markcount = 1; ! 412: emitl("mark", 0); ! 413: traverse(TREE1(t)); ! 414: emit("pop"); ! 415: if (TYPE(TREE2(t)) != N_EMPTY) { /* every e1 do e2 */ ! 416: emitl("mark", 0); ! 417: loopsp->ltype = N_LOOP; ! 418: loopsp->markcount++; ! 419: traverse(TREE2(t)); ! 420: loopsp->markcount--; ! 421: emitn("unmark", 1); ! 422: } ! 423: emitlab(loopsp->nextlab); ! 424: emit("efail"); ! 425: emitlab(loopsp->breaklab); ! 426: loopsp--; ! 427: break; ! 428: ! 429: case REPEAT: ! 430: lab = alclab(3); ! 431: loopsp++; ! 432: loopsp->ltype = N_LOOP; ! 433: loopsp->nextlab = lab + 1; ! 434: loopsp->breaklab = lab + 2; ! 435: loopsp->markcount = 1; ! 436: emitlab(lab); ! 437: setline(0); ! 438: setline(LINE(t)); ! 439: emitl("mark", lab); ! 440: traverse(TREE1(t)); ! 441: emitlab(loopsp->nextlab); ! 442: emitn("unmark", 1); ! 443: emitl("goto", lab); ! 444: emitlab(loopsp->breaklab); ! 445: loopsp--; ! 446: break; ! 447: ! 448: case WHILE: ! 449: lab = alclab(3); ! 450: loopsp++; ! 451: loopsp->ltype = N_LOOP; ! 452: loopsp->nextlab = lab + 1; ! 453: loopsp->breaklab = lab + 2; ! 454: loopsp->markcount = 1; ! 455: emitlab(lab); ! 456: setline(0); ! 457: setline(LINE(t)); ! 458: emitl("mark", 0); ! 459: traverse(TREE1(t)); ! 460: if (TYPE(TREE2(t)) != N_EMPTY) { ! 461: emitn("unmark", 1); ! 462: emitl("mark", lab); ! 463: traverse(TREE2(t)); ! 464: } ! 465: emitlab(loopsp->nextlab); ! 466: emitn("unmark", 1); ! 467: emitl("goto", lab); ! 468: emitlab(loopsp->breaklab); ! 469: loopsp--; ! 470: break; ! 471: ! 472: case UNTIL: ! 473: lab = alclab(4); ! 474: loopsp++; ! 475: loopsp->ltype = N_LOOP; ! 476: loopsp->nextlab = lab + 2; ! 477: loopsp->breaklab = lab + 3; ! 478: loopsp->markcount = 1; ! 479: emitlab(lab); ! 480: setline(0); ! 481: setline(LINE(t)); ! 482: emitl("mark", lab+1); ! 483: traverse(TREE1(t)); ! 484: emitn("unmark", 1); ! 485: emit("efail"); ! 486: emitlab(lab+1); ! 487: emitl("mark", lab); ! 488: traverse(TREE2(t)); ! 489: emitlab(loopsp->nextlab); ! 490: emitn("unmark", 1); ! 491: emitl("goto", lab); ! 492: emitlab(loopsp->breaklab); ! 493: loopsp--; ! 494: break; ! 495: } ! 496: break; ! 497: ! 498: case N_NEXT: /* next expression */ ! 499: if (loopsp < loopstk || loopsp->nextlab <= 0) ! 500: lerr(LINE(t), "invalid context for next"); ! 501: else { ! 502: if (loopsp->ltype != EVERY && loopsp->markcount > 1) ! 503: emitn("unmark", loopsp->markcount - 1); ! 504: emitl("goto", loopsp->nextlab); ! 505: } ! 506: break; ! 507: ! 508: case N_NOT: /* not expression */ ! 509: lab = alclab(1); ! 510: emitl("mark", lab); ! 511: loopsp->markcount++; ! 512: traverse(TREE0(t)); ! 513: loopsp->markcount--; ! 514: emitn("unmark", 1); ! 515: emit("efail"); ! 516: emitlab(lab); ! 517: emit("pnull"); ! 518: break; ! 519: ! 520: case N_PROC: /* procedure */ ! 521: loopsp = loopstk; ! 522: loopsp->nextlab = 0; ! 523: loopsp->breaklab = 0; ! 524: loopsp->markcount = 0; ! 525: casesp = casestk; ! 526: creatsp = creatstk; ! 527: fprintf(codefile, "proc %s\n", STR0(TREE0(t))); ! 528: lout(codefile); ! 529: cout(codefile); ! 530: emit("declend"); ! 531: emits("file", *filep); ! 532: setline(0); ! 533: setline(LINE(t)); ! 534: if (TYPE(TREE1(t)) != N_EMPTY) { ! 535: lab = alclab(1); ! 536: emitl("init?", lab); ! 537: emitl("mark", lab); ! 538: traverse(TREE1(t)); ! 539: emitn("unmark", 1); ! 540: emitlab(lab); ! 541: } ! 542: if (TYPE(TREE2(t)) != N_EMPTY) ! 543: traverse(TREE2(t)); ! 544: setline(LINE(TREE3(t))); ! 545: emit("pfail"); ! 546: emit("end"); ! 547: if (!silence) ! 548: fprintf(stderr, " %s (%d/%d)\n", STR0(TREE0(t)), ! 549: (int *)tfree - (int *)tree, tsize); ! 550: break; ! 551: ! 552: case N_REAL: /* real literal */ ! 553: emitn("real", VAL0(t)); ! 554: break; ! 555: ! 556: case N_RET: /* return expression */ ! 557: if (creatsp > creatstk) ! 558: lerr(LINE(t), "invalid context for return or fail"); ! 559: if (VAL0(TREE0(t)) != FAIL) { ! 560: lab = alclab(1); ! 561: emitl("mark", lab); ! 562: loopsp->markcount++; ! 563: traverse(TREE1(t)); ! 564: loopsp->markcount--; ! 565: setline(LINE(t)); ! 566: emit("pret"); ! 567: emitlab(lab); ! 568: } ! 569: setline(0); ! 570: setline(LINE(t)); ! 571: emit("pfail"); ! 572: break; ! 573: ! 574: case N_SCAN: /* scanning expression */ ! 575: if (VAL0(TREE0(t)) == SCANASGN) ! 576: emit("pnull"); ! 577: traverse(TREE1(t)); ! 578: if (VAL0(TREE0(t)) == SCANASGN) ! 579: emit("sdup"); ! 580: setline(LINE(t)); ! 581: emit("bscan"); ! 582: traverse(TREE2(t)); ! 583: setline(LINE(t)); ! 584: emit("escan"); ! 585: if (VAL0(TREE0(t)) == SCANASGN) ! 586: emit("asgn"); ! 587: break; ! 588: ! 589: case N_SECT: /* section operation */ ! 590: emit("pnull"); ! 591: traverse(TREE1(t)); ! 592: traverse(TREE2(t)); ! 593: if (VAL0(TREE0(t)) == PCOLON || VAL0(TREE0(t)) == MCOLON) ! 594: emit("dup"); ! 595: traverse(TREE3(t)); ! 596: setline(LINE(TREE0(t))); ! 597: if (VAL0(TREE0(t)) == PCOLON) ! 598: emit("plus"); ! 599: else if (VAL0(TREE0(t)) == MCOLON) ! 600: emit("minus"); ! 601: setline(LINE(t)); ! 602: emit("sect"); ! 603: break; ! 604: ! 605: case N_SLIST: /* semicolon separated list of expressions */ ! 606: lab = alclab(1); ! 607: emitl("mark", lab); ! 608: loopsp->markcount++; ! 609: traverse(TREE0(t)); ! 610: loopsp->markcount--; ! 611: emitn("unmark", 1); ! 612: emitlab(lab); ! 613: traverse(TREE1(t)); ! 614: break; ! 615: ! 616: case N_STR: /* string literal */ ! 617: emitn("str", VAL0(t)); ! 618: break; ! 619: ! 620: case N_SUSP: /* suspension expression */ ! 621: if (creatsp > creatstk) ! 622: lerr(LINE(t), "invalid context for suspend"); ! 623: emitl("mark", 0); ! 624: loopsp->markcount++; ! 625: traverse(TREE0(t)); ! 626: loopsp->markcount--; ! 627: setline(LINE(t)); ! 628: emit("psusp"); ! 629: emit("efail"); ! 630: break; ! 631: ! 632: case N_TO: /* to expression */ ! 633: emit("pnull"); ! 634: traverse(TREE0(t)); ! 635: traverse(TREE1(t)); ! 636: emit("push1"); ! 637: setline(LINE(t)); ! 638: emit("toby"); ! 639: break; ! 640: ! 641: case N_TOBY: /* to-by expression */ ! 642: emit("pnull"); ! 643: traverse(TREE0(t)); ! 644: traverse(TREE1(t)); ! 645: traverse(TREE2(t)); ! 646: setline(LINE(t)); ! 647: emit("toby"); ! 648: break; ! 649: ! 650: case N_UNOP: /* unary operator */ ! 651: unopa(VAL0(TREE0(t))); ! 652: traverse(TREE1(t)); ! 653: setline(LINE(t)); ! 654: unopb(VAL0(TREE0(t))); ! 655: break; ! 656: ! 657: default: ! 658: emitn("?????", TYPE(t)); ! 659: syserr("traverse: undefined node type"); ! 660: } ! 661: return (n); ! 662: } ! 663: /* ! 664: * binop emits code for binary operators. For non-augmented operators, ! 665: * the name of operator is emitted. For augmented operators, an "asgn" ! 666: * is emitted after the name of the operator. ! 667: */ ! 668: binop(op) ! 669: int op; ! 670: { ! 671: register int asgn; ! 672: register char *name; ! 673: ! 674: asgn = 0; ! 675: switch (op) { ! 676: ! 677: case ASSIGN: ! 678: name = "asgn"; ! 679: break; ! 680: ! 681: case CARETASGN: ! 682: asgn++; ! 683: case CARET: ! 684: name = "power"; ! 685: break; ! 686: ! 687: case CONCATASGN: ! 688: asgn++; ! 689: case CONCAT: ! 690: name = "cat"; ! 691: break; ! 692: ! 693: case DIFFASGN: ! 694: asgn++; ! 695: case DIFF: ! 696: name = "diff"; ! 697: break; ! 698: ! 699: case AUGEQV: ! 700: asgn++; ! 701: case EQUIV: ! 702: name = "eqv"; ! 703: break; ! 704: ! 705: case INTERASGN: ! 706: asgn++; ! 707: case INTER: ! 708: name = "inter"; ! 709: break; ! 710: ! 711: case LBRACK: ! 712: name = "subsc"; ! 713: break; ! 714: ! 715: case LCONCATASGN: ! 716: asgn++; ! 717: case LCONCAT: ! 718: name = "lconcat"; ! 719: break; ! 720: ! 721: case AUGSEQ: ! 722: asgn++; ! 723: case LEXEQ: ! 724: name = "lexeq"; ! 725: break; ! 726: ! 727: case AUGSGE: ! 728: asgn++; ! 729: case LEXGE: ! 730: name = "lexge"; ! 731: break; ! 732: ! 733: case AUGSGT: ! 734: asgn++; ! 735: case LEXGT: ! 736: name = "lexgt"; ! 737: break; ! 738: ! 739: case AUGSLE: ! 740: asgn++; ! 741: case LEXLE: ! 742: name = "lexle"; ! 743: break; ! 744: ! 745: case AUGSLT: ! 746: asgn++; ! 747: case LEXLT: ! 748: name = "lexlt"; ! 749: break; ! 750: ! 751: case AUGSNE: ! 752: asgn++; ! 753: case LEXNE: ! 754: name = "lexne"; ! 755: break; ! 756: ! 757: case MINUSASGN: ! 758: asgn++; ! 759: case MINUS: ! 760: name = "minus"; ! 761: break; ! 762: ! 763: case MODASGN: ! 764: asgn++; ! 765: case MOD: ! 766: name = "mod"; ! 767: break; ! 768: ! 769: case AUGNEQV: ! 770: asgn++; ! 771: case NOTEQUIV: ! 772: name = "neqv"; ! 773: break; ! 774: ! 775: case AUGEQ: ! 776: asgn++; ! 777: case NUMEQ: ! 778: name = "numeq"; ! 779: break; ! 780: ! 781: case AUGGE: ! 782: asgn++; ! 783: case NUMGE: ! 784: name = "numge"; ! 785: break; ! 786: ! 787: case AUGGT: ! 788: asgn++; ! 789: case NUMGT: ! 790: name = "numgt"; ! 791: break; ! 792: ! 793: case AUGLE: ! 794: asgn++; ! 795: case NUMLE: ! 796: name = "numle"; ! 797: break; ! 798: ! 799: case AUGLT: ! 800: asgn++; ! 801: case NUMLT: ! 802: name = "numlt"; ! 803: break; ! 804: ! 805: case AUGNE: ! 806: asgn++; ! 807: case NUMNE: ! 808: name = "numne"; ! 809: break; ! 810: ! 811: case PLUSASGN: ! 812: asgn++; ! 813: case PLUS: ! 814: name = "plus"; ! 815: break; ! 816: ! 817: case REVASSIGN: ! 818: name = "rasgn"; ! 819: break; ! 820: ! 821: case REVSWAP: ! 822: name = "rswap"; ! 823: break; ! 824: ! 825: case SLASHASGN: ! 826: asgn++; ! 827: case SLASH: ! 828: name = "div"; ! 829: break; ! 830: ! 831: case STARASGN: ! 832: asgn++; ! 833: case STAR: ! 834: name = "mult"; ! 835: break; ! 836: ! 837: case SWAP: ! 838: name = "swap"; ! 839: break; ! 840: ! 841: case UNIONASGN: ! 842: asgn++; ! 843: case UNION: ! 844: name = "unioncs"; ! 845: break; ! 846: ! 847: default: ! 848: emitn("?binop", op); ! 849: syserr("binop: undefined binary operator"); ! 850: } ! 851: emit(name); ! 852: if (asgn) ! 853: emit("asgn"); ! 854: return; ! 855: } ! 856: /* ! 857: * unopa and unopb handle code emission for unary operators. unary operator ! 858: * sequences that are the same as binary operator sequences are recognized ! 859: * by the lexical analyzer as binary operators. For example, ~===x means to ! 860: * do three tab(match(...)) operations and then a cset complement, but the ! 861: * lexical analyzer sees the operator sequence as the "neqv" binary ! 862: * operation. unopa and unopb unravel tokens of this form. ! 863: * ! 864: * When a N_UNOP node is encountered, unopa is called to emit the necessary ! 865: * number of "pnull" operations to receive the intermediate results. This ! 866: * amounts to a pnull for each operation. ! 867: */ ! 868: unopa(op) ! 869: int op; ! 870: { ! 871: switch (op) { ! 872: case NOTEQUIV: /* unary ~ and three = operators */ ! 873: emit("pnull"); ! 874: case LEXNE: /* unary ~ and two = operators */ ! 875: case EQUIV: /* three unary = operators */ ! 876: emit("pnull"); ! 877: case NUMNE: /* unary ~ and = operators */ ! 878: case UNION: /* two unary + operators */ ! 879: case DIFF: /* two unary - operators */ ! 880: case LEXEQ: /* two unary = operators */ ! 881: case INTER: /* two unary * operators */ ! 882: emit("pnull"); ! 883: case DOT: /* unary . operator */ ! 884: case BACKSLASH: /* unary \ operator */ ! 885: case BANG: /* unary ! operator */ ! 886: case CARET: /* unary ^ operator */ ! 887: case PLUS: /* unary + operator */ ! 888: case TILDE: /* unary ~ operator */ ! 889: case MINUS: /* unary - operator */ ! 890: case NUMEQ: /* unary = operator */ ! 891: case STAR: /* unary * operator */ ! 892: case QMARK: /* unary ? operator */ ! 893: case SLASH: /* unary / operator */ ! 894: emit("pnull"); ! 895: break; ! 896: default: ! 897: syserr("unopa: undefined unary operator"); ! 898: } ! 899: return; ! 900: } ! 901: /* ! 902: * unopb is the back-end code emitter for unary operators. It emits ! 903: * the operations represented by the token op. For tokens representing ! 904: * a single operator, the name of the operator is emitted. For tokens ! 905: * representing a sequence of operators, recursive calls are used. In ! 906: * such a case, the operator sequence is "scanned" from right to left ! 907: * and unopb is called with the token for the appropriate operation. ! 908: * ! 909: * For example, consider the sequence of calls and code emission for "~===": ! 910: * unopb(NOTEQUIV) ~=== ! 911: * unopb(NUMEQ) = ! 912: * emits "tabmat" ! 913: * unopb(NUMEQ) = ! 914: * emits "tabmat" ! 915: * unopb(NUMEQ) = ! 916: * emits "tabmat" ! 917: * emits "compl" ! 918: */ ! 919: unopb(op) ! 920: int op; ! 921: { ! 922: register char *name; ! 923: ! 924: switch (op) { ! 925: ! 926: case DOT: /* unary . operator */ ! 927: name = "value"; ! 928: break; ! 929: ! 930: case BACKSLASH: /* unary \ operator */ ! 931: name = "nonnull"; ! 932: break; ! 933: ! 934: case BANG: /* unary ! operator */ ! 935: name = "bang"; ! 936: break; ! 937: ! 938: case CARET: /* unary ^ operator */ ! 939: name = "refresh"; ! 940: break; ! 941: ! 942: case UNION: /* two unary + operators */ ! 943: unopb(PLUS); ! 944: case PLUS: /* unary + operator */ ! 945: name = "number"; ! 946: break; ! 947: ! 948: case NOTEQUIV: /* unary ~ and three = operators */ ! 949: unopb(NUMEQ); ! 950: case LEXNE: /* unary ~ and two = operators */ ! 951: unopb(NUMEQ); ! 952: case NUMNE: /* unary ~ and = operators */ ! 953: unopb(NUMEQ); ! 954: case TILDE: /* unary ~ operator (cset compl) */ ! 955: name = "compl"; ! 956: break; ! 957: ! 958: case DIFF: /* two unary - operators */ ! 959: unopb(MINUS); ! 960: case MINUS: /* unary - operator */ ! 961: name = "neg"; ! 962: break; ! 963: ! 964: case EQUIV: /* three unary = operators */ ! 965: unopb(NUMEQ); ! 966: case LEXEQ: /* two unary = operators */ ! 967: unopb(NUMEQ); ! 968: case NUMEQ: /* unary = operator */ ! 969: name = "tabmat"; ! 970: break; ! 971: ! 972: case INTER: /* two unary * operators */ ! 973: unopb(STAR); ! 974: case STAR: /* unary * operator */ ! 975: name = "size"; ! 976: break; ! 977: ! 978: case QMARK: /* unary ? operator */ ! 979: name = "random"; ! 980: break; ! 981: ! 982: case SLASH: /* unary / operator */ ! 983: name = "null"; ! 984: break; ! 985: ! 986: default: ! 987: emitn("?unop", op); ! 988: syserr("unopb: undefined unary operator"); ! 989: } ! 990: emit(name); ! 991: return; ! 992: } ! 993: ! 994: /* ! 995: * setline emits a "line" instruction for line n. A "line" instruction is not ! 996: * emitted if the last "line" instruction was also for line n. ! 997: */ ! 998: setline(n) ! 999: int n; ! 1000: { ! 1001: static lastline = 0; ! 1002: ! 1003: if (n != lastline) { ! 1004: lastline = n; ! 1005: if (n > 0) ! 1006: emitn("line", n); ! 1007: } ! 1008: } ! 1009: /* ! 1010: * The emit* routines output ucode to codefile. The various routines are: ! 1011: * ! 1012: * emitlab(l) - emit "lab" instruction for label l. ! 1013: * emit(s) - emit instruction s. ! 1014: * emitl(s,a) - emit instruction s with reference to label a. ! 1015: * emitn(s,n) - emit instruction s with numeric operand a. ! 1016: * emitnl(s,a,b) - emit instruction s with numeric operand a and label b. ! 1017: * emits(s,a) - emit instruction s with string operand a. ! 1018: */ ! 1019: emitlab(l) ! 1020: int l; ! 1021: { ! 1022: fprintf(codefile, "lab L%d\n", l); ! 1023: } ! 1024: ! 1025: emit(s) ! 1026: char *s; ! 1027: { ! 1028: fprintf(codefile, "\t%s\n", s); ! 1029: } ! 1030: ! 1031: emitl(s, a) ! 1032: char *s; ! 1033: int a; ! 1034: { ! 1035: fprintf(codefile, "\t%s\tL%d\n", s, a); ! 1036: } ! 1037: ! 1038: emitn(s, a) ! 1039: char *s; ! 1040: int a; ! 1041: { ! 1042: fprintf(codefile, "\t%s\t%d\n", s, a); ! 1043: } ! 1044: ! 1045: emitnl(s, a, b) ! 1046: char *s; ! 1047: int a, b; ! 1048: { ! 1049: fprintf(codefile, "\t%s\t%d,L%d\n", s, a, b); ! 1050: } ! 1051: ! 1052: emits(s, a) ! 1053: char *s, *a; ! 1054: { ! 1055: fprintf(codefile, "\t%s\t%s\n", s, a); ! 1056: } ! 1057: /* ! 1058: * alclab allocates n labels and returns the first. For the interpreter, ! 1059: * labels are restarted at 1 for each procedure, while in the compiler, ! 1060: * they start at 1 and increase throughout the entire compilation. ! 1061: */ ! 1062: alclab(n) ! 1063: int n; ! 1064: { ! 1065: register int lab; ! 1066: ! 1067: lab = nextlab; ! 1068: nextlab += n; ! 1069: return (lab); ! 1070: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.