xref: /csrg-svn/usr.bin/pascal/src/case.c (revision 62205)
148116Sbostic /*-
2*62205Sbostic  * Copyright (c) 1980, 1993
3*62205Sbostic  *	The Regents of the University of California.  All rights reserved.
448116Sbostic  *
548116Sbostic  * %sccs.include.redist.c%
622077Sdist  */
722077Sdist 
822077Sdist #ifndef lint
9*62205Sbostic static char sccsid[] = "@(#)case.c	8.1 (Berkeley) 06/06/93";
1048116Sbostic #endif /* not lint */
1122077Sdist 
12746Speter #include "whoami.h"
13746Speter #include "0.h"
14746Speter #include "tree.h"
15746Speter #include "opcode.h"
1614728Sthien #include "tree_ty.h"
17746Speter 
18746Speter /*
19746Speter  * The structure used to
20746Speter  * hold information about
21746Speter  * each case label.
22746Speter  */
23746Speter struct ct {
24746Speter 	long	clong;
25746Speter 	int	cline;
26746Speter };
27746Speter 
28746Speter #ifdef OBJ
29746Speter /*
30746Speter  * Caseop generates the
31746Speter  * pascal case statement code
32746Speter  */
caseop(rnode)3314728Sthien caseop(rnode)
3414728Sthien 	WHI_CAS *rnode;
35746Speter {
36746Speter 	register struct nl *p;
37746Speter 	register struct ct *ctab;
3814728Sthien 	register struct tnode *cs;
3914728Sthien 	extern char *lc;
40746Speter 	double low, high;
41746Speter 	short *brtab;
42746Speter 	char *brtab0;
43746Speter 	char *csend;
4414728Sthien 	int w, j, m, n;
453072Smckusic 	int goc;
463072Smckusic 	bool nr;
47746Speter 
48746Speter 	goc = gocnt;
49746Speter 	/*
50746Speter 	 * Obtain selector attributes:
51746Speter 	 *	p	type
52746Speter 	 *	w	width
53746Speter 	 *	low	lwb(p)
54746Speter 	 *	high	upb(p)
55746Speter 	 */
5614728Sthien 	p = rvalue(rnode->expr, NLNIL , RREQ );
5714728Sthien 
5814728Sthien 	{
5914728Sthien 	    register struct nl	*cl;
6014728Sthien 
6114728Sthien 	if (p != NLNIL) {
62746Speter 		if (isnta(p, "bcsi")) {
63746Speter 			error("Case selectors cannot be %ss", nameof(p));
6414728Sthien 			p = NLNIL;
65746Speter 		} else {
66746Speter 			cl = p;
6714728Sthien 			if (p->class != (char) RANGE)
68746Speter 				cl = p->type;
6914728Sthien 			if (cl == NLNIL)
7014728Sthien 				p = NLNIL;
71746Speter 			else {
72746Speter 				w = width(p);
73746Speter #ifdef DEBUG
74746Speter 				if (hp21mx)
75746Speter 					w = 2;
76746Speter #endif
77746Speter 				low = cl->range[0];
78746Speter 				high = cl->range[1];
79746Speter 			}
80746Speter 		}
81746Speter 	}
8214728Sthien 	} /* local declaration */
8314728Sthien 	{
8414728Sthien 	    struct tnode	*cl;	/* list node */
85746Speter 	/*
86746Speter 	 * Count # of cases
87746Speter 	 */
88746Speter 	n = 0;
8914728Sthien 	for (cl = rnode->stmnt_list; cl != TR_NIL;
9014728Sthien 		cl = cl->list_node.next) {
9114728Sthien 		cs = cl->list_node.list;;
9214728Sthien 		if (cs == TR_NIL)
93746Speter 			continue;
9414728Sthien 		for (cs = cs->c_stmnt.const_list; cs != TR_NIL;
9514728Sthien 				cs = cs->list_node.next)
96746Speter 			n++;
97746Speter 	}
9814728Sthien 	} /* local declaration */
99746Speter 	/*
100746Speter 	 * Allocate case table space
101746Speter 	 */
10214728Sthien 	{
10314728Sthien 		char *i;
10414728Sthien 	i = malloc((unsigned) n * sizeof *ctab);
1051832Speter 	if (i == 0) {
106746Speter 		error("Ran out of memory (case)");
107746Speter 		pexit(DIED);
108746Speter 	}
10914728Sthien 	ctab = (struct ct *) i;
11014728Sthien 	}
111746Speter 	/*
112746Speter 	 * Check the legality of the
113746Speter 	 * labels and count the number
114746Speter 	 * of good labels
115746Speter 	 */
11614728Sthien 	{
11714728Sthien 	    register struct tnode *cl;
118746Speter 	m = 0;
11914728Sthien 	for (cl = rnode->stmnt_list; cl != TR_NIL;
12014728Sthien 		cl = cl->list_node.next) {
12114728Sthien 		cs = cl->list_node.list;
12214728Sthien 		if (cs == TR_NIL)
123746Speter 			continue;
12414728Sthien 		line = cs->c_stmnt.line_no;
12514728Sthien 		for (cs = cs->c_stmnt.const_list; cs != TR_NIL;
12614728Sthien 				cs =  cs->list_node.next) {
12714728Sthien 			gconst(cs->list_node.list);
12814728Sthien 			if (p == NLNIL || con.ctype == NIL)
129746Speter 				continue;
13014728Sthien 			if (incompat(con.ctype, p, TR_NIL )) {
131746Speter 				cerror("Case label type clashed with case selector expression type");
132746Speter 				continue;
133746Speter 			}
134746Speter 			if (con.crval < low || con.crval > high) {
135746Speter 				error("Case label out of range");
136746Speter 				continue;
137746Speter 			}
138746Speter 			ctab[m].clong = con.crval;
139746Speter 			ctab[m].cline = line;
140746Speter 			m++;
141746Speter 		}
142746Speter 	}
14314728Sthien 	} /* decl of cl */
14414728Sthien 	{
14514728Sthien 		register int i;
146746Speter 	/*
147746Speter 	 * Check for duplicate labels
148746Speter 	 */
149746Speter 	for (i = 0; i < m; i++)
150746Speter 		for (j = 0; j < m; j++)
151746Speter 			if (ctab[i].clong == ctab[j].clong) {
152746Speter 				if (i == j)
153746Speter 					continue;
154746Speter 				if (j < i)
155746Speter 					break;
15614728Sthien 				error("Multiply defined label in case, lines %d and %d", (char *) ctab[i].cline, (char *) ctab[j].cline);
157746Speter 			}
15814728Sthien 	}
159746Speter 	/*
160746Speter 	 * Put out case operator and
161746Speter 	 * leave space for the
162746Speter 	 * branch table
163746Speter 	 */
16414728Sthien 	if (p != NLNIL) {
16514728Sthien 		(void) put(2, O_CASE1OP + (w >> 1), n);
16614728Sthien 		brtab0 = lc;
16714728Sthien 		brtab = ((short *) brtab0);
168746Speter 		putspace(n * 2);
16914728Sthien 		(void) put(1, O_CASEBEG);
17014728Sthien 		{
17114728Sthien 		    int i;
172746Speter 		for (i=0; i<m; i++)
1733072Smckusic 			if (w <= 2)
17414728Sthien 				(void) put(2 ,O_CASE1 + (w >> 1), (int)ctab[i].clong);
1753072Smckusic 			else
17614728Sthien 				(void) put(2 ,O_CASE4, ctab[i].clong);
17714728Sthien 		}
17814728Sthien 		(void) put(1, O_CASEEND);
179746Speter 	}
180746Speter 	csend = getlab();
18114728Sthien 	(void) put(2, O_TRA, csend);
182746Speter 	/*
183746Speter 	 * Free the case
184746Speter 	 * table space.
185746Speter 	 */
18614728Sthien 	free((char *) ctab);
187746Speter 	/*
188746Speter 	 * Generate code for each
189746Speter 	 * statement. Patch branch
190746Speter 	 * table to beginning of each
191746Speter 	 * statement and follow each
192746Speter 	 * statement with a branch back
193746Speter 	 * to the TRA above.
194746Speter 	 */
19514728Sthien 	{
19614728Sthien 	    register struct tnode *cl;
1973072Smckusic 	nr = TRUE;
19814728Sthien 	for (cl = rnode->stmnt_list; cl != TR_NIL;
19914728Sthien 			cl = cl->list_node.next) {
20014728Sthien 		cs = cl->list_node.list;
20114728Sthien 		if (cs == TR_NIL)
202746Speter 			continue;
20314728Sthien 		if (p != NLNIL)
20414728Sthien 			for (cs = cs->c_stmnt.const_list; cs != TR_NIL;
20514728Sthien 				cs =  cs->list_node.next) {
20614728Sthien #ifdef ADDR16
20714728Sthien 				patchfil(((char *) (brtab - 1)),
20814728Sthien 					(long)(lc - brtab0), 1);
20914728Sthien #endif ADDR16
21014728Sthien #ifdef ADDR32
21114728Sthien 
21214728Sthien 				patchfil( ((unsigned long) (brtab - 1)),
21314728Sthien 					(long)(lc - brtab0), 1);
21414728Sthien #endif ADDR32
215746Speter 				brtab++;
216746Speter 			}
21714728Sthien 		cs = cl->list_node.list;
218746Speter 		putcnt();
219746Speter 		level++;
22014728Sthien 		statement(cs->c_stmnt.stmnt);
22114728Sthien 		nr = (bool)(noreach && nr);
22214728Sthien 		noreach = FALSE;
22314728Sthien 		(void) put(2, O_TRA, csend);
224746Speter 		level--;
225746Speter 		if (gotos[cbn])
226746Speter 			ungoto();
227746Speter 	}
22814728Sthien 	} /* decl of cl */
229746Speter 	/*
230746Speter 	 * Patch the termination branch
231746Speter 	 */
23214728Sthien #ifdef ADDR16
23314728Sthien 	patch((char *) csend);
23414728Sthien #endif ADDR16
23514728Sthien #ifdef ADDR32
23614728Sthien 	patch((unsigned long) csend);
23714728Sthien #endif ADDR32
238746Speter 	noreach = nr;
239746Speter 	if (goc != gocnt)
240746Speter 		putcnt();
241746Speter }
242746Speter #endif OBJ
243