148116Sbostic /*-
2*62205Sbostic * Copyright (c) 1980, 1993
3*62205Sbostic * The Regents of the University of California. All rights reserved.
448116Sbostic *
548116Sbostic * %sccs.include.redist.c%
622077Sdist */
722077Sdist
822077Sdist #ifndef lint
9*62205Sbostic static char sccsid[] = "@(#)case.c 8.1 (Berkeley) 06/06/93";
1048116Sbostic #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 */
caseop(rnode)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