xref: /original-bsd/usr.bin/pascal/src/case.c (revision 552e81d8)
1 /* Copyright (c) 1979 Regents of the University of California */
2 
3 static	char sccsid[] = "@(#)case.c 1.1 08/27/80";
4 
5 #include "whoami.h"
6 #include "0.h"
7 #include "tree.h"
8 #include "opcode.h"
9 
10 /*
11  * The structure used to
12  * hold information about
13  * each case label.
14  */
15 struct ct {
16 	long	clong;
17 	int	cline;
18 };
19 
20 #ifdef OBJ
21 /*
22  * Caseop generates the
23  * pascal case statement code
24  */
25 caseop(r)
26 	int *r;
27 {
28 	register struct nl *p;
29 	register struct ct *ctab;
30 	register *cs;
31 	int *cl;
32 	double low, high;
33 	short *brtab;
34 	char *brtab0;
35 	char *csend;
36 	int w, i, j, m, n;
37 	int nr, goc;
38 
39 	goc = gocnt;
40 	/*
41 	 * Obtain selector attributes:
42 	 *	p	type
43 	 *	w	width
44 	 *	low	lwb(p)
45 	 *	high	upb(p)
46 	 */
47 	p = rvalue((int *) r[2], NLNIL , RREQ );
48 	if (p != NIL) {
49 		if (isnta(p, "bcsi")) {
50 			error("Case selectors cannot be %ss", nameof(p));
51 			p = NIL;
52 		} else {
53 			cl = p;
54 			if (p->class != RANGE)
55 				cl = p->type;
56 			if (cl == NIL)
57 				p = NIL;
58 			else {
59 				w = width(p);
60 #ifdef DEBUG
61 				if (hp21mx)
62 					w = 2;
63 #endif
64 				low = cl->range[0];
65 				high = cl->range[1];
66 			}
67 		}
68 	}
69 	/*
70 	 * Count # of cases
71 	 */
72 	n = 0;
73 	for (cl = r[3]; cl != NIL; cl = cl[2]) {
74 		cs = cl[1];
75 		if (cs == NIL)
76 			continue;
77 		for (cs = cs[2]; cs != NIL; cs = cs[2])
78 			n++;
79 	}
80 	/*
81 	 * Allocate case table space
82 	 */
83 	ctab = i = malloc(n * sizeof *ctab);
84 	if (i == -1) {
85 		error("Ran out of memory (case)");
86 		pexit(DIED);
87 	}
88 	/*
89 	 * Check the legality of the
90 	 * labels and count the number
91 	 * of good labels
92 	 */
93 	m = 0;
94 	for (cl = r[3]; cl != NIL; cl = cl[2]) {
95 		cs = cl[1];
96 		if (cs == NIL)
97 			continue;
98 		line = cs[1];
99 		for (cs = cs[2]; cs != NIL; cs = cs[2]) {
100 			gconst(cs[1]);
101 			if (p == NIL || con.ctype == NIL)
102 				continue;
103 			if (incompat(con.ctype, p, NIL )) {
104 				cerror("Case label type clashed with case selector expression type");
105 				continue;
106 			}
107 			if (con.crval < low || con.crval > high) {
108 				error("Case label out of range");
109 				continue;
110 			}
111 			ctab[m].clong = con.crval;
112 			ctab[m].cline = line;
113 			m++;
114 		}
115 	}
116 
117 	/*
118 	 * Check for duplicate labels
119 	 */
120 	for (i = 0; i < m; i++)
121 		for (j = 0; j < m; j++)
122 			if (ctab[i].clong == ctab[j].clong) {
123 				if (i == j)
124 					continue;
125 				if (j < i)
126 					break;
127 				error("Multiply defined label in case, lines %d and %d", ctab[i].cline, ctab[j].cline);
128 			}
129 	/*
130 	 * Put out case operator and
131 	 * leave space for the
132 	 * branch table
133 	 */
134 	if (p != NIL) {
135 		put(2, O_CASE1OP + (w >> 1), n);
136 		brtab = brtab0 = lc;
137 		putspace(n * 2);
138 		put(1, O_CASEBEG);
139 		for (i=0; i<m; i++)
140 			put( 2 , O_CASE1 + (w >> 1), ctab[i].clong);
141 		put(1, O_CASEEND);
142 	}
143 	csend = getlab();
144 	put(2, O_TRA, csend);
145 	/*
146 	 * Free the case
147 	 * table space.
148 	 */
149 	free(ctab);
150 	/*
151 	 * Generate code for each
152 	 * statement. Patch branch
153 	 * table to beginning of each
154 	 * statement and follow each
155 	 * statement with a branch back
156 	 * to the TRA above.
157 	 */
158 	nr = 1;
159 	for (cl = r[3]; cl != NIL; cl = cl[2]) {
160 		cs = cl[1];
161 		if (cs == NIL)
162 			continue;
163 		if (p != NIL)
164 			for (cs = cs[2]; cs != NIL; cs = cs[2]) {
165 				patchfil(brtab - 1, lc - brtab0, 1);
166 				brtab++;
167 			}
168 		cs = cl[1];
169 		putcnt();
170 		level++;
171 		statement(cs[3]);
172 		nr &= noreach;
173 		noreach = 0;
174 		put(2, O_TRA, csend);
175 		level--;
176 		if (gotos[cbn])
177 			ungoto();
178 	}
179 	/*
180 	 * Patch the termination branch
181 	 */
182 	patch(csend);
183 	noreach = nr;
184 	if (goc != gocnt)
185 		putcnt();
186 }
187 #endif OBJ
188