xref: /csrg-svn/usr.bin/pascal/src/case.c (revision 14728)
1746Speter /* Copyright (c) 1979 Regents of the University of California */
2746Speter 
3*14728Sthien #ifndef lint
4*14728Sthien static char sccsid[] = "@(#)case.c 1.4 08/19/83";
5*14728Sthien #endif
6746Speter 
7746Speter #include "whoami.h"
8746Speter #include "0.h"
9746Speter #include "tree.h"
10746Speter #include "opcode.h"
11*14728Sthien #include "tree_ty.h"
12746Speter 
13746Speter /*
14746Speter  * The structure used to
15746Speter  * hold information about
16746Speter  * each case label.
17746Speter  */
18746Speter struct ct {
19746Speter 	long	clong;
20746Speter 	int	cline;
21746Speter };
22746Speter 
23746Speter #ifdef OBJ
24746Speter /*
25746Speter  * Caseop generates the
26746Speter  * pascal case statement code
27746Speter  */
28*14728Sthien caseop(rnode)
29*14728Sthien 	WHI_CAS *rnode;
30746Speter {
31746Speter 	register struct nl *p;
32746Speter 	register struct ct *ctab;
33*14728Sthien 	register struct tnode *cs;
34*14728Sthien 	extern char *lc;
35746Speter 	double low, high;
36746Speter 	short *brtab;
37746Speter 	char *brtab0;
38746Speter 	char *csend;
39*14728Sthien 	int w, j, m, n;
403072Smckusic 	int goc;
413072Smckusic 	bool nr;
42746Speter 
43746Speter 	goc = gocnt;
44746Speter 	/*
45746Speter 	 * Obtain selector attributes:
46746Speter 	 *	p	type
47746Speter 	 *	w	width
48746Speter 	 *	low	lwb(p)
49746Speter 	 *	high	upb(p)
50746Speter 	 */
51*14728Sthien 	p = rvalue(rnode->expr, NLNIL , RREQ );
52*14728Sthien 
53*14728Sthien 	{
54*14728Sthien 	    register struct nl	*cl;
55*14728Sthien 
56*14728Sthien 	if (p != NLNIL) {
57746Speter 		if (isnta(p, "bcsi")) {
58746Speter 			error("Case selectors cannot be %ss", nameof(p));
59*14728Sthien 			p = NLNIL;
60746Speter 		} else {
61746Speter 			cl = p;
62*14728Sthien 			if (p->class != (char) RANGE)
63746Speter 				cl = p->type;
64*14728Sthien 			if (cl == NLNIL)
65*14728Sthien 				p = NLNIL;
66746Speter 			else {
67746Speter 				w = width(p);
68746Speter #ifdef DEBUG
69746Speter 				if (hp21mx)
70746Speter 					w = 2;
71746Speter #endif
72746Speter 				low = cl->range[0];
73746Speter 				high = cl->range[1];
74746Speter 			}
75746Speter 		}
76746Speter 	}
77*14728Sthien 	} /* local declaration */
78*14728Sthien 	{
79*14728Sthien 	    struct tnode	*cl;	/* list node */
80746Speter 	/*
81746Speter 	 * Count # of cases
82746Speter 	 */
83746Speter 	n = 0;
84*14728Sthien 	for (cl = rnode->stmnt_list; cl != TR_NIL;
85*14728Sthien 		cl = cl->list_node.next) {
86*14728Sthien 		cs = cl->list_node.list;;
87*14728Sthien 		if (cs == TR_NIL)
88746Speter 			continue;
89*14728Sthien 		for (cs = cs->c_stmnt.const_list; cs != TR_NIL;
90*14728Sthien 				cs = cs->list_node.next)
91746Speter 			n++;
92746Speter 	}
93*14728Sthien 	} /* local declaration */
94746Speter 	/*
95746Speter 	 * Allocate case table space
96746Speter 	 */
97*14728Sthien 	{
98*14728Sthien 		char *i;
99*14728Sthien 	i = malloc((unsigned) n * sizeof *ctab);
1001832Speter 	if (i == 0) {
101746Speter 		error("Ran out of memory (case)");
102746Speter 		pexit(DIED);
103746Speter 	}
104*14728Sthien 	ctab = (struct ct *) i;
105*14728Sthien 	}
106746Speter 	/*
107746Speter 	 * Check the legality of the
108746Speter 	 * labels and count the number
109746Speter 	 * of good labels
110746Speter 	 */
111*14728Sthien 	{
112*14728Sthien 	    register struct tnode *cl;
113746Speter 	m = 0;
114*14728Sthien 	for (cl = rnode->stmnt_list; cl != TR_NIL;
115*14728Sthien 		cl = cl->list_node.next) {
116*14728Sthien 		cs = cl->list_node.list;
117*14728Sthien 		if (cs == TR_NIL)
118746Speter 			continue;
119*14728Sthien 		line = cs->c_stmnt.line_no;
120*14728Sthien 		for (cs = cs->c_stmnt.const_list; cs != TR_NIL;
121*14728Sthien 				cs =  cs->list_node.next) {
122*14728Sthien 			gconst(cs->list_node.list);
123*14728Sthien 			if (p == NLNIL || con.ctype == NIL)
124746Speter 				continue;
125*14728Sthien 			if (incompat(con.ctype, p, TR_NIL )) {
126746Speter 				cerror("Case label type clashed with case selector expression type");
127746Speter 				continue;
128746Speter 			}
129746Speter 			if (con.crval < low || con.crval > high) {
130746Speter 				error("Case label out of range");
131746Speter 				continue;
132746Speter 			}
133746Speter 			ctab[m].clong = con.crval;
134746Speter 			ctab[m].cline = line;
135746Speter 			m++;
136746Speter 		}
137746Speter 	}
138*14728Sthien 	} /* decl of cl */
139*14728Sthien 	{
140*14728Sthien 		register int i;
141746Speter 	/*
142746Speter 	 * Check for duplicate labels
143746Speter 	 */
144746Speter 	for (i = 0; i < m; i++)
145746Speter 		for (j = 0; j < m; j++)
146746Speter 			if (ctab[i].clong == ctab[j].clong) {
147746Speter 				if (i == j)
148746Speter 					continue;
149746Speter 				if (j < i)
150746Speter 					break;
151*14728Sthien 				error("Multiply defined label in case, lines %d and %d", (char *) ctab[i].cline, (char *) ctab[j].cline);
152746Speter 			}
153*14728Sthien 	}
154746Speter 	/*
155746Speter 	 * Put out case operator and
156746Speter 	 * leave space for the
157746Speter 	 * branch table
158746Speter 	 */
159*14728Sthien 	if (p != NLNIL) {
160*14728Sthien 		(void) put(2, O_CASE1OP + (w >> 1), n);
161*14728Sthien 		brtab0 = lc;
162*14728Sthien 		brtab = ((short *) brtab0);
163746Speter 		putspace(n * 2);
164*14728Sthien 		(void) put(1, O_CASEBEG);
165*14728Sthien 		{
166*14728Sthien 		    int i;
167746Speter 		for (i=0; i<m; i++)
1683072Smckusic 			if (w <= 2)
169*14728Sthien 				(void) put(2 ,O_CASE1 + (w >> 1), (int)ctab[i].clong);
1703072Smckusic 			else
171*14728Sthien 				(void) put(2 ,O_CASE4, ctab[i].clong);
172*14728Sthien 		}
173*14728Sthien 		(void) put(1, O_CASEEND);
174746Speter 	}
175746Speter 	csend = getlab();
176*14728Sthien 	(void) put(2, O_TRA, csend);
177746Speter 	/*
178746Speter 	 * Free the case
179746Speter 	 * table space.
180746Speter 	 */
181*14728Sthien 	free((char *) ctab);
182746Speter 	/*
183746Speter 	 * Generate code for each
184746Speter 	 * statement. Patch branch
185746Speter 	 * table to beginning of each
186746Speter 	 * statement and follow each
187746Speter 	 * statement with a branch back
188746Speter 	 * to the TRA above.
189746Speter 	 */
190*14728Sthien 	{
191*14728Sthien 	    register struct tnode *cl;
1923072Smckusic 	nr = TRUE;
193*14728Sthien 	for (cl = rnode->stmnt_list; cl != TR_NIL;
194*14728Sthien 			cl = cl->list_node.next) {
195*14728Sthien 		cs = cl->list_node.list;
196*14728Sthien 		if (cs == TR_NIL)
197746Speter 			continue;
198*14728Sthien 		if (p != NLNIL)
199*14728Sthien 			for (cs = cs->c_stmnt.const_list; cs != TR_NIL;
200*14728Sthien 				cs =  cs->list_node.next) {
201*14728Sthien #ifdef ADDR16
202*14728Sthien 				patchfil(((char *) (brtab - 1)),
203*14728Sthien 					(long)(lc - brtab0), 1);
204*14728Sthien #endif ADDR16
205*14728Sthien #ifdef ADDR32
206*14728Sthien 
207*14728Sthien 				patchfil( ((unsigned long) (brtab - 1)),
208*14728Sthien 					(long)(lc - brtab0), 1);
209*14728Sthien #endif ADDR32
210746Speter 				brtab++;
211746Speter 			}
212*14728Sthien 		cs = cl->list_node.list;
213746Speter 		putcnt();
214746Speter 		level++;
215*14728Sthien 		statement(cs->c_stmnt.stmnt);
216*14728Sthien 		nr = (bool)(noreach && nr);
217*14728Sthien 		noreach = FALSE;
218*14728Sthien 		(void) put(2, O_TRA, csend);
219746Speter 		level--;
220746Speter 		if (gotos[cbn])
221746Speter 			ungoto();
222746Speter 	}
223*14728Sthien 	} /* decl of cl */
224746Speter 	/*
225746Speter 	 * Patch the termination branch
226746Speter 	 */
227*14728Sthien #ifdef ADDR16
228*14728Sthien 	patch((char *) csend);
229*14728Sthien #endif ADDR16
230*14728Sthien #ifdef ADDR32
231*14728Sthien 	patch((unsigned long) csend);
232*14728Sthien #endif ADDR32
233746Speter 	noreach = nr;
234746Speter 	if (goc != gocnt)
235746Speter 		putcnt();
236746Speter }
237746Speter #endif OBJ
238