xref: /original-bsd/usr.bin/pascal/src/case.c (revision c3e32dec)
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  */
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