1*48116Sbostic /*- 2*48116Sbostic * Copyright (c) 1980 The Regents of the University of California. 3*48116Sbostic * All rights reserved. 4*48116Sbostic * 5*48116Sbostic * %sccs.include.redist.c% 622077Sdist */ 722077Sdist 822077Sdist #ifndef lint 9*48116Sbostic static char sccsid[] = "@(#)case.c 5.3 (Berkeley) 04/16/91"; 10*48116Sbostic #endif /* not lint */ 1122077Sdist 12746Speter #include "whoami.h" 13746Speter #include "0.h" 14746Speter #include "tree.h" 15746Speter #include "opcode.h" 1614728Sthien #include "tree_ty.h" 17746Speter 18746Speter /* 19746Speter * The structure used to 20746Speter * hold information about 21746Speter * each case label. 22746Speter */ 23746Speter struct ct { 24746Speter long clong; 25746Speter int cline; 26746Speter }; 27746Speter 28746Speter #ifdef OBJ 29746Speter /* 30746Speter * Caseop generates the 31746Speter * pascal case statement code 32746Speter */ 3314728Sthien caseop(rnode) 3414728Sthien WHI_CAS *rnode; 35746Speter { 36746Speter register struct nl *p; 37746Speter register struct ct *ctab; 3814728Sthien register struct tnode *cs; 3914728Sthien extern char *lc; 40746Speter double low, high; 41746Speter short *brtab; 42746Speter char *brtab0; 43746Speter char *csend; 4414728Sthien int w, j, m, n; 453072Smckusic int goc; 463072Smckusic bool nr; 47746Speter 48746Speter goc = gocnt; 49746Speter /* 50746Speter * Obtain selector attributes: 51746Speter * p type 52746Speter * w width 53746Speter * low lwb(p) 54746Speter * high upb(p) 55746Speter */ 5614728Sthien p = rvalue(rnode->expr, NLNIL , RREQ ); 5714728Sthien 5814728Sthien { 5914728Sthien register struct nl *cl; 6014728Sthien 6114728Sthien if (p != NLNIL) { 62746Speter if (isnta(p, "bcsi")) { 63746Speter error("Case selectors cannot be %ss", nameof(p)); 6414728Sthien p = NLNIL; 65746Speter } else { 66746Speter cl = p; 6714728Sthien if (p->class != (char) RANGE) 68746Speter cl = p->type; 6914728Sthien if (cl == NLNIL) 7014728Sthien p = NLNIL; 71746Speter else { 72746Speter w = width(p); 73746Speter #ifdef DEBUG 74746Speter if (hp21mx) 75746Speter w = 2; 76746Speter #endif 77746Speter low = cl->range[0]; 78746Speter high = cl->range[1]; 79746Speter } 80746Speter } 81746Speter } 8214728Sthien } /* local declaration */ 8314728Sthien { 8414728Sthien struct tnode *cl; /* list node */ 85746Speter /* 86746Speter * Count # of cases 87746Speter */ 88746Speter n = 0; 8914728Sthien for (cl = rnode->stmnt_list; cl != TR_NIL; 9014728Sthien cl = cl->list_node.next) { 9114728Sthien cs = cl->list_node.list;; 9214728Sthien if (cs == TR_NIL) 93746Speter continue; 9414728Sthien for (cs = cs->c_stmnt.const_list; cs != TR_NIL; 9514728Sthien cs = cs->list_node.next) 96746Speter n++; 97746Speter } 9814728Sthien } /* local declaration */ 99746Speter /* 100746Speter * Allocate case table space 101746Speter */ 10214728Sthien { 10314728Sthien char *i; 10414728Sthien i = malloc((unsigned) n * sizeof *ctab); 1051832Speter if (i == 0) { 106746Speter error("Ran out of memory (case)"); 107746Speter pexit(DIED); 108746Speter } 10914728Sthien ctab = (struct ct *) i; 11014728Sthien } 111746Speter /* 112746Speter * Check the legality of the 113746Speter * labels and count the number 114746Speter * of good labels 115746Speter */ 11614728Sthien { 11714728Sthien register struct tnode *cl; 118746Speter m = 0; 11914728Sthien for (cl = rnode->stmnt_list; cl != TR_NIL; 12014728Sthien cl = cl->list_node.next) { 12114728Sthien cs = cl->list_node.list; 12214728Sthien if (cs == TR_NIL) 123746Speter continue; 12414728Sthien line = cs->c_stmnt.line_no; 12514728Sthien for (cs = cs->c_stmnt.const_list; cs != TR_NIL; 12614728Sthien cs = cs->list_node.next) { 12714728Sthien gconst(cs->list_node.list); 12814728Sthien if (p == NLNIL || con.ctype == NIL) 129746Speter continue; 13014728Sthien if (incompat(con.ctype, p, TR_NIL )) { 131746Speter cerror("Case label type clashed with case selector expression type"); 132746Speter continue; 133746Speter } 134746Speter if (con.crval < low || con.crval > high) { 135746Speter error("Case label out of range"); 136746Speter continue; 137746Speter } 138746Speter ctab[m].clong = con.crval; 139746Speter ctab[m].cline = line; 140746Speter m++; 141746Speter } 142746Speter } 14314728Sthien } /* decl of cl */ 14414728Sthien { 14514728Sthien register int i; 146746Speter /* 147746Speter * Check for duplicate labels 148746Speter */ 149746Speter for (i = 0; i < m; i++) 150746Speter for (j = 0; j < m; j++) 151746Speter if (ctab[i].clong == ctab[j].clong) { 152746Speter if (i == j) 153746Speter continue; 154746Speter if (j < i) 155746Speter break; 15614728Sthien error("Multiply defined label in case, lines %d and %d", (char *) ctab[i].cline, (char *) ctab[j].cline); 157746Speter } 15814728Sthien } 159746Speter /* 160746Speter * Put out case operator and 161746Speter * leave space for the 162746Speter * branch table 163746Speter */ 16414728Sthien if (p != NLNIL) { 16514728Sthien (void) put(2, O_CASE1OP + (w >> 1), n); 16614728Sthien brtab0 = lc; 16714728Sthien brtab = ((short *) brtab0); 168746Speter putspace(n * 2); 16914728Sthien (void) put(1, O_CASEBEG); 17014728Sthien { 17114728Sthien int i; 172746Speter for (i=0; i<m; i++) 1733072Smckusic if (w <= 2) 17414728Sthien (void) put(2 ,O_CASE1 + (w >> 1), (int)ctab[i].clong); 1753072Smckusic else 17614728Sthien (void) put(2 ,O_CASE4, ctab[i].clong); 17714728Sthien } 17814728Sthien (void) put(1, O_CASEEND); 179746Speter } 180746Speter csend = getlab(); 18114728Sthien (void) put(2, O_TRA, csend); 182746Speter /* 183746Speter * Free the case 184746Speter * table space. 185746Speter */ 18614728Sthien free((char *) ctab); 187746Speter /* 188746Speter * Generate code for each 189746Speter * statement. Patch branch 190746Speter * table to beginning of each 191746Speter * statement and follow each 192746Speter * statement with a branch back 193746Speter * to the TRA above. 194746Speter */ 19514728Sthien { 19614728Sthien register struct tnode *cl; 1973072Smckusic nr = TRUE; 19814728Sthien for (cl = rnode->stmnt_list; cl != TR_NIL; 19914728Sthien cl = cl->list_node.next) { 20014728Sthien cs = cl->list_node.list; 20114728Sthien if (cs == TR_NIL) 202746Speter continue; 20314728Sthien if (p != NLNIL) 20414728Sthien for (cs = cs->c_stmnt.const_list; cs != TR_NIL; 20514728Sthien cs = cs->list_node.next) { 20614728Sthien #ifdef ADDR16 20714728Sthien patchfil(((char *) (brtab - 1)), 20814728Sthien (long)(lc - brtab0), 1); 20914728Sthien #endif ADDR16 21014728Sthien #ifdef ADDR32 21114728Sthien 21214728Sthien patchfil( ((unsigned long) (brtab - 1)), 21314728Sthien (long)(lc - brtab0), 1); 21414728Sthien #endif ADDR32 215746Speter brtab++; 216746Speter } 21714728Sthien cs = cl->list_node.list; 218746Speter putcnt(); 219746Speter level++; 22014728Sthien statement(cs->c_stmnt.stmnt); 22114728Sthien nr = (bool)(noreach && nr); 22214728Sthien noreach = FALSE; 22314728Sthien (void) put(2, O_TRA, csend); 224746Speter level--; 225746Speter if (gotos[cbn]) 226746Speter ungoto(); 227746Speter } 22814728Sthien } /* decl of cl */ 229746Speter /* 230746Speter * Patch the termination branch 231746Speter */ 23214728Sthien #ifdef ADDR16 23314728Sthien patch((char *) csend); 23414728Sthien #endif ADDR16 23514728Sthien #ifdef ADDR32 23614728Sthien patch((unsigned long) csend); 23714728Sthien #endif ADDR32 238746Speter noreach = nr; 239746Speter if (goc != gocnt) 240746Speter putcnt(); 241746Speter } 242746Speter #endif OBJ 243