/* Copyright (c) 1979 Regents of the University of California */ static char sccsid[] = "@(#)case.c 1.3 3/8/81"; #include "whoami.h" #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; }; #ifdef OBJ /* * 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 goc; bool nr; goc = gocnt; /* * Obtain selector attributes: * p type * w width * low lwb(p) * high upb(p) */ p = rvalue((int *) r[2], NLNIL , RREQ ); 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) { put(2, O_CASE1OP + (w >> 1), n); brtab = brtab0 = lc; putspace(n * 2); put(1, O_CASEBEG); for (i=0; i<m; i++) if (w <= 2) put(2 ,O_CASE1 + (w >> 1), (int)ctab[i].clong); else put(2 ,O_CASE4, ctab[i].clong); put(1, O_CASEEND); } csend = getlab(); put(2, 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 = TRUE; 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, (long)(lc - brtab0), 1); brtab++; } cs = cl[1]; putcnt(); level++; statement(cs[3]); nr = (noreach && nr); noreach = 0; put(2, O_TRA, csend); level--; if (gotos[cbn]) ungoto(); } /* * Patch the termination branch */ patch(csend); noreach = nr; if (goc != gocnt) putcnt(); } #endif OBJ