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