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 */
caseop(rnode)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