1*22077Sdist /* 2*22077Sdist * Copyright (c) 1980 Regents of the University of California. 3*22077Sdist * All rights reserved. The Berkeley software License Agreement 4*22077Sdist * specifies the terms and conditions for redistribution. 5*22077Sdist */ 6*22077Sdist 7*22077Sdist #ifndef lint 8*22077Sdist static char sccsid[] = "@(#)case.c 5.1 (Berkeley) 06/05/85"; 9*22077Sdist #endif not lint 10*22077Sdist 11746Speter /* Copyright (c) 1979 Regents of the University of California */ 12746Speter 1314728Sthien #ifndef lint 14*22077Sdist static char sccsid[] = "@(#)case.c 5.1 06/05/85"; 1514728Sthien #endif 16746Speter 17746Speter #include "whoami.h" 18746Speter #include "0.h" 19746Speter #include "tree.h" 20746Speter #include "opcode.h" 2114728Sthien #include "tree_ty.h" 22746Speter 23746Speter /* 24746Speter * The structure used to 25746Speter * hold information about 26746Speter * each case label. 27746Speter */ 28746Speter struct ct { 29746Speter long clong; 30746Speter int cline; 31746Speter }; 32746Speter 33746Speter #ifdef OBJ 34746Speter /* 35746Speter * Caseop generates the 36746Speter * pascal case statement code 37746Speter */ 3814728Sthien caseop(rnode) 3914728Sthien WHI_CAS *rnode; 40746Speter { 41746Speter register struct nl *p; 42746Speter register struct ct *ctab; 4314728Sthien register struct tnode *cs; 4414728Sthien extern char *lc; 45746Speter double low, high; 46746Speter short *brtab; 47746Speter char *brtab0; 48746Speter char *csend; 4914728Sthien int w, j, m, n; 503072Smckusic int goc; 513072Smckusic bool nr; 52746Speter 53746Speter goc = gocnt; 54746Speter /* 55746Speter * Obtain selector attributes: 56746Speter * p type 57746Speter * w width 58746Speter * low lwb(p) 59746Speter * high upb(p) 60746Speter */ 6114728Sthien p = rvalue(rnode->expr, NLNIL , RREQ ); 6214728Sthien 6314728Sthien { 6414728Sthien register struct nl *cl; 6514728Sthien 6614728Sthien if (p != NLNIL) { 67746Speter if (isnta(p, "bcsi")) { 68746Speter error("Case selectors cannot be %ss", nameof(p)); 6914728Sthien p = NLNIL; 70746Speter } else { 71746Speter cl = p; 7214728Sthien if (p->class != (char) RANGE) 73746Speter cl = p->type; 7414728Sthien if (cl == NLNIL) 7514728Sthien p = NLNIL; 76746Speter else { 77746Speter w = width(p); 78746Speter #ifdef DEBUG 79746Speter if (hp21mx) 80746Speter w = 2; 81746Speter #endif 82746Speter low = cl->range[0]; 83746Speter high = cl->range[1]; 84746Speter } 85746Speter } 86746Speter } 8714728Sthien } /* local declaration */ 8814728Sthien { 8914728Sthien struct tnode *cl; /* list node */ 90746Speter /* 91746Speter * Count # of cases 92746Speter */ 93746Speter n = 0; 9414728Sthien for (cl = rnode->stmnt_list; cl != TR_NIL; 9514728Sthien cl = cl->list_node.next) { 9614728Sthien cs = cl->list_node.list;; 9714728Sthien if (cs == TR_NIL) 98746Speter continue; 9914728Sthien for (cs = cs->c_stmnt.const_list; cs != TR_NIL; 10014728Sthien cs = cs->list_node.next) 101746Speter n++; 102746Speter } 10314728Sthien } /* local declaration */ 104746Speter /* 105746Speter * Allocate case table space 106746Speter */ 10714728Sthien { 10814728Sthien char *i; 10914728Sthien i = malloc((unsigned) n * sizeof *ctab); 1101832Speter if (i == 0) { 111746Speter error("Ran out of memory (case)"); 112746Speter pexit(DIED); 113746Speter } 11414728Sthien ctab = (struct ct *) i; 11514728Sthien } 116746Speter /* 117746Speter * Check the legality of the 118746Speter * labels and count the number 119746Speter * of good labels 120746Speter */ 12114728Sthien { 12214728Sthien register struct tnode *cl; 123746Speter m = 0; 12414728Sthien for (cl = rnode->stmnt_list; cl != TR_NIL; 12514728Sthien cl = cl->list_node.next) { 12614728Sthien cs = cl->list_node.list; 12714728Sthien if (cs == TR_NIL) 128746Speter continue; 12914728Sthien line = cs->c_stmnt.line_no; 13014728Sthien for (cs = cs->c_stmnt.const_list; cs != TR_NIL; 13114728Sthien cs = cs->list_node.next) { 13214728Sthien gconst(cs->list_node.list); 13314728Sthien if (p == NLNIL || con.ctype == NIL) 134746Speter continue; 13514728Sthien if (incompat(con.ctype, p, TR_NIL )) { 136746Speter cerror("Case label type clashed with case selector expression type"); 137746Speter continue; 138746Speter } 139746Speter if (con.crval < low || con.crval > high) { 140746Speter error("Case label out of range"); 141746Speter continue; 142746Speter } 143746Speter ctab[m].clong = con.crval; 144746Speter ctab[m].cline = line; 145746Speter m++; 146746Speter } 147746Speter } 14814728Sthien } /* decl of cl */ 14914728Sthien { 15014728Sthien register int i; 151746Speter /* 152746Speter * Check for duplicate labels 153746Speter */ 154746Speter for (i = 0; i < m; i++) 155746Speter for (j = 0; j < m; j++) 156746Speter if (ctab[i].clong == ctab[j].clong) { 157746Speter if (i == j) 158746Speter continue; 159746Speter if (j < i) 160746Speter break; 16114728Sthien error("Multiply defined label in case, lines %d and %d", (char *) ctab[i].cline, (char *) ctab[j].cline); 162746Speter } 16314728Sthien } 164746Speter /* 165746Speter * Put out case operator and 166746Speter * leave space for the 167746Speter * branch table 168746Speter */ 16914728Sthien if (p != NLNIL) { 17014728Sthien (void) put(2, O_CASE1OP + (w >> 1), n); 17114728Sthien brtab0 = lc; 17214728Sthien brtab = ((short *) brtab0); 173746Speter putspace(n * 2); 17414728Sthien (void) put(1, O_CASEBEG); 17514728Sthien { 17614728Sthien int i; 177746Speter for (i=0; i<m; i++) 1783072Smckusic if (w <= 2) 17914728Sthien (void) put(2 ,O_CASE1 + (w >> 1), (int)ctab[i].clong); 1803072Smckusic else 18114728Sthien (void) put(2 ,O_CASE4, ctab[i].clong); 18214728Sthien } 18314728Sthien (void) put(1, O_CASEEND); 184746Speter } 185746Speter csend = getlab(); 18614728Sthien (void) put(2, O_TRA, csend); 187746Speter /* 188746Speter * Free the case 189746Speter * table space. 190746Speter */ 19114728Sthien free((char *) ctab); 192746Speter /* 193746Speter * Generate code for each 194746Speter * statement. Patch branch 195746Speter * table to beginning of each 196746Speter * statement and follow each 197746Speter * statement with a branch back 198746Speter * to the TRA above. 199746Speter */ 20014728Sthien { 20114728Sthien register struct tnode *cl; 2023072Smckusic nr = TRUE; 20314728Sthien for (cl = rnode->stmnt_list; cl != TR_NIL; 20414728Sthien cl = cl->list_node.next) { 20514728Sthien cs = cl->list_node.list; 20614728Sthien if (cs == TR_NIL) 207746Speter continue; 20814728Sthien if (p != NLNIL) 20914728Sthien for (cs = cs->c_stmnt.const_list; cs != TR_NIL; 21014728Sthien cs = cs->list_node.next) { 21114728Sthien #ifdef ADDR16 21214728Sthien patchfil(((char *) (brtab - 1)), 21314728Sthien (long)(lc - brtab0), 1); 21414728Sthien #endif ADDR16 21514728Sthien #ifdef ADDR32 21614728Sthien 21714728Sthien patchfil( ((unsigned long) (brtab - 1)), 21814728Sthien (long)(lc - brtab0), 1); 21914728Sthien #endif ADDR32 220746Speter brtab++; 221746Speter } 22214728Sthien cs = cl->list_node.list; 223746Speter putcnt(); 224746Speter level++; 22514728Sthien statement(cs->c_stmnt.stmnt); 22614728Sthien nr = (bool)(noreach && nr); 22714728Sthien noreach = FALSE; 22814728Sthien (void) put(2, O_TRA, csend); 229746Speter level--; 230746Speter if (gotos[cbn]) 231746Speter ungoto(); 232746Speter } 23314728Sthien } /* decl of cl */ 234746Speter /* 235746Speter * Patch the termination branch 236746Speter */ 23714728Sthien #ifdef ADDR16 23814728Sthien patch((char *) csend); 23914728Sthien #endif ADDR16 24014728Sthien #ifdef ADDR32 24114728Sthien patch((unsigned long) csend); 24214728Sthien #endif ADDR32 243746Speter noreach = nr; 244746Speter if (goc != gocnt) 245746Speter putcnt(); 246746Speter } 247746Speter #endif OBJ 248