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