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