/* @(#)case.c 2.3 SCCS id keyword */ /* Copyright (c) 1979 Regents of the University of California */ # /* * pi - Pascal interpreter code translator * * Charles Haley, Bill Joy UCB * Version 1.2 November 1978 */ #include "whoami" #include "0.h" #include "tree.h" #include "opcode.h" /* * The structure used to * hold information about * each case label. */ struct ct { long clong; int cline; }; /* * Caseop generates the * pascal case statement code */ caseop(r) int *r; { register struct nl *p; register struct ct *ctab; register *cs; int *cl; double low, high; short *brtab; char *brtab0; char *csend; int w, i, j, m, n; int nr, goc; goc = gocnt; /* * Obtain selector attributes: * p type * w width * low lwb(p) * high upb(p) */ p = rvalue((int *) r[2], NLNIL); if (p != NIL) { if (isnta(p, "bcsi")) { error("Case selectors cannot be %ss", nameof(p)); p = NIL; } else { cl = p; if (p->class != RANGE) cl = p->type; if (cl == NIL) p = NIL; else { w = width(p); #ifdef DEBUG if (hp21mx) w = 2; #endif low = cl->range[0]; high = cl->range[1]; } } } /* * Count # of cases */ n = 0; for (cl = r[3]; cl != NIL; cl = cl[2]) { cs = cl[1]; if (cs == NIL) continue; for (cs = cs[2]; cs != NIL; cs = cs[2]) n++; } /* * Allocate case table space */ ctab = i = malloc(n * sizeof *ctab); if (i == 0) { error("Ran out of memory (case)"); pexit(DIED); } /* * Check the legality of the * labels and count the number * of good labels */ m = 0; for (cl = r[3]; cl != NIL; cl = cl[2]) { cs = cl[1]; if (cs == NIL) continue; line = cs[1]; for (cs = cs[2]; cs != NIL; cs = cs[2]) { gconst(cs[1]); if (p == NIL || con.ctype == NIL) continue; if (incompat(con.ctype, p, NIL)) { cerror("Case label type clashed with case selector expression type"); continue; } if (con.crval < low || con.crval > high) { error("Case label out of range"); continue; } ctab[m].clong = con.crval; ctab[m].cline = line; m++; } } /* * Check for duplicate labels */ for (i = 0; i < m; i++) for (j = 0; j < m; j++) if (ctab[i].clong == ctab[j].clong) { if (i == j) continue; if (j < i) break; error("Multiply defined label in case, lines %d and %d", ctab[i].cline, ctab[j].cline); } /* * Put out case operator and * leave space for the * branch table */ if (p != NIL) { put2(O_CASE1OP + (w >> 1), n); brtab = brtab0 = lc; putspace(n * 2); put1(O_CASEBEG); for (i=0; i> 1), ctab[i].clong); put1(O_CASEEND); } csend = getlab(); put2(O_TRA, csend); /* * Free the case * table space. */ free(ctab); /* * Generate code for each * statement. Patch branch * table to beginning of each * statement and follow each * statement with a branch back * to the TRA above. */ nr = 1; for (cl = r[3]; cl != NIL; cl = cl[2]) { cs = cl[1]; if (cs == NIL) continue; if (p != NIL) for (cs = cs[2]; cs != NIL; cs = cs[2]) { patchfil(brtab - 1, lc - brtab0); brtab++; } cs = cl[1]; putcnt(); level++; statement(cs[3]); nr &= noreach; noreach = 0; put2(O_TRA, csend); level--; if (gotos[cbn]) ungoto(); } /* * Patch the termination branch */ patch(csend); noreach = nr; if (goc != gocnt) putcnt(); }