1*763Speter /* Copyright (c) 1979 Regents of the University of California */
2*763Speter 
3*763Speter static	char sccsid[] = "@(#)pccaseop.c 1.1 08/27/80";
4*763Speter 
5*763Speter #include "whoami.h"
6*763Speter #ifdef PC
7*763Speter     /*
8*763Speter      *	and the rest of the file
9*763Speter      */
10*763Speter #include "0.h"
11*763Speter #include "tree.h"
12*763Speter #include "objfmt.h"
13*763Speter #include "pcops.h"
14*763Speter #include "pc.h"
15*763Speter     /*
16*763Speter      *	tcase	[0]	T_CASE
17*763Speter      *		[1]	lineof "case"
18*763Speter      *		[2]	expression
19*763Speter      *		[3]	list of cased statements
20*763Speter      *			cstat	[0]	T_CSTAT
21*763Speter      *				[1]	lineof ":"
22*763Speter      *				[2]	constant list
23*763Speter      *				[3]	statement
24*763Speter      */
25*763Speter 
26*763Speter struct ct {
27*763Speter     long	clong;
28*763Speter     int		cline;
29*763Speter };
30*763Speter 
31*763Speter pccaseop( tcase )
32*763Speter     int	*tcase;
33*763Speter     {
34*763Speter 	struct nl	*exprtype;
35*763Speter 	struct nl	*rangetype;
36*763Speter 	long		low;
37*763Speter 	long		high;
38*763Speter 	long		exproff;
39*763Speter 	long		exprctype;
40*763Speter 	long		count;
41*763Speter 	long		*cstatlp;
42*763Speter 	long		*cstatp;
43*763Speter 	struct ct	*ctab;
44*763Speter 	long		endlabel;
45*763Speter 	long		nextlabel;
46*763Speter 	long		firsttime;
47*763Speter 	long		*casep;
48*763Speter 	long		i;
49*763Speter 	long		nr;
50*763Speter 	long		goc;
51*763Speter 
52*763Speter 	goc = gocnt;
53*763Speter 	    /*
54*763Speter 	     *	find out the type of the case expression
55*763Speter 	     */
56*763Speter 	line = tcase[1];
57*763Speter 	codeoff();
58*763Speter 	exprtype = rvalue( (int *) tcase[2] , NIL  , RREQ );
59*763Speter 	codeon();
60*763Speter 	if ( exprtype != NIL ) {
61*763Speter 	    if ( isnta( exprtype , "bcsi" ) ) {
62*763Speter 		error("Case selectors cannot be %ss" , nameof( exprtype ) );
63*763Speter 		exprtype = NIL;
64*763Speter 	    } else {
65*763Speter 		if ( exprtype -> class != RANGE ) {
66*763Speter 		    rangetype = exprtype -> type;
67*763Speter 		} else {
68*763Speter 		    rangetype = exprtype;
69*763Speter 		}
70*763Speter 		if ( rangetype == NIL ) {
71*763Speter 		    exprtype = NIL;
72*763Speter 		} else {
73*763Speter 		    low = rangetype -> range[0];
74*763Speter 		    high = rangetype -> range[1];
75*763Speter 		}
76*763Speter 	    }
77*763Speter 	}
78*763Speter 	if ( exprtype != NIL ) {
79*763Speter 		/*
80*763Speter 		 * allocate temporary for case expression
81*763Speter 		 */
82*763Speter 	    sizes[cbn].om_off -= sizeof( long );
83*763Speter 	    exproff = sizes[cbn].om_off;
84*763Speter 	    putlbracket( ftnno , -sizes[cbn].om_off );
85*763Speter 	    if ( sizes[cbn].om_off < sizes[cbn].om_max ) {
86*763Speter 		sizes[cbn].om_max = sizes[cbn].om_off;
87*763Speter 	    }
88*763Speter 		/*
89*763Speter 		 * compute and save the expression
90*763Speter 		 */
91*763Speter 	    exprctype = p2type( exprtype );
92*763Speter 	    putRV( 0 , cbn , exproff , P2INT );
93*763Speter 	    rvalue( (int *) tcase[2] , NIL  , RREQ );
94*763Speter 	    putop( P2ASSIGN , exprctype );
95*763Speter 	    putdot( filename , line );
96*763Speter 	}
97*763Speter 	    /*
98*763Speter 	     *	count the number of cases
99*763Speter 	     *	and allocate table for cases and lines
100*763Speter 	     */
101*763Speter 	count = 0;
102*763Speter 	for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) {
103*763Speter 	    cstatp = cstatlp[1];
104*763Speter 	    if ( cstatp == NIL ) {
105*763Speter 		continue;
106*763Speter 	    }
107*763Speter 	    for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) {
108*763Speter 		count++;
109*763Speter 	    }
110*763Speter 	}
111*763Speter 	ctab = (struct ct *) malloc( count * sizeof( struct ct ) );
112*763Speter 	if ( ctab == (struct ct *) -1 ) {
113*763Speter 	    error("Ran out of memory (case)");
114*763Speter 	    pexit( DIED );
115*763Speter 	}
116*763Speter 	    /*
117*763Speter 	     * generate code for each case
118*763Speter 	     */
119*763Speter 	endlabel = getlab();
120*763Speter 	nextlabel = getlab();
121*763Speter 	count = 0;
122*763Speter 	nr = 1;
123*763Speter 	for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) {
124*763Speter 	    cstatp = cstatlp[1];
125*763Speter 	    if ( cstatp == NIL ) {
126*763Speter 		continue;
127*763Speter 	    }
128*763Speter 	    line = cstatp[1];
129*763Speter 	    putlab( nextlabel );
130*763Speter 	    nextlabel = getlab();
131*763Speter 		/*
132*763Speter 		 * if it's not any of these, then go to next
133*763Speter 		 */
134*763Speter 	    firsttime = 1;
135*763Speter 	    for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) {
136*763Speter 		gconst( casep[1] );
137*763Speter 		if( exprtype == NIL || con.ctype == NIL ) {
138*763Speter 		    continue;
139*763Speter 		}
140*763Speter 		if ( incompat( con.ctype , exprtype , NIL ) ) {
141*763Speter 		    cerror("Case label type clashed with case selector expression type");
142*763Speter 		    continue;
143*763Speter 		}
144*763Speter 		if ( con.crval < low || con.crval > high ) {
145*763Speter 		    error("Case label out of range");
146*763Speter 		    continue;
147*763Speter 		}
148*763Speter 		ctab[ count ].clong = con.crval;
149*763Speter 		ctab[ count ].cline = line;
150*763Speter 		    /*
151*763Speter 		     *	check for duplicates
152*763Speter 		     */
153*763Speter 		for ( i = 0 ; i < count ; i++ ) {
154*763Speter 		    if ( ctab[ i ].clong == con.crval ) {
155*763Speter 			error("Multiply defined label in case, lines %d and %d"
156*763Speter 				, ctab[ i ].cline , line );
157*763Speter 		    }
158*763Speter 		}
159*763Speter 		putRV( 0 , cbn , exproff , exprctype , 0 );
160*763Speter 		putleaf( P2ICON , ctab[ count ].clong , 0 , exprctype , 0 );
161*763Speter 		putop( P2EQ , exprctype );
162*763Speter 		if ( ! firsttime ) {
163*763Speter 			/*
164*763Speter 			 * note the use of !! to get short circuiting
165*763Speter 			 */
166*763Speter 		    putop( P2OROR , P2CHAR );
167*763Speter 		}
168*763Speter 		firsttime = 0;
169*763Speter 	    }
170*763Speter 	    putleaf( P2ICON , nextlabel , 0 , P2INT , 0 );
171*763Speter 	    putop( P2CBRANCH , P2INT );
172*763Speter 	    putdot( filename , line );
173*763Speter 		/*
174*763Speter 		 * if we get here, we must be in this case
175*763Speter 		 */
176*763Speter 	    putcnt();
177*763Speter 	    level++;
178*763Speter 	    statement( cstatp[3] );
179*763Speter 	    nr &= noreach;
180*763Speter 	    noreach = 0;
181*763Speter 	    putjbr( endlabel );
182*763Speter 	    level--;
183*763Speter 	    if (gotos[cbn]) {
184*763Speter 		    ungoto();
185*763Speter 	    }
186*763Speter 	}
187*763Speter 	    /*
188*763Speter 	     *	default action is to call error
189*763Speter 	     */
190*763Speter 	putlab( nextlabel );
191*763Speter 	putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_ERROR" );
192*763Speter 	putleaf( P2ICON , ECASE , 0 , P2INT , 0 );
193*763Speter 	putRV( 0 , cbn , exproff , P2INT );
194*763Speter 	putop( P2LISTOP , P2INT );
195*763Speter 	putop( P2CALL , P2INT );
196*763Speter 	putdot( filename , line );
197*763Speter 	putlab( endlabel );
198*763Speter 	noreach = nr;
199*763Speter 	if ( goc != gocnt ) {
200*763Speter 		putcnt();
201*763Speter 	}
202*763Speter     }
203*763Speter 
204*763Speter #endif PC
205