1 /*- 2 * Copyright (c) 1980, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)case.c 8.1 (Berkeley) 06/06/93"; 10 #endif /* not lint */ 11 12 #include "whoami.h" 13 #include "0.h" 14 #include "tree.h" 15 #include "opcode.h" 16 #include "tree_ty.h" 17 18 /* 19 * The structure used to 20 * hold information about 21 * each case label. 22 */ 23 struct ct { 24 long clong; 25 int cline; 26 }; 27 28 #ifdef OBJ 29 /* 30 * Caseop generates the 31 * pascal case statement code 32 */ 33 caseop(rnode) 34 WHI_CAS *rnode; 35 { 36 register struct nl *p; 37 register struct ct *ctab; 38 register struct tnode *cs; 39 extern char *lc; 40 double low, high; 41 short *brtab; 42 char *brtab0; 43 char *csend; 44 int w, j, m, n; 45 int goc; 46 bool nr; 47 48 goc = gocnt; 49 /* 50 * Obtain selector attributes: 51 * p type 52 * w width 53 * low lwb(p) 54 * high upb(p) 55 */ 56 p = rvalue(rnode->expr, NLNIL , RREQ ); 57 58 { 59 register struct nl *cl; 60 61 if (p != NLNIL) { 62 if (isnta(p, "bcsi")) { 63 error("Case selectors cannot be %ss", nameof(p)); 64 p = NLNIL; 65 } else { 66 cl = p; 67 if (p->class != (char) RANGE) 68 cl = p->type; 69 if (cl == NLNIL) 70 p = NLNIL; 71 else { 72 w = width(p); 73 #ifdef DEBUG 74 if (hp21mx) 75 w = 2; 76 #endif 77 low = cl->range[0]; 78 high = cl->range[1]; 79 } 80 } 81 } 82 } /* local declaration */ 83 { 84 struct tnode *cl; /* list node */ 85 /* 86 * Count # of cases 87 */ 88 n = 0; 89 for (cl = rnode->stmnt_list; cl != TR_NIL; 90 cl = cl->list_node.next) { 91 cs = cl->list_node.list;; 92 if (cs == TR_NIL) 93 continue; 94 for (cs = cs->c_stmnt.const_list; cs != TR_NIL; 95 cs = cs->list_node.next) 96 n++; 97 } 98 } /* local declaration */ 99 /* 100 * Allocate case table space 101 */ 102 { 103 char *i; 104 i = malloc((unsigned) n * sizeof *ctab); 105 if (i == 0) { 106 error("Ran out of memory (case)"); 107 pexit(DIED); 108 } 109 ctab = (struct ct *) i; 110 } 111 /* 112 * Check the legality of the 113 * labels and count the number 114 * of good labels 115 */ 116 { 117 register struct tnode *cl; 118 m = 0; 119 for (cl = rnode->stmnt_list; cl != TR_NIL; 120 cl = cl->list_node.next) { 121 cs = cl->list_node.list; 122 if (cs == TR_NIL) 123 continue; 124 line = cs->c_stmnt.line_no; 125 for (cs = cs->c_stmnt.const_list; cs != TR_NIL; 126 cs = cs->list_node.next) { 127 gconst(cs->list_node.list); 128 if (p == NLNIL || con.ctype == NIL) 129 continue; 130 if (incompat(con.ctype, p, TR_NIL )) { 131 cerror("Case label type clashed with case selector expression type"); 132 continue; 133 } 134 if (con.crval < low || con.crval > high) { 135 error("Case label out of range"); 136 continue; 137 } 138 ctab[m].clong = con.crval; 139 ctab[m].cline = line; 140 m++; 141 } 142 } 143 } /* decl of cl */ 144 { 145 register int i; 146 /* 147 * Check for duplicate labels 148 */ 149 for (i = 0; i < m; i++) 150 for (j = 0; j < m; j++) 151 if (ctab[i].clong == ctab[j].clong) { 152 if (i == j) 153 continue; 154 if (j < i) 155 break; 156 error("Multiply defined label in case, lines %d and %d", (char *) ctab[i].cline, (char *) ctab[j].cline); 157 } 158 } 159 /* 160 * Put out case operator and 161 * leave space for the 162 * branch table 163 */ 164 if (p != NLNIL) { 165 (void) put(2, O_CASE1OP + (w >> 1), n); 166 brtab0 = lc; 167 brtab = ((short *) brtab0); 168 putspace(n * 2); 169 (void) put(1, O_CASEBEG); 170 { 171 int i; 172 for (i=0; i<m; i++) 173 if (w <= 2) 174 (void) put(2 ,O_CASE1 + (w >> 1), (int)ctab[i].clong); 175 else 176 (void) put(2 ,O_CASE4, ctab[i].clong); 177 } 178 (void) put(1, O_CASEEND); 179 } 180 csend = getlab(); 181 (void) put(2, O_TRA, csend); 182 /* 183 * Free the case 184 * table space. 185 */ 186 free((char *) ctab); 187 /* 188 * Generate code for each 189 * statement. Patch branch 190 * table to beginning of each 191 * statement and follow each 192 * statement with a branch back 193 * to the TRA above. 194 */ 195 { 196 register struct tnode *cl; 197 nr = TRUE; 198 for (cl = rnode->stmnt_list; cl != TR_NIL; 199 cl = cl->list_node.next) { 200 cs = cl->list_node.list; 201 if (cs == TR_NIL) 202 continue; 203 if (p != NLNIL) 204 for (cs = cs->c_stmnt.const_list; cs != TR_NIL; 205 cs = cs->list_node.next) { 206 #ifdef ADDR16 207 patchfil(((char *) (brtab - 1)), 208 (long)(lc - brtab0), 1); 209 #endif ADDR16 210 #ifdef ADDR32 211 212 patchfil( ((unsigned long) (brtab - 1)), 213 (long)(lc - brtab0), 1); 214 #endif ADDR32 215 brtab++; 216 } 217 cs = cl->list_node.list; 218 putcnt(); 219 level++; 220 statement(cs->c_stmnt.stmnt); 221 nr = (bool)(noreach && nr); 222 noreach = FALSE; 223 (void) put(2, O_TRA, csend); 224 level--; 225 if (gotos[cbn]) 226 ungoto(); 227 } 228 } /* decl of cl */ 229 /* 230 * Patch the termination branch 231 */ 232 #ifdef ADDR16 233 patch((char *) csend); 234 #endif ADDR16 235 #ifdef ADDR32 236 patch((unsigned long) csend); 237 #endif ADDR32 238 noreach = nr; 239 if (goc != gocnt) 240 putcnt(); 241 } 242 #endif OBJ 243