xref: /csrg-svn/usr.bin/pascal/src/case.c (revision 22077)
1*22077Sdist /*
2*22077Sdist  * Copyright (c) 1980 Regents of the University of California.
3*22077Sdist  * All rights reserved.  The Berkeley software License Agreement
4*22077Sdist  * specifies the terms and conditions for redistribution.
5*22077Sdist  */
6*22077Sdist 
7*22077Sdist #ifndef lint
8*22077Sdist static char sccsid[] = "@(#)case.c	5.1 (Berkeley) 06/05/85";
9*22077Sdist #endif not lint
10*22077Sdist 
11746Speter /* Copyright (c) 1979 Regents of the University of California */
12746Speter 
1314728Sthien #ifndef lint
14*22077Sdist static char sccsid[] = "@(#)case.c 5.1 06/05/85";
1514728Sthien #endif
16746Speter 
17746Speter #include "whoami.h"
18746Speter #include "0.h"
19746Speter #include "tree.h"
20746Speter #include "opcode.h"
2114728Sthien #include "tree_ty.h"
22746Speter 
23746Speter /*
24746Speter  * The structure used to
25746Speter  * hold information about
26746Speter  * each case label.
27746Speter  */
28746Speter struct ct {
29746Speter 	long	clong;
30746Speter 	int	cline;
31746Speter };
32746Speter 
33746Speter #ifdef OBJ
34746Speter /*
35746Speter  * Caseop generates the
36746Speter  * pascal case statement code
37746Speter  */
3814728Sthien caseop(rnode)
3914728Sthien 	WHI_CAS *rnode;
40746Speter {
41746Speter 	register struct nl *p;
42746Speter 	register struct ct *ctab;
4314728Sthien 	register struct tnode *cs;
4414728Sthien 	extern char *lc;
45746Speter 	double low, high;
46746Speter 	short *brtab;
47746Speter 	char *brtab0;
48746Speter 	char *csend;
4914728Sthien 	int w, j, m, n;
503072Smckusic 	int goc;
513072Smckusic 	bool nr;
52746Speter 
53746Speter 	goc = gocnt;
54746Speter 	/*
55746Speter 	 * Obtain selector attributes:
56746Speter 	 *	p	type
57746Speter 	 *	w	width
58746Speter 	 *	low	lwb(p)
59746Speter 	 *	high	upb(p)
60746Speter 	 */
6114728Sthien 	p = rvalue(rnode->expr, NLNIL , RREQ );
6214728Sthien 
6314728Sthien 	{
6414728Sthien 	    register struct nl	*cl;
6514728Sthien 
6614728Sthien 	if (p != NLNIL) {
67746Speter 		if (isnta(p, "bcsi")) {
68746Speter 			error("Case selectors cannot be %ss", nameof(p));
6914728Sthien 			p = NLNIL;
70746Speter 		} else {
71746Speter 			cl = p;
7214728Sthien 			if (p->class != (char) RANGE)
73746Speter 				cl = p->type;
7414728Sthien 			if (cl == NLNIL)
7514728Sthien 				p = NLNIL;
76746Speter 			else {
77746Speter 				w = width(p);
78746Speter #ifdef DEBUG
79746Speter 				if (hp21mx)
80746Speter 					w = 2;
81746Speter #endif
82746Speter 				low = cl->range[0];
83746Speter 				high = cl->range[1];
84746Speter 			}
85746Speter 		}
86746Speter 	}
8714728Sthien 	} /* local declaration */
8814728Sthien 	{
8914728Sthien 	    struct tnode	*cl;	/* list node */
90746Speter 	/*
91746Speter 	 * Count # of cases
92746Speter 	 */
93746Speter 	n = 0;
9414728Sthien 	for (cl = rnode->stmnt_list; cl != TR_NIL;
9514728Sthien 		cl = cl->list_node.next) {
9614728Sthien 		cs = cl->list_node.list;;
9714728Sthien 		if (cs == TR_NIL)
98746Speter 			continue;
9914728Sthien 		for (cs = cs->c_stmnt.const_list; cs != TR_NIL;
10014728Sthien 				cs = cs->list_node.next)
101746Speter 			n++;
102746Speter 	}
10314728Sthien 	} /* local declaration */
104746Speter 	/*
105746Speter 	 * Allocate case table space
106746Speter 	 */
10714728Sthien 	{
10814728Sthien 		char *i;
10914728Sthien 	i = malloc((unsigned) n * sizeof *ctab);
1101832Speter 	if (i == 0) {
111746Speter 		error("Ran out of memory (case)");
112746Speter 		pexit(DIED);
113746Speter 	}
11414728Sthien 	ctab = (struct ct *) i;
11514728Sthien 	}
116746Speter 	/*
117746Speter 	 * Check the legality of the
118746Speter 	 * labels and count the number
119746Speter 	 * of good labels
120746Speter 	 */
12114728Sthien 	{
12214728Sthien 	    register struct tnode *cl;
123746Speter 	m = 0;
12414728Sthien 	for (cl = rnode->stmnt_list; cl != TR_NIL;
12514728Sthien 		cl = cl->list_node.next) {
12614728Sthien 		cs = cl->list_node.list;
12714728Sthien 		if (cs == TR_NIL)
128746Speter 			continue;
12914728Sthien 		line = cs->c_stmnt.line_no;
13014728Sthien 		for (cs = cs->c_stmnt.const_list; cs != TR_NIL;
13114728Sthien 				cs =  cs->list_node.next) {
13214728Sthien 			gconst(cs->list_node.list);
13314728Sthien 			if (p == NLNIL || con.ctype == NIL)
134746Speter 				continue;
13514728Sthien 			if (incompat(con.ctype, p, TR_NIL )) {
136746Speter 				cerror("Case label type clashed with case selector expression type");
137746Speter 				continue;
138746Speter 			}
139746Speter 			if (con.crval < low || con.crval > high) {
140746Speter 				error("Case label out of range");
141746Speter 				continue;
142746Speter 			}
143746Speter 			ctab[m].clong = con.crval;
144746Speter 			ctab[m].cline = line;
145746Speter 			m++;
146746Speter 		}
147746Speter 	}
14814728Sthien 	} /* decl of cl */
14914728Sthien 	{
15014728Sthien 		register int i;
151746Speter 	/*
152746Speter 	 * Check for duplicate labels
153746Speter 	 */
154746Speter 	for (i = 0; i < m; i++)
155746Speter 		for (j = 0; j < m; j++)
156746Speter 			if (ctab[i].clong == ctab[j].clong) {
157746Speter 				if (i == j)
158746Speter 					continue;
159746Speter 				if (j < i)
160746Speter 					break;
16114728Sthien 				error("Multiply defined label in case, lines %d and %d", (char *) ctab[i].cline, (char *) ctab[j].cline);
162746Speter 			}
16314728Sthien 	}
164746Speter 	/*
165746Speter 	 * Put out case operator and
166746Speter 	 * leave space for the
167746Speter 	 * branch table
168746Speter 	 */
16914728Sthien 	if (p != NLNIL) {
17014728Sthien 		(void) put(2, O_CASE1OP + (w >> 1), n);
17114728Sthien 		brtab0 = lc;
17214728Sthien 		brtab = ((short *) brtab0);
173746Speter 		putspace(n * 2);
17414728Sthien 		(void) put(1, O_CASEBEG);
17514728Sthien 		{
17614728Sthien 		    int i;
177746Speter 		for (i=0; i<m; i++)
1783072Smckusic 			if (w <= 2)
17914728Sthien 				(void) put(2 ,O_CASE1 + (w >> 1), (int)ctab[i].clong);
1803072Smckusic 			else
18114728Sthien 				(void) put(2 ,O_CASE4, ctab[i].clong);
18214728Sthien 		}
18314728Sthien 		(void) put(1, O_CASEEND);
184746Speter 	}
185746Speter 	csend = getlab();
18614728Sthien 	(void) put(2, O_TRA, csend);
187746Speter 	/*
188746Speter 	 * Free the case
189746Speter 	 * table space.
190746Speter 	 */
19114728Sthien 	free((char *) ctab);
192746Speter 	/*
193746Speter 	 * Generate code for each
194746Speter 	 * statement. Patch branch
195746Speter 	 * table to beginning of each
196746Speter 	 * statement and follow each
197746Speter 	 * statement with a branch back
198746Speter 	 * to the TRA above.
199746Speter 	 */
20014728Sthien 	{
20114728Sthien 	    register struct tnode *cl;
2023072Smckusic 	nr = TRUE;
20314728Sthien 	for (cl = rnode->stmnt_list; cl != TR_NIL;
20414728Sthien 			cl = cl->list_node.next) {
20514728Sthien 		cs = cl->list_node.list;
20614728Sthien 		if (cs == TR_NIL)
207746Speter 			continue;
20814728Sthien 		if (p != NLNIL)
20914728Sthien 			for (cs = cs->c_stmnt.const_list; cs != TR_NIL;
21014728Sthien 				cs =  cs->list_node.next) {
21114728Sthien #ifdef ADDR16
21214728Sthien 				patchfil(((char *) (brtab - 1)),
21314728Sthien 					(long)(lc - brtab0), 1);
21414728Sthien #endif ADDR16
21514728Sthien #ifdef ADDR32
21614728Sthien 
21714728Sthien 				patchfil( ((unsigned long) (brtab - 1)),
21814728Sthien 					(long)(lc - brtab0), 1);
21914728Sthien #endif ADDR32
220746Speter 				brtab++;
221746Speter 			}
22214728Sthien 		cs = cl->list_node.list;
223746Speter 		putcnt();
224746Speter 		level++;
22514728Sthien 		statement(cs->c_stmnt.stmnt);
22614728Sthien 		nr = (bool)(noreach && nr);
22714728Sthien 		noreach = FALSE;
22814728Sthien 		(void) put(2, O_TRA, csend);
229746Speter 		level--;
230746Speter 		if (gotos[cbn])
231746Speter 			ungoto();
232746Speter 	}
23314728Sthien 	} /* decl of cl */
234746Speter 	/*
235746Speter 	 * Patch the termination branch
236746Speter 	 */
23714728Sthien #ifdef ADDR16
23814728Sthien 	patch((char *) csend);
23914728Sthien #endif ADDR16
24014728Sthien #ifdef ADDR32
24114728Sthien 	patch((unsigned long) csend);
24214728Sthien #endif ADDR32
243746Speter 	noreach = nr;
244746Speter 	if (goc != gocnt)
245746Speter 		putcnt();
246746Speter }
247746Speter #endif OBJ
248