xref: /csrg-svn/usr.bin/pascal/src/case.c (revision 3072)
1746Speter /* Copyright (c) 1979 Regents of the University of California */
2746Speter 
3*3072Smckusic static char sccsid[] = "@(#)case.c 1.3 03/08/81";
4746Speter 
5746Speter #include "whoami.h"
6746Speter #include "0.h"
7746Speter #include "tree.h"
8746Speter #include "opcode.h"
9746Speter 
10746Speter /*
11746Speter  * The structure used to
12746Speter  * hold information about
13746Speter  * each case label.
14746Speter  */
15746Speter struct ct {
16746Speter 	long	clong;
17746Speter 	int	cline;
18746Speter };
19746Speter 
20746Speter #ifdef OBJ
21746Speter /*
22746Speter  * Caseop generates the
23746Speter  * pascal case statement code
24746Speter  */
25746Speter caseop(r)
26746Speter 	int *r;
27746Speter {
28746Speter 	register struct nl *p;
29746Speter 	register struct ct *ctab;
30746Speter 	register *cs;
31746Speter 	int *cl;
32746Speter 	double low, high;
33746Speter 	short *brtab;
34746Speter 	char *brtab0;
35746Speter 	char *csend;
36746Speter 	int w, i, j, m, n;
37*3072Smckusic 	int goc;
38*3072Smckusic 	bool nr;
39746Speter 
40746Speter 	goc = gocnt;
41746Speter 	/*
42746Speter 	 * Obtain selector attributes:
43746Speter 	 *	p	type
44746Speter 	 *	w	width
45746Speter 	 *	low	lwb(p)
46746Speter 	 *	high	upb(p)
47746Speter 	 */
48746Speter 	p = rvalue((int *) r[2], NLNIL , RREQ );
49746Speter 	if (p != NIL) {
50746Speter 		if (isnta(p, "bcsi")) {
51746Speter 			error("Case selectors cannot be %ss", nameof(p));
52746Speter 			p = NIL;
53746Speter 		} else {
54746Speter 			cl = p;
55746Speter 			if (p->class != RANGE)
56746Speter 				cl = p->type;
57746Speter 			if (cl == NIL)
58746Speter 				p = NIL;
59746Speter 			else {
60746Speter 				w = width(p);
61746Speter #ifdef DEBUG
62746Speter 				if (hp21mx)
63746Speter 					w = 2;
64746Speter #endif
65746Speter 				low = cl->range[0];
66746Speter 				high = cl->range[1];
67746Speter 			}
68746Speter 		}
69746Speter 	}
70746Speter 	/*
71746Speter 	 * Count # of cases
72746Speter 	 */
73746Speter 	n = 0;
74746Speter 	for (cl = r[3]; cl != NIL; cl = cl[2]) {
75746Speter 		cs = cl[1];
76746Speter 		if (cs == NIL)
77746Speter 			continue;
78746Speter 		for (cs = cs[2]; cs != NIL; cs = cs[2])
79746Speter 			n++;
80746Speter 	}
81746Speter 	/*
82746Speter 	 * Allocate case table space
83746Speter 	 */
84746Speter 	ctab = i = malloc(n * sizeof *ctab);
851832Speter 	if (i == 0) {
86746Speter 		error("Ran out of memory (case)");
87746Speter 		pexit(DIED);
88746Speter 	}
89746Speter 	/*
90746Speter 	 * Check the legality of the
91746Speter 	 * labels and count the number
92746Speter 	 * of good labels
93746Speter 	 */
94746Speter 	m = 0;
95746Speter 	for (cl = r[3]; cl != NIL; cl = cl[2]) {
96746Speter 		cs = cl[1];
97746Speter 		if (cs == NIL)
98746Speter 			continue;
99746Speter 		line = cs[1];
100746Speter 		for (cs = cs[2]; cs != NIL; cs = cs[2]) {
101746Speter 			gconst(cs[1]);
102746Speter 			if (p == NIL || con.ctype == NIL)
103746Speter 				continue;
104746Speter 			if (incompat(con.ctype, p, NIL )) {
105746Speter 				cerror("Case label type clashed with case selector expression type");
106746Speter 				continue;
107746Speter 			}
108746Speter 			if (con.crval < low || con.crval > high) {
109746Speter 				error("Case label out of range");
110746Speter 				continue;
111746Speter 			}
112746Speter 			ctab[m].clong = con.crval;
113746Speter 			ctab[m].cline = line;
114746Speter 			m++;
115746Speter 		}
116746Speter 	}
117746Speter 
118746Speter 	/*
119746Speter 	 * Check for duplicate labels
120746Speter 	 */
121746Speter 	for (i = 0; i < m; i++)
122746Speter 		for (j = 0; j < m; j++)
123746Speter 			if (ctab[i].clong == ctab[j].clong) {
124746Speter 				if (i == j)
125746Speter 					continue;
126746Speter 				if (j < i)
127746Speter 					break;
128746Speter 				error("Multiply defined label in case, lines %d and %d", ctab[i].cline, ctab[j].cline);
129746Speter 			}
130746Speter 	/*
131746Speter 	 * Put out case operator and
132746Speter 	 * leave space for the
133746Speter 	 * branch table
134746Speter 	 */
135746Speter 	if (p != NIL) {
136746Speter 		put(2, O_CASE1OP + (w >> 1), n);
137746Speter 		brtab = brtab0 = lc;
138746Speter 		putspace(n * 2);
139746Speter 		put(1, O_CASEBEG);
140746Speter 		for (i=0; i<m; i++)
141*3072Smckusic 			if (w <= 2)
142*3072Smckusic 				put(2 ,O_CASE1 + (w >> 1), (int)ctab[i].clong);
143*3072Smckusic 			else
144*3072Smckusic 				put(2 ,O_CASE4, ctab[i].clong);
145746Speter 		put(1, O_CASEEND);
146746Speter 	}
147746Speter 	csend = getlab();
148746Speter 	put(2, O_TRA, csend);
149746Speter 	/*
150746Speter 	 * Free the case
151746Speter 	 * table space.
152746Speter 	 */
153746Speter 	free(ctab);
154746Speter 	/*
155746Speter 	 * Generate code for each
156746Speter 	 * statement. Patch branch
157746Speter 	 * table to beginning of each
158746Speter 	 * statement and follow each
159746Speter 	 * statement with a branch back
160746Speter 	 * to the TRA above.
161746Speter 	 */
162*3072Smckusic 	nr = TRUE;
163746Speter 	for (cl = r[3]; cl != NIL; cl = cl[2]) {
164746Speter 		cs = cl[1];
165746Speter 		if (cs == NIL)
166746Speter 			continue;
167746Speter 		if (p != NIL)
168746Speter 			for (cs = cs[2]; cs != NIL; cs = cs[2]) {
169*3072Smckusic 				patchfil(brtab - 1, (long)(lc - brtab0), 1);
170746Speter 				brtab++;
171746Speter 			}
172746Speter 		cs = cl[1];
173746Speter 		putcnt();
174746Speter 		level++;
175746Speter 		statement(cs[3]);
176*3072Smckusic 		nr = (noreach && nr);
177746Speter 		noreach = 0;
178746Speter 		put(2, O_TRA, csend);
179746Speter 		level--;
180746Speter 		if (gotos[cbn])
181746Speter 			ungoto();
182746Speter 	}
183746Speter 	/*
184746Speter 	 * Patch the termination branch
185746Speter 	 */
186746Speter 	patch(csend);
187746Speter 	noreach = nr;
188746Speter 	if (goc != gocnt)
189746Speter 		putcnt();
190746Speter }
191746Speter #endif OBJ
192