/* * Copyright (c) 1980 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ #ifndef lint static char sccsid[] = "@(#)case.c 5.2 (Berkeley) 6/5/85"; #endif not lint #include "whoami.h" #include "0.h" #include "tree.h" #include "opcode.h" #include "tree_ty.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(rnode) WHI_CAS *rnode; { register struct nl *p; register struct ct *ctab; register struct tnode *cs; extern char *lc; double low, high; short *brtab; char *brtab0; char *csend; int w, j, m, n; int goc; bool nr; goc = gocnt; /* * Obtain selector attributes: * p type * w width * low lwb(p) * high upb(p) */ p = rvalue(rnode->expr, NLNIL , RREQ ); { register struct nl *cl; if (p != NLNIL) { if (isnta(p, "bcsi")) { error("Case selectors cannot be %ss", nameof(p)); p = NLNIL; } else { cl = p; if (p->class != (char) RANGE) cl = p->type; if (cl == NLNIL) p = NLNIL; else { w = width(p); #ifdef DEBUG if (hp21mx) w = 2; #endif low = cl->range[0]; high = cl->range[1]; } } } } /* local declaration */ { struct tnode *cl; /* list node */ /* * Count # of cases */ n = 0; for (cl = rnode->stmnt_list; cl != TR_NIL; cl = cl->list_node.next) { cs = cl->list_node.list;; if (cs == TR_NIL) continue; for (cs = cs->c_stmnt.const_list; cs != TR_NIL; cs = cs->list_node.next) n++; } } /* local declaration */ /* * Allocate case table space */ { char *i; i = malloc((unsigned) n * sizeof *ctab); if (i == 0) { error("Ran out of memory (case)"); pexit(DIED); } ctab = (struct ct *) i; } /* * Check the legality of the * labels and count the number * of good labels */ { register struct tnode *cl; m = 0; for (cl = rnode->stmnt_list; cl != TR_NIL; cl = cl->list_node.next) { cs = cl->list_node.list; if (cs == TR_NIL) continue; line = cs->c_stmnt.line_no; for (cs = cs->c_stmnt.const_list; cs != TR_NIL; cs = cs->list_node.next) { gconst(cs->list_node.list); if (p == NLNIL || con.ctype == NIL) continue; if (incompat(con.ctype, p, TR_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++; } } } /* decl of cl */ { register int i; /* * 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", (char *) ctab[i].cline, (char *) ctab[j].cline); } } /* * Put out case operator and * leave space for the * branch table */ if (p != NLNIL) { (void) put(2, O_CASE1OP + (w >> 1), n); brtab0 = lc; brtab = ((short *) brtab0); putspace(n * 2); (void) put(1, O_CASEBEG); { int i; for (i=0; i> 1), (int)ctab[i].clong); else (void) put(2 ,O_CASE4, ctab[i].clong); } (void) put(1, O_CASEEND); } csend = getlab(); (void) put(2, O_TRA, csend); /* * Free the case * table space. */ free((char *) 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. */ { register struct tnode *cl; nr = TRUE; for (cl = rnode->stmnt_list; cl != TR_NIL; cl = cl->list_node.next) { cs = cl->list_node.list; if (cs == TR_NIL) continue; if (p != NLNIL) for (cs = cs->c_stmnt.const_list; cs != TR_NIL; cs = cs->list_node.next) { #ifdef ADDR16 patchfil(((char *) (brtab - 1)), (long)(lc - brtab0), 1); #endif ADDR16 #ifdef ADDR32 patchfil( ((unsigned long) (brtab - 1)), (long)(lc - brtab0), 1); #endif ADDR32 brtab++; } cs = cl->list_node.list; putcnt(); level++; statement(cs->c_stmnt.stmnt); nr = (bool)(noreach && nr); noreach = FALSE; (void) put(2, O_TRA, csend); level--; if (gotos[cbn]) ungoto(); } } /* decl of cl */ /* * Patch the termination branch */ #ifdef ADDR16 patch((char *) csend); #endif ADDR16 #ifdef ADDR32 patch((unsigned long) csend); #endif ADDR32 noreach = nr; if (goc != gocnt) putcnt(); } #endif OBJ