xref: /csrg-svn/usr.bin/pascal/src/case.c (revision 22077)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)case.c	5.1 (Berkeley) 06/05/85";
9 #endif not lint
10 
11 /* Copyright (c) 1979 Regents of the University of California */
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)case.c 5.1 06/05/85";
15 #endif
16 
17 #include "whoami.h"
18 #include "0.h"
19 #include "tree.h"
20 #include "opcode.h"
21 #include "tree_ty.h"
22 
23 /*
24  * The structure used to
25  * hold information about
26  * each case label.
27  */
28 struct ct {
29 	long	clong;
30 	int	cline;
31 };
32 
33 #ifdef OBJ
34 /*
35  * Caseop generates the
36  * pascal case statement code
37  */
38 caseop(rnode)
39 	WHI_CAS *rnode;
40 {
41 	register struct nl *p;
42 	register struct ct *ctab;
43 	register struct tnode *cs;
44 	extern char *lc;
45 	double low, high;
46 	short *brtab;
47 	char *brtab0;
48 	char *csend;
49 	int w, j, m, n;
50 	int goc;
51 	bool nr;
52 
53 	goc = gocnt;
54 	/*
55 	 * Obtain selector attributes:
56 	 *	p	type
57 	 *	w	width
58 	 *	low	lwb(p)
59 	 *	high	upb(p)
60 	 */
61 	p = rvalue(rnode->expr, NLNIL , RREQ );
62 
63 	{
64 	    register struct nl	*cl;
65 
66 	if (p != NLNIL) {
67 		if (isnta(p, "bcsi")) {
68 			error("Case selectors cannot be %ss", nameof(p));
69 			p = NLNIL;
70 		} else {
71 			cl = p;
72 			if (p->class != (char) RANGE)
73 				cl = p->type;
74 			if (cl == NLNIL)
75 				p = NLNIL;
76 			else {
77 				w = width(p);
78 #ifdef DEBUG
79 				if (hp21mx)
80 					w = 2;
81 #endif
82 				low = cl->range[0];
83 				high = cl->range[1];
84 			}
85 		}
86 	}
87 	} /* local declaration */
88 	{
89 	    struct tnode	*cl;	/* list node */
90 	/*
91 	 * Count # of cases
92 	 */
93 	n = 0;
94 	for (cl = rnode->stmnt_list; cl != TR_NIL;
95 		cl = cl->list_node.next) {
96 		cs = cl->list_node.list;;
97 		if (cs == TR_NIL)
98 			continue;
99 		for (cs = cs->c_stmnt.const_list; cs != TR_NIL;
100 				cs = cs->list_node.next)
101 			n++;
102 	}
103 	} /* local declaration */
104 	/*
105 	 * Allocate case table space
106 	 */
107 	{
108 		char *i;
109 	i = malloc((unsigned) n * sizeof *ctab);
110 	if (i == 0) {
111 		error("Ran out of memory (case)");
112 		pexit(DIED);
113 	}
114 	ctab = (struct ct *) i;
115 	}
116 	/*
117 	 * Check the legality of the
118 	 * labels and count the number
119 	 * of good labels
120 	 */
121 	{
122 	    register struct tnode *cl;
123 	m = 0;
124 	for (cl = rnode->stmnt_list; cl != TR_NIL;
125 		cl = cl->list_node.next) {
126 		cs = cl->list_node.list;
127 		if (cs == TR_NIL)
128 			continue;
129 		line = cs->c_stmnt.line_no;
130 		for (cs = cs->c_stmnt.const_list; cs != TR_NIL;
131 				cs =  cs->list_node.next) {
132 			gconst(cs->list_node.list);
133 			if (p == NLNIL || con.ctype == NIL)
134 				continue;
135 			if (incompat(con.ctype, p, TR_NIL )) {
136 				cerror("Case label type clashed with case selector expression type");
137 				continue;
138 			}
139 			if (con.crval < low || con.crval > high) {
140 				error("Case label out of range");
141 				continue;
142 			}
143 			ctab[m].clong = con.crval;
144 			ctab[m].cline = line;
145 			m++;
146 		}
147 	}
148 	} /* decl of cl */
149 	{
150 		register int i;
151 	/*
152 	 * Check for duplicate labels
153 	 */
154 	for (i = 0; i < m; i++)
155 		for (j = 0; j < m; j++)
156 			if (ctab[i].clong == ctab[j].clong) {
157 				if (i == j)
158 					continue;
159 				if (j < i)
160 					break;
161 				error("Multiply defined label in case, lines %d and %d", (char *) ctab[i].cline, (char *) ctab[j].cline);
162 			}
163 	}
164 	/*
165 	 * Put out case operator and
166 	 * leave space for the
167 	 * branch table
168 	 */
169 	if (p != NLNIL) {
170 		(void) put(2, O_CASE1OP + (w >> 1), n);
171 		brtab0 = lc;
172 		brtab = ((short *) brtab0);
173 		putspace(n * 2);
174 		(void) put(1, O_CASEBEG);
175 		{
176 		    int i;
177 		for (i=0; i<m; i++)
178 			if (w <= 2)
179 				(void) put(2 ,O_CASE1 + (w >> 1), (int)ctab[i].clong);
180 			else
181 				(void) put(2 ,O_CASE4, ctab[i].clong);
182 		}
183 		(void) put(1, O_CASEEND);
184 	}
185 	csend = getlab();
186 	(void) put(2, O_TRA, csend);
187 	/*
188 	 * Free the case
189 	 * table space.
190 	 */
191 	free((char *) ctab);
192 	/*
193 	 * Generate code for each
194 	 * statement. Patch branch
195 	 * table to beginning of each
196 	 * statement and follow each
197 	 * statement with a branch back
198 	 * to the TRA above.
199 	 */
200 	{
201 	    register struct tnode *cl;
202 	nr = TRUE;
203 	for (cl = rnode->stmnt_list; cl != TR_NIL;
204 			cl = cl->list_node.next) {
205 		cs = cl->list_node.list;
206 		if (cs == TR_NIL)
207 			continue;
208 		if (p != NLNIL)
209 			for (cs = cs->c_stmnt.const_list; cs != TR_NIL;
210 				cs =  cs->list_node.next) {
211 #ifdef ADDR16
212 				patchfil(((char *) (brtab - 1)),
213 					(long)(lc - brtab0), 1);
214 #endif ADDR16
215 #ifdef ADDR32
216 
217 				patchfil( ((unsigned long) (brtab - 1)),
218 					(long)(lc - brtab0), 1);
219 #endif ADDR32
220 				brtab++;
221 			}
222 		cs = cl->list_node.list;
223 		putcnt();
224 		level++;
225 		statement(cs->c_stmnt.stmnt);
226 		nr = (bool)(noreach && nr);
227 		noreach = FALSE;
228 		(void) put(2, O_TRA, csend);
229 		level--;
230 		if (gotos[cbn])
231 			ungoto();
232 	}
233 	} /* decl of cl */
234 	/*
235 	 * Patch the termination branch
236 	 */
237 #ifdef ADDR16
238 	patch((char *) csend);
239 #endif ADDR16
240 #ifdef ADDR32
241 	patch((unsigned long) csend);
242 #endif ADDR32
243 	noreach = nr;
244 	if (goc != gocnt)
245 		putcnt();
246 }
247 #endif OBJ
248