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