/* Copyright (c) 1979 Regents of the University of California */ static char sccsid[] = "@(#)case.c 1.1 08/27/80"; #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 nr, goc; 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 == -1) { 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> 1), 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 = 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, 1); brtab++; } cs = cl[1]; putcnt(); level++; statement(cs[3]); nr &= noreach; 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