xref: /csrg-svn/usr.bin/pascal/src/case.c (revision 1832)
1746Speter /* Copyright (c) 1979 Regents of the University of California */
2746Speter 
3*1832Speter static	char sccsid[] = "@(#)case.c 1.2 11/24/80";
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;
37746Speter 	int nr, goc;
38746Speter 
39746Speter 	goc = gocnt;
40746Speter 	/*
41746Speter 	 * Obtain selector attributes:
42746Speter 	 *	p	type
43746Speter 	 *	w	width
44746Speter 	 *	low	lwb(p)
45746Speter 	 *	high	upb(p)
46746Speter 	 */
47746Speter 	p = rvalue((int *) r[2], NLNIL , RREQ );
48746Speter 	if (p != NIL) {
49746Speter 		if (isnta(p, "bcsi")) {
50746Speter 			error("Case selectors cannot be %ss", nameof(p));
51746Speter 			p = NIL;
52746Speter 		} else {
53746Speter 			cl = p;
54746Speter 			if (p->class != RANGE)
55746Speter 				cl = p->type;
56746Speter 			if (cl == NIL)
57746Speter 				p = NIL;
58746Speter 			else {
59746Speter 				w = width(p);
60746Speter #ifdef DEBUG
61746Speter 				if (hp21mx)
62746Speter 					w = 2;
63746Speter #endif
64746Speter 				low = cl->range[0];
65746Speter 				high = cl->range[1];
66746Speter 			}
67746Speter 		}
68746Speter 	}
69746Speter 	/*
70746Speter 	 * Count # of cases
71746Speter 	 */
72746Speter 	n = 0;
73746Speter 	for (cl = r[3]; cl != NIL; cl = cl[2]) {
74746Speter 		cs = cl[1];
75746Speter 		if (cs == NIL)
76746Speter 			continue;
77746Speter 		for (cs = cs[2]; cs != NIL; cs = cs[2])
78746Speter 			n++;
79746Speter 	}
80746Speter 	/*
81746Speter 	 * Allocate case table space
82746Speter 	 */
83746Speter 	ctab = i = malloc(n * sizeof *ctab);
84*1832Speter 	if (i == 0) {
85746Speter 		error("Ran out of memory (case)");
86746Speter 		pexit(DIED);
87746Speter 	}
88746Speter 	/*
89746Speter 	 * Check the legality of the
90746Speter 	 * labels and count the number
91746Speter 	 * of good labels
92746Speter 	 */
93746Speter 	m = 0;
94746Speter 	for (cl = r[3]; cl != NIL; cl = cl[2]) {
95746Speter 		cs = cl[1];
96746Speter 		if (cs == NIL)
97746Speter 			continue;
98746Speter 		line = cs[1];
99746Speter 		for (cs = cs[2]; cs != NIL; cs = cs[2]) {
100746Speter 			gconst(cs[1]);
101746Speter 			if (p == NIL || con.ctype == NIL)
102746Speter 				continue;
103746Speter 			if (incompat(con.ctype, p, NIL )) {
104746Speter 				cerror("Case label type clashed with case selector expression type");
105746Speter 				continue;
106746Speter 			}
107746Speter 			if (con.crval < low || con.crval > high) {
108746Speter 				error("Case label out of range");
109746Speter 				continue;
110746Speter 			}
111746Speter 			ctab[m].clong = con.crval;
112746Speter 			ctab[m].cline = line;
113746Speter 			m++;
114746Speter 		}
115746Speter 	}
116746Speter 
117746Speter 	/*
118746Speter 	 * Check for duplicate labels
119746Speter 	 */
120746Speter 	for (i = 0; i < m; i++)
121746Speter 		for (j = 0; j < m; j++)
122746Speter 			if (ctab[i].clong == ctab[j].clong) {
123746Speter 				if (i == j)
124746Speter 					continue;
125746Speter 				if (j < i)
126746Speter 					break;
127746Speter 				error("Multiply defined label in case, lines %d and %d", ctab[i].cline, ctab[j].cline);
128746Speter 			}
129746Speter 	/*
130746Speter 	 * Put out case operator and
131746Speter 	 * leave space for the
132746Speter 	 * branch table
133746Speter 	 */
134746Speter 	if (p != NIL) {
135746Speter 		put(2, O_CASE1OP + (w >> 1), n);
136746Speter 		brtab = brtab0 = lc;
137746Speter 		putspace(n * 2);
138746Speter 		put(1, O_CASEBEG);
139746Speter 		for (i=0; i<m; i++)
140746Speter 			put( 2 , O_CASE1 + (w >> 1), ctab[i].clong);
141746Speter 		put(1, O_CASEEND);
142746Speter 	}
143746Speter 	csend = getlab();
144746Speter 	put(2, O_TRA, csend);
145746Speter 	/*
146746Speter 	 * Free the case
147746Speter 	 * table space.
148746Speter 	 */
149746Speter 	free(ctab);
150746Speter 	/*
151746Speter 	 * Generate code for each
152746Speter 	 * statement. Patch branch
153746Speter 	 * table to beginning of each
154746Speter 	 * statement and follow each
155746Speter 	 * statement with a branch back
156746Speter 	 * to the TRA above.
157746Speter 	 */
158746Speter 	nr = 1;
159746Speter 	for (cl = r[3]; cl != NIL; cl = cl[2]) {
160746Speter 		cs = cl[1];
161746Speter 		if (cs == NIL)
162746Speter 			continue;
163746Speter 		if (p != NIL)
164746Speter 			for (cs = cs[2]; cs != NIL; cs = cs[2]) {
165746Speter 				patchfil(brtab - 1, lc - brtab0, 1);
166746Speter 				brtab++;
167746Speter 			}
168746Speter 		cs = cl[1];
169746Speter 		putcnt();
170746Speter 		level++;
171746Speter 		statement(cs[3]);
172746Speter 		nr &= noreach;
173746Speter 		noreach = 0;
174746Speter 		put(2, O_TRA, csend);
175746Speter 		level--;
176746Speter 		if (gotos[cbn])
177746Speter 			ungoto();
178746Speter 	}
179746Speter 	/*
180746Speter 	 * Patch the termination branch
181746Speter 	 */
182746Speter 	patch(csend);
183746Speter 	noreach = nr;
184746Speter 	if (goc != gocnt)
185746Speter 		putcnt();
186746Speter }
187746Speter #endif OBJ
188