xref: /csrg-svn/usr.bin/pascal/src/rval.c (revision 1200)
1771Speter /* Copyright (c) 1979 Regents of the University of California */
2771Speter 
3*1200Speter static	char sccsid[] = "@(#)rval.c 1.2 10/03/80";
4771Speter 
5771Speter #include "whoami.h"
6771Speter #include "0.h"
7771Speter #include "tree.h"
8771Speter #include "opcode.h"
9771Speter #include "objfmt.h"
10771Speter #ifdef PC
11771Speter #   include	"pc.h"
12771Speter #   include "pcops.h"
13771Speter #endif PC
14771Speter 
15771Speter extern	char *opnames[];
16771Speter bool	inempty = FALSE;
17771Speter 
18771Speter #ifdef PC
19771Speter     char	*relts[] =  {
20771Speter 				"_RELEQ" , "_RELNE" ,
21771Speter 				"_RELTLT" , "_RELTGT" ,
22771Speter 				"_RELTLE" , "_RELTGE"
23771Speter 			    };
24771Speter     char	*relss[] =  {
25771Speter 				"_RELEQ" , "_RELNE" ,
26771Speter 				"_RELSLT" , "_RELSGT" ,
27771Speter 				"_RELSLE" , "_RELSGE"
28771Speter 			    };
29771Speter     long	relops[] =  {
30771Speter 				P2EQ , P2NE ,
31771Speter 				P2LT , P2GT ,
32771Speter 				P2LE , P2GE
33771Speter 			    };
34771Speter     long	mathop[] =  {	P2MUL , P2PLUS , P2MINUS };
35771Speter     char	*setop[] =  {	"_MULT" , "_ADDT" , "_SUBT" };
36771Speter #endif PC
37771Speter /*
38771Speter  * Rvalue - an expression.
39771Speter  *
40771Speter  * Contype is the type that the caller would prefer, nand is important
41771Speter  * if constant sets or constant strings are involved, the latter
42771Speter  * because of string padding.
43771Speter  * required is a flag whether an lvalue or an rvalue is required.
44771Speter  * only VARs and structured things can have gt their lvalue this way.
45771Speter  */
46771Speter struct nl *
47771Speter rvalue(r, contype , required )
48771Speter 	int *r;
49771Speter 	struct nl *contype;
50771Speter 	int	required;
51771Speter {
52771Speter 	register struct nl *p, *p1;
53771Speter 	register struct nl *q;
54771Speter 	int c, c1, *rt, w, g;
55771Speter 	char *cp, *cp1, *opname;
56771Speter 	long l;
57771Speter 	double f;
58771Speter 	extern int	flagwas;
59771Speter 	struct csetstr	csetd;
60771Speter #	ifdef PC
61771Speter 	    struct nl	*rettype;
62771Speter 	    long	ctype;
63771Speter 	    long	tempoff;
64771Speter #	endif PC
65771Speter 
66771Speter 	if (r == NIL)
67771Speter 		return (NIL);
68771Speter 	if (nowexp(r))
69771Speter 		return (NIL);
70771Speter 	/*
71771Speter 	 * Pick up the name of the operation
72771Speter 	 * for future error messages.
73771Speter 	 */
74771Speter 	if (r[0] <= T_IN)
75771Speter 		opname = opnames[r[0]];
76771Speter 
77771Speter 	/*
78771Speter 	 * The root of the tree tells us what sort of expression we have.
79771Speter 	 */
80771Speter 	switch (r[0]) {
81771Speter 
82771Speter 	/*
83771Speter 	 * The constant nil
84771Speter 	 */
85771Speter 	case T_NIL:
86771Speter #		ifdef OBJ
87771Speter 		    put(2, O_CON2, 0);
88771Speter #		endif OBJ
89771Speter #		ifdef PC
90771Speter 		    putleaf( P2ICON , 0 , 0 , P2PTR|P2UNDEFINED , 0 );
91771Speter #		endif PC
92771Speter 		return (nl+TNIL);
93771Speter 
94771Speter 	/*
95771Speter 	 * Function call with arguments.
96771Speter 	 */
97771Speter 	case T_FCALL:
98771Speter #	    ifdef OBJ
99771Speter 		return (funccod(r));
100771Speter #	    endif OBJ
101771Speter #	    ifdef PC
102771Speter 		return (pcfunccod( r ));
103771Speter #	    endif PC
104771Speter 
105771Speter 	case T_VAR:
106771Speter 		p = lookup(r[2]);
107771Speter 		if (p == NIL || p->class == BADUSE)
108771Speter 			return (NIL);
109771Speter 		switch (p->class) {
110771Speter 		    case VAR:
111771Speter 			    /*
112771Speter 			     * If a variable is
113771Speter 			     * qualified then get
114771Speter 			     * the rvalue by a
115771Speter 			     * lvalue and an ind.
116771Speter 			     */
117771Speter 			    if (r[3] != NIL)
118771Speter 				    goto ind;
119771Speter 			    q = p->type;
120771Speter 			    if (q == NIL)
121771Speter 				    return (NIL);
122771Speter #			    ifdef OBJ
123771Speter 				w = width(q);
124771Speter 				switch (w) {
125771Speter 				    case 8:
126771Speter 					put(2, O_RV8 | bn << 8+INDX, p->value[0]);
127771Speter 					break;
128771Speter 				    case 4:
129771Speter 					put(2, O_RV4 | bn << 8+INDX, p->value[0]);
130771Speter 					break;
131771Speter 				    case 2:
132771Speter 					put(2, O_RV2 | bn << 8+INDX, p->value[0]);
133771Speter 					break;
134771Speter 				    case 1:
135771Speter 					put(2, O_RV1 | bn << 8+INDX, p->value[0]);
136771Speter 					break;
137771Speter 				    default:
138771Speter 					put(3, O_RV | bn << 8+INDX, p->value[0], w);
139771Speter 				}
140771Speter #			   endif OBJ
141771Speter #			   ifdef PC
142771Speter 				if ( required == RREQ ) {
143771Speter 				    putRV( p -> symbol , bn , p -> value[0]
144771Speter 					    , p2type( q ) );
145771Speter 				} else {
146771Speter 				    putLV( p -> symbol , bn , p -> value[0]
147771Speter 					    , p2type( q ) );
148771Speter 				}
149771Speter #			   endif PC
150771Speter 			   return (q);
151771Speter 
152771Speter 		    case WITHPTR:
153771Speter 		    case REF:
154771Speter 			    /*
155771Speter 			     * A lvalue for these
156771Speter 			     * is actually what one
157771Speter 			     * might consider a rvalue.
158771Speter 			     */
159771Speter ind:
160771Speter 			    q = lvalue(r, NOFLAGS , LREQ );
161771Speter 			    if (q == NIL)
162771Speter 				    return (NIL);
163771Speter #			    ifdef OBJ
164771Speter 				w = width(q);
165771Speter 				switch (w) {
166771Speter 				    case 8:
167771Speter 					    put(1, O_IND8);
168771Speter 					    break;
169771Speter 				    case 4:
170771Speter 					    put(1, O_IND4);
171771Speter 					    break;
172771Speter 				    case 2:
173771Speter 					    put(1, O_IND2);
174771Speter 					    break;
175771Speter 				    case 1:
176771Speter 					    put(1, O_IND1);
177771Speter 					    break;
178771Speter 				    default:
179771Speter 					    put(2, O_IND, w);
180771Speter 				}
181771Speter #			    endif OBJ
182771Speter #			    ifdef PC
183771Speter 				if ( required == RREQ ) {
184771Speter 				    putop( P2UNARY P2MUL , p2type( q ) );
185771Speter 				}
186771Speter #			    endif PC
187771Speter 			    return (q);
188771Speter 
189771Speter 		    case CONST:
190771Speter 			    if (r[3] != NIL) {
191771Speter 				error("%s is a constant and cannot be qualified", r[2]);
192771Speter 				return (NIL);
193771Speter 			    }
194771Speter 			    q = p->type;
195771Speter 			    if (q == NIL)
196771Speter 				    return (NIL);
197771Speter 			    if (q == nl+TSTR) {
198771Speter 				    /*
199771Speter 				     * Find the size of the string
200771Speter 				     * constant if needed.
201771Speter 				     */
202771Speter 				    cp = p->ptr[0];
203771Speter cstrng:
204771Speter 				    cp1 = cp;
205771Speter 				    for (c = 0; *cp++; c++)
206771Speter 					    continue;
207771Speter 				    if (contype != NIL && !opt('s')) {
208771Speter 					    if (width(contype) < c && classify(contype) == TSTR) {
209771Speter 						    error("Constant string too long");
210771Speter 						    return (NIL);
211771Speter 					    }
212771Speter 					    c = width(contype);
213771Speter 				    }
214771Speter #				    ifdef OBJ
215771Speter 					put( 2 + (sizeof(char *)/sizeof(short))
216771Speter 						, O_CONG, c, cp1);
217771Speter #				    endif OBJ
218771Speter #				    ifdef PC
219771Speter 					putCONG( cp1 , c , required );
220771Speter #				    endif PC
221771Speter 				    /*
222771Speter 				     * Define the string temporarily
223771Speter 				     * so later people can know its
224771Speter 				     * width.
225771Speter 				     * cleaned out by stat.
226771Speter 				     */
227771Speter 				    q = defnl(0, STR, 0, c);
228771Speter 				    q->type = q;
229771Speter 				    return (q);
230771Speter 			    }
231771Speter 			    if (q == nl+T1CHAR) {
232771Speter #				    ifdef OBJ
233771Speter 					put(2, O_CONC, p->value[0]);
234771Speter #				    endif OBJ
235771Speter #				    ifdef PC
236771Speter 					putleaf( P2ICON , p -> value[0] , 0
237771Speter 						, P2CHAR , 0 );
238771Speter #				    endif PC
239771Speter 				    return (q);
240771Speter 			    }
241771Speter 			    /*
242771Speter 			     * Every other kind of constant here
243771Speter 			     */
244771Speter 			    switch (width(q)) {
245771Speter 			    case 8:
246771Speter #ifndef DEBUG
247771Speter #				    ifdef OBJ
248771Speter 					put(2, O_CON8, p->real);
249771Speter #				    endif OBJ
250771Speter #				    ifdef PC
251771Speter 					putCON8( p -> real );
252771Speter #				    endif PC
253771Speter #else
254771Speter 				    if (hp21mx) {
255771Speter 					    f = p->real;
256771Speter 					    conv(&f);
257771Speter 					    l = f.plong;
258771Speter 					    put(2, O_CON4, l);
259771Speter 				    } else
260771Speter #					    ifdef OBJ
261771Speter 						put(2, O_CON8, p->real);
262771Speter #					    endif OBJ
263771Speter #					    ifdef PC
264771Speter 						putCON8( p -> real );
265771Speter #					    endif PC
266771Speter #endif
267771Speter 				    break;
268771Speter 			    case 4:
269771Speter #				    ifdef OBJ
270771Speter 					put(2, O_CON4, p->range[0]);
271771Speter #				    endif OBJ
272771Speter #				    ifdef PC
273771Speter 					putleaf( P2ICON , p -> range[0] , 0
274771Speter 						, P2INT , 0 );
275771Speter #				    endif PC
276771Speter 				    break;
277771Speter 			    case 2:
278771Speter #				    ifdef OBJ
279771Speter 					put(2, O_CON2, ( short ) p->range[0]);
280771Speter #				    endif OBJ
281771Speter #				    ifdef PC
282771Speter 					    /*
283771Speter 					     * make short constants ints
284771Speter 					     */
285771Speter 					putleaf( P2ICON , (short) p -> range[0]
286771Speter 						, 0 , P2INT , 0 );
287771Speter #				    endif PC
288771Speter 				    break;
289771Speter 			    case 1:
290771Speter #				    ifdef OBJ
291771Speter 					put(2, O_CON1, p->value[0]);
292771Speter #				    endif OBJ
293771Speter #				    ifdef PC
294771Speter 					    /*
295771Speter 					     * make char constants ints
296771Speter 					     */
297771Speter 					putleaf( P2ICON , p -> value[0] , 0
298771Speter 						, P2INT , 0 );
299771Speter #				    endif PC
300771Speter 				    break;
301771Speter 			    default:
302771Speter 				    panic("rval");
303771Speter 			    }
304771Speter 			    return (q);
305771Speter 
306771Speter 		    case FUNC:
307*1200Speter 		    case FFUNC:
308771Speter 			    /*
309771Speter 			     * Function call with no arguments.
310771Speter 			     */
311771Speter 			    if (r[3]) {
312771Speter 				    error("Can't qualify a function result value");
313771Speter 				    return (NIL);
314771Speter 			    }
315771Speter #			    ifdef OBJ
316771Speter 				return (funccod((int *) r));
317771Speter #			    endif OBJ
318771Speter #			    ifdef PC
319771Speter 				return (pcfunccod( r ));
320771Speter #			    endif PC
321771Speter 
322771Speter 		    case TYPE:
323771Speter 			    error("Type names (e.g. %s) allowed only in declarations", p->symbol);
324771Speter 			    return (NIL);
325771Speter 
326771Speter 		    case PROC:
327*1200Speter 		    case FPROC:
328771Speter 			    error("Procedure %s found where expression required", p->symbol);
329771Speter 			    return (NIL);
330771Speter 		    default:
331771Speter 			    panic("rvid");
332771Speter 		}
333771Speter 	/*
334771Speter 	 * Constant sets
335771Speter 	 */
336771Speter 	case T_CSET:
337771Speter #		ifdef OBJ
338771Speter 		    if ( precset( r , contype , &csetd ) ) {
339771Speter 			if ( csetd.csettype == NIL ) {
340771Speter 			    return NIL;
341771Speter 			}
342771Speter 			postcset( r , &csetd );
343771Speter 		    } else {
344771Speter 			put( 2, O_PUSH, -width(csetd.csettype));
345771Speter 			postcset( r , &csetd );
346771Speter 			setran( ( csetd.csettype ) -> type );
347771Speter 			put( 2, O_CON24, set.uprbp);
348771Speter 			put( 2, O_CON24, set.lwrb);
349771Speter 			put( 2, O_CTTOT, 5 + csetd.singcnt + 2 * csetd.paircnt);
350771Speter 		    }
351771Speter 		    return csetd.csettype;
352771Speter #		endif OBJ
353771Speter #		ifdef PC
354771Speter 		    if ( precset( r , contype , &csetd ) ) {
355771Speter 			if ( csetd.csettype == NIL ) {
356771Speter 			    return NIL;
357771Speter 			}
358771Speter 			postcset( r , &csetd );
359771Speter 		    } else {
360771Speter 			putleaf( P2ICON , 0 , 0
361771Speter 				, ADDTYPE( P2FTN | P2INT , P2PTR )
362771Speter 				, "_CTTOT" );
363771Speter 			/*
364771Speter 			 *	allocate a temporary and use it
365771Speter 			 */
366771Speter 			sizes[ cbn ].om_off -= lwidth( csetd.csettype );
367771Speter 			tempoff = sizes[ cbn ].om_off;
368771Speter 			putlbracket( ftnno , -tempoff );
369771Speter 			if ( tempoff < sizes[ cbn ].om_max ) {
370771Speter 			    sizes[ cbn ].om_max = tempoff;
371771Speter 			}
372771Speter 			putLV( 0 , cbn , tempoff , P2PTR|P2STRTY );
373771Speter 			setran( ( csetd.csettype ) -> type );
374771Speter 			putleaf( P2ICON , set.lwrb , 0 , P2INT , 0 );
375771Speter 			putop( P2LISTOP , P2INT );
376771Speter 			putleaf( P2ICON , set.uprbp , 0 , P2INT , 0 );
377771Speter 			putop( P2LISTOP , P2INT );
378771Speter 			postcset( r , &csetd );
379771Speter 			putop( P2CALL , P2INT );
380771Speter 		    }
381771Speter 		    return csetd.csettype;
382771Speter #		endif PC
383771Speter 
384771Speter 	/*
385771Speter 	 * Unary plus and minus
386771Speter 	 */
387771Speter 	case T_PLUS:
388771Speter 	case T_MINUS:
389771Speter 		q = rvalue(r[2], NIL , RREQ );
390771Speter 		if (q == NIL)
391771Speter 			return (NIL);
392771Speter 		if (isnta(q, "id")) {
393771Speter 			error("Operand of %s must be integer or real, not %s", opname, nameof(q));
394771Speter 			return (NIL);
395771Speter 		}
396771Speter 		if (r[0] == T_MINUS) {
397771Speter #		    ifdef OBJ
398771Speter 			put(1, O_NEG2 + (width(q) >> 2));
399771Speter #		    endif OBJ
400771Speter #		    ifdef PC
401771Speter 			putop( P2UNARY P2MINUS , p2type( q ) );
402771Speter #		    endif PC
403771Speter 		    return (isa(q, "d") ? q : nl+T4INT);
404771Speter 		}
405771Speter 		return (q);
406771Speter 
407771Speter 	case T_NOT:
408771Speter 		q = rvalue(r[2], NIL , RREQ );
409771Speter 		if (q == NIL)
410771Speter 			return (NIL);
411771Speter 		if (isnta(q, "b")) {
412771Speter 			error("not must operate on a Boolean, not %s", nameof(q));
413771Speter 			return (NIL);
414771Speter 		}
415771Speter #		ifdef OBJ
416771Speter 		    put(1, O_NOT);
417771Speter #		endif OBJ
418771Speter #		ifdef PC
419771Speter 		    putop( P2NOT , P2INT );
420771Speter #		endif PC
421771Speter 		return (nl+T1BOOL);
422771Speter 
423771Speter 	case T_AND:
424771Speter 	case T_OR:
425771Speter 		p = rvalue(r[2], NIL , RREQ );
426771Speter 		p1 = rvalue(r[3], NIL , RREQ );
427771Speter 		if (p == NIL || p1 == NIL)
428771Speter 			return (NIL);
429771Speter 		if (isnta(p, "b")) {
430771Speter 			error("Left operand of %s must be Boolean, not %s", opname, nameof(p));
431771Speter 			return (NIL);
432771Speter 		}
433771Speter 		if (isnta(p1, "b")) {
434771Speter 			error("Right operand of %s must be Boolean, not %s", opname, nameof(p1));
435771Speter 			return (NIL);
436771Speter 		}
437771Speter #		ifdef OBJ
438771Speter 		    put(1, r[0] == T_AND ? O_AND : O_OR);
439771Speter #		endif OBJ
440771Speter #		ifdef PC
441771Speter 			/*
442771Speter 			 * note the use of & and | rather than && and ||
443771Speter 			 * to force evaluation of all the expressions.
444771Speter 			 */
445771Speter 		    putop( r[ 0 ] == T_AND ? P2AND : P2OR , P2INT );
446771Speter #		endif PC
447771Speter 		return (nl+T1BOOL);
448771Speter 
449771Speter 	case T_DIVD:
450771Speter #		ifdef OBJ
451771Speter 		    p = rvalue(r[2], NIL , RREQ );
452771Speter 		    p1 = rvalue(r[3], NIL , RREQ );
453771Speter #		endif OBJ
454771Speter #		ifdef PC
455771Speter 			/*
456771Speter 			 *	force these to be doubles for the divide
457771Speter 			 */
458771Speter 		    p = rvalue( r[ 2 ] , NIL , RREQ );
459771Speter 		    if ( isnta( p , "d" ) ) {
460771Speter 			putop( P2SCONV , P2DOUBLE );
461771Speter 		    }
462771Speter 		    p1 = rvalue( r[ 3 ] , NIL , RREQ );
463771Speter 		    if ( isnta( p1 , "d" ) ) {
464771Speter 			putop( P2SCONV , P2DOUBLE );
465771Speter 		    }
466771Speter #		endif PC
467771Speter 		if (p == NIL || p1 == NIL)
468771Speter 			return (NIL);
469771Speter 		if (isnta(p, "id")) {
470771Speter 			error("Left operand of / must be integer or real, not %s", nameof(p));
471771Speter 			return (NIL);
472771Speter 		}
473771Speter 		if (isnta(p1, "id")) {
474771Speter 			error("Right operand of / must be integer or real, not %s", nameof(p1));
475771Speter 			return (NIL);
476771Speter 		}
477771Speter #		ifdef OBJ
478771Speter 		    return gen(NIL, r[0], width(p), width(p1));
479771Speter #		endif OBJ
480771Speter #		ifdef PC
481771Speter 		    putop( P2DIV , P2DOUBLE );
482771Speter 		    return nl + TDOUBLE;
483771Speter #		endif PC
484771Speter 
485771Speter 	case T_MULT:
486771Speter 	case T_ADD:
487771Speter 	case T_SUB:
488771Speter #		ifdef OBJ
489771Speter 		    /*
490771Speter 		     * If the context hasn't told us
491771Speter 		     * the type and a constant set is
492771Speter 		     * present on the left we need to infer
493771Speter 		     * the type from the right if possible
494771Speter 		     * before generating left side code.
495771Speter 		     */
496771Speter 		    if (contype == NIL && (rt = r[2]) != NIL && rt[1] == SAWCON) {
497771Speter 			    codeoff();
498771Speter 			    contype = rvalue(r[3], NIL , RREQ );
499771Speter 			    codeon();
500771Speter 			    if (contype == NIL)
501771Speter 				    return (NIL);
502771Speter 		    }
503771Speter 		    p = rvalue(r[2], contype , RREQ );
504771Speter 		    p1 = rvalue(r[3], p , RREQ );
505771Speter 		    if (p == NIL || p1 == NIL)
506771Speter 			    return (NIL);
507771Speter 		    if (isa(p, "id") && isa(p1, "id"))
508771Speter 			return (gen(NIL, r[0], width(p), width(p1)));
509771Speter 		    if (isa(p, "t") && isa(p1, "t")) {
510771Speter 			    if (p != p1) {
511771Speter 				    error("Set types of operands of %s must be identical", opname);
512771Speter 				    return (NIL);
513771Speter 			    }
514771Speter 			    gen(TSET, r[0], width(p), 0);
515771Speter 			    return (p);
516771Speter 		    }
517771Speter #		endif OBJ
518771Speter #		ifdef PC
519771Speter 			/*
520771Speter 			 * the second pass can't do
521771Speter 			 *	long op double  or  double op long
522771Speter 			 * so we have to know the type of both operands
523771Speter 			 * also, it gets tricky for sets, which are done
524771Speter 			 * by function calls.
525771Speter 			 */
526771Speter 		    codeoff();
527771Speter 		    p1 = rvalue( r[ 3 ] , contype , RREQ );
528771Speter 		    codeon();
529771Speter 		    if ( isa( p1 , "id" ) ) {
530771Speter 			p = rvalue( r[ 2 ] , contype , RREQ );
531771Speter 			if ( ( p == NIL ) || ( p1 == NIL ) ) {
532771Speter 			    return NIL;
533771Speter 			}
534771Speter 			if ( isa( p , "i" ) && isa( p1 , "d" ) ) {
535771Speter 			    putop( P2SCONV , P2DOUBLE );
536771Speter 			}
537771Speter 			p1 = rvalue( r[ 3 ] , contype , RREQ );
538771Speter 			if ( isa( p , "d" ) && isa( p1 , "i" ) ) {
539771Speter 			    putop( P2SCONV , P2DOUBLE );
540771Speter 			}
541771Speter 			if ( isa( p , "id" ) ) {
542771Speter 			    if ( isa( p , "d" ) || isa( p1 , "d" ) ) {
543771Speter 				ctype = P2DOUBLE;
544771Speter 				rettype = nl + TDOUBLE;
545771Speter 			    } else {
546771Speter 				ctype = P2INT;
547771Speter 				rettype = nl + T4INT;
548771Speter 			    }
549771Speter 			    putop( mathop[ r[0] - T_MULT ] , ctype );
550771Speter 			    return rettype;
551771Speter 			}
552771Speter 		    }
553771Speter 		    if ( isa( p1 , "t" ) ) {
554771Speter 			putleaf( P2ICON , 0 , 0
555771Speter 			    , ADDTYPE( ADDTYPE( P2PTR | P2STRTY , P2FTN )
556771Speter 					, P2PTR )
557771Speter 			    , setop[ r[0] - T_MULT ] );
558771Speter 			/*
559771Speter 			 *	allocate a temporary and use it
560771Speter 			 */
561771Speter 			sizes[ cbn ].om_off -= lwidth( p1 );
562771Speter 			tempoff = sizes[ cbn ].om_off;
563771Speter 			putlbracket( ftnno , -tempoff );
564771Speter 			if ( tempoff < sizes[ cbn ].om_max ) {
565771Speter 			    sizes[ cbn ].om_max = tempoff;
566771Speter 			}
567771Speter 			putLV( 0 , cbn , tempoff , P2PTR|P2STRTY );
568771Speter 			p = rvalue( r[2] , p1 , LREQ );
569771Speter 			if ( isa( p , "t" ) ) {
570771Speter 			    putop( P2LISTOP , P2INT );
571771Speter 			    if ( p == NIL || p1 == NIL ) {
572771Speter 				return NIL;
573771Speter 			    }
574771Speter 			    p1 = rvalue( r[3] , p , LREQ );
575771Speter 			    if ( p != p1 ) {
576771Speter 				error("Set types of operands of %s must be identical", opname);
577771Speter 				return NIL;
578771Speter 			    }
579771Speter 			    putop( P2LISTOP , P2INT );
580771Speter 			    putleaf( P2ICON , lwidth( p1 ) / sizeof( long ) , 0
581771Speter 				    , P2INT , 0 );
582771Speter 			    putop( P2LISTOP , P2INT );
583771Speter 			    putop( P2CALL , P2PTR | P2STRTY );
584771Speter 			    return p;
585771Speter 			}
586771Speter 		    }
587771Speter 		    if ( isnta( p1 , "idt" ) ) {
588771Speter 			    /*
589771Speter 			     *	find type of left operand for error message.
590771Speter 			     */
591771Speter 			p = rvalue( r[2] , contype , RREQ );
592771Speter 		    }
593771Speter 			/*
594771Speter 			 *	don't give spurious error messages.
595771Speter 			 */
596771Speter 		    if ( p == NIL || p1 == NIL ) {
597771Speter 			return NIL;
598771Speter 		    }
599771Speter #		endif PC
600771Speter 		if (isnta(p, "idt")) {
601771Speter 			error("Left operand of %s must be integer, real or set, not %s", opname, nameof(p));
602771Speter 			return (NIL);
603771Speter 		}
604771Speter 		if (isnta(p1, "idt")) {
605771Speter 			error("Right operand of %s must be integer, real or set, not %s", opname, nameof(p1));
606771Speter 			return (NIL);
607771Speter 		}
608771Speter 		error("Cannot mix sets with integers and reals as operands of %s", opname);
609771Speter 		return (NIL);
610771Speter 
611771Speter 	case T_MOD:
612771Speter 	case T_DIV:
613771Speter 		p = rvalue(r[2], NIL , RREQ );
614771Speter 		p1 = rvalue(r[3], NIL , RREQ );
615771Speter 		if (p == NIL || p1 == NIL)
616771Speter 			return (NIL);
617771Speter 		if (isnta(p, "i")) {
618771Speter 			error("Left operand of %s must be integer, not %s", opname, nameof(p));
619771Speter 			return (NIL);
620771Speter 		}
621771Speter 		if (isnta(p1, "i")) {
622771Speter 			error("Right operand of %s must be integer, not %s", opname, nameof(p1));
623771Speter 			return (NIL);
624771Speter 		}
625771Speter #		ifdef OBJ
626771Speter 		    return (gen(NIL, r[0], width(p), width(p1)));
627771Speter #		endif OBJ
628771Speter #		ifdef PC
629771Speter 		    putop( r[ 0 ] == T_DIV ? P2DIV : P2MOD , P2INT );
630771Speter 		    return ( nl + T4INT );
631771Speter #		endif PC
632771Speter 
633771Speter 	case T_EQ:
634771Speter 	case T_NE:
635771Speter 	case T_LT:
636771Speter 	case T_GT:
637771Speter 	case T_LE:
638771Speter 	case T_GE:
639771Speter 		/*
640771Speter 		 * Since there can be no, a priori, knowledge
641771Speter 		 * of the context type should a constant string
642771Speter 		 * or set arise, we must poke around to find such
643771Speter 		 * a type if possible.  Since constant strings can
644771Speter 		 * always masquerade as identifiers, this is always
645771Speter 		 * necessary.
646771Speter 		 */
647771Speter 		codeoff();
648771Speter 		p1 = rvalue(r[3], NIL , RREQ );
649771Speter 		codeon();
650771Speter 		if (p1 == NIL)
651771Speter 			return (NIL);
652771Speter 		contype = p1;
653771Speter #		ifdef OBJ
654771Speter 		    if (p1 == nl+TSET || p1->class == STR) {
655771Speter 			    /*
656771Speter 			     * For constant strings we want
657771Speter 			     * the longest type so as to be
658771Speter 			     * able to do padding (more importantly
659771Speter 			     * avoiding truncation). For clarity,
660771Speter 			     * we get this length here.
661771Speter 			     */
662771Speter 			    codeoff();
663771Speter 			    p = rvalue(r[2], NIL , RREQ );
664771Speter 			    codeon();
665771Speter 			    if (p == NIL)
666771Speter 				    return (NIL);
667771Speter 			    if (p1 == nl+TSET || width(p) > width(p1))
668771Speter 				    contype = p;
669771Speter 		    }
670771Speter 		    /*
671771Speter 		     * Now we generate code for
672771Speter 		     * the operands of the relational
673771Speter 		     * operation.
674771Speter 		     */
675771Speter 		    p = rvalue(r[2], contype , RREQ );
676771Speter 		    if (p == NIL)
677771Speter 			    return (NIL);
678771Speter 		    p1 = rvalue(r[3], p , RREQ );
679771Speter 		    if (p1 == NIL)
680771Speter 			    return (NIL);
681771Speter #		endif OBJ
682771Speter #		ifdef PC
683771Speter 		    c1 = classify( p1 );
684771Speter 		    if ( c1 == TSET || c1 == TSTR || c1 == TREC ) {
685771Speter 			putleaf( P2ICON , 0 , 0
686771Speter 				, ADDTYPE( P2FTN | P2INT , P2PTR )
687771Speter 				, c1 == TSET  ? relts[ r[0] - T_EQ ]
688771Speter 					      : relss[ r[0] - T_EQ ] );
689771Speter 			    /*
690771Speter 			     *	for [] and strings, comparisons are done on
691771Speter 			     *	the maximum width of the two sides.
692771Speter 			     *	for other sets, we have to ask the left side
693771Speter 			     *	what type it is based on the type of the right.
694771Speter 			     *	(this matters for intsets).
695771Speter 			     */
696771Speter 			if ( p1 == nl + TSET || c1 == TSTR ) {
697771Speter 			    codeoff();
698771Speter 			    p = rvalue( r[ 2 ] , NIL , LREQ );
699771Speter 			    codeon();
700771Speter 			    if (   p1 == nl + TSET
701771Speter 				|| lwidth( p ) > lwidth( p1 ) ) {
702771Speter 				contype = p;
703771Speter 			    }
704771Speter 			} else {
705771Speter 			    codeoff();
706771Speter 			    p = rvalue( r[ 2 ] , contype , LREQ );
707771Speter 			    codeon();
708771Speter 			    contype = p;
709771Speter 			}
710771Speter 			if ( p == NIL ) {
711771Speter 			    return NIL;
712771Speter 			}
713771Speter 			    /*
714771Speter 			     *	put out the width of the comparison.
715771Speter 			     */
716771Speter 			putleaf( P2ICON , lwidth( contype ) , 0 , P2INT , 0 );
717771Speter 			    /*
718771Speter 			     *	and the left hand side,
719771Speter 			     *	for sets, strings, records
720771Speter 			     */
721771Speter 			p = rvalue( r[ 2 ] , contype , LREQ );
722771Speter 			putop( P2LISTOP , P2INT );
723771Speter 			p1 = rvalue( r[ 3 ] , p , LREQ );
724771Speter 			putop( P2LISTOP , P2INT );
725771Speter 			putop( P2CALL , P2INT );
726771Speter 		    } else {
727771Speter 			    /*
728771Speter 			     *	the easy (scalar or error) case
729771Speter 			     */
730771Speter 			p = rvalue( r[ 2 ] , contype , RREQ );
731771Speter 			if ( p == NIL ) {
732771Speter 			    return NIL;
733771Speter 			    /*
734771Speter 			     * since the second pass can't do
735771Speter 			     *	long op double  or  double op long
736771Speter 			     * we may have to do some coercing.
737771Speter 			     */
738771Speter 			if ( isa( p , "i" ) && isa( p1 , "d" ) )
739771Speter 			    putop( P2SCONV , P2DOUBLE );
740771Speter 			}
741771Speter 			p1 = rvalue( r[ 3 ] , p , RREQ );
742771Speter 			if ( isa( p , "d" ) && isa( p1 , "i" ) )
743771Speter 			    putop( P2SCONV , P2DOUBLE );
744771Speter 			putop( relops[ r[0] - T_EQ ] , P2INT );
745771Speter 		    }
746771Speter #		endif PC
747771Speter 		c = classify(p);
748771Speter 		c1 = classify(p1);
749771Speter 		if (nocomp(c) || nocomp(c1))
750771Speter 			return (NIL);
751771Speter 		g = NIL;
752771Speter 		switch (c) {
753771Speter 			case TBOOL:
754771Speter 			case TCHAR:
755771Speter 				if (c != c1)
756771Speter 					goto clash;
757771Speter 				break;
758771Speter 			case TINT:
759771Speter 			case TDOUBLE:
760771Speter 				if (c1 != TINT && c1 != TDOUBLE)
761771Speter 					goto clash;
762771Speter 				break;
763771Speter 			case TSCAL:
764771Speter 				if (c1 != TSCAL)
765771Speter 					goto clash;
766771Speter 				if (scalar(p) != scalar(p1))
767771Speter 					goto nonident;
768771Speter 				break;
769771Speter 			case TSET:
770771Speter 				if (c1 != TSET)
771771Speter 					goto clash;
772771Speter 				if (p != p1)
773771Speter 					goto nonident;
774771Speter 				g = TSET;
775771Speter 				break;
776771Speter 			case TREC:
777771Speter 				if ( c1 != TREC ) {
778771Speter 				    goto clash;
779771Speter 				}
780771Speter 				if ( p != p1 ) {
781771Speter 				    goto nonident;
782771Speter 				}
783771Speter 				if (r[0] != T_EQ && r[0] != T_NE) {
784771Speter 					error("%s not allowed on records - only allow = and <>" , opname );
785771Speter 					return (NIL);
786771Speter 				}
787771Speter 				g = TREC;
788771Speter 				break;
789771Speter 			case TPTR:
790771Speter 			case TNIL:
791771Speter 				if (c1 != TPTR && c1 != TNIL)
792771Speter 					goto clash;
793771Speter 				if (r[0] != T_EQ && r[0] != T_NE) {
794771Speter 					error("%s not allowed on pointers - only allow = and <>" , opname );
795771Speter 					return (NIL);
796771Speter 				}
797771Speter 				break;
798771Speter 			case TSTR:
799771Speter 				if (c1 != TSTR)
800771Speter 					goto clash;
801771Speter 				if (width(p) != width(p1)) {
802771Speter 					error("Strings not same length in %s comparison", opname);
803771Speter 					return (NIL);
804771Speter 				}
805771Speter 				g = TSTR;
806771Speter 				break;
807771Speter 			default:
808771Speter 				panic("rval2");
809771Speter 		}
810771Speter #		ifdef OBJ
811771Speter 		    return (gen(g, r[0], width(p), width(p1)));
812771Speter #		endif OBJ
813771Speter #		ifdef PC
814771Speter 		    return nl + TBOOL;
815771Speter #		endif PC
816771Speter clash:
817771Speter 		error("%ss and %ss cannot be compared - operator was %s", clnames[c], clnames[c1], opname);
818771Speter 		return (NIL);
819771Speter nonident:
820771Speter 		error("%s types must be identical in comparisons - operator was %s", clnames[c1], opname);
821771Speter 		return (NIL);
822771Speter 
823771Speter 	case T_IN:
824771Speter 	    rt = r[3];
825771Speter #	    ifdef OBJ
826771Speter 		if (rt != NIL && rt[0] == T_CSET) {
827771Speter 			precset( rt , NIL , &csetd );
828771Speter 			p1 = csetd.csettype;
829771Speter 			if (p1 == NIL)
830771Speter 			    return NIL;
831771Speter 			if (p1 == nl+TSET) {
832771Speter 			    if ( !inempty ) {
833771Speter 				warning();
834771Speter 				error("... in [] makes little sense, since it is always false!");
835771Speter 				inempty = TRUE;
836771Speter 			    }
837771Speter 			    put(1, O_CON1, 0);
838771Speter 			    return (nl+T1BOOL);
839771Speter 			}
840771Speter 			postcset( rt, &csetd);
841771Speter 		    } else {
842771Speter 			p1 = stkrval(r[3], NIL , RREQ );
843771Speter 			rt = NIL;
844771Speter 		    }
845771Speter #		endif OBJ
846771Speter #		ifdef PC
847771Speter 		    if (rt != NIL && rt[0] == T_CSET) {
848771Speter 			if ( precset( rt , NIL , &csetd ) ) {
849771Speter 			    if ( csetd.csettype != nl + TSET ) {
850771Speter 				putleaf( P2ICON , 0 , 0
851771Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
852771Speter 					, "_IN" );
853771Speter 			    }
854771Speter 			} else {
855771Speter 			    putleaf( P2ICON , 0 , 0
856771Speter 				    , ADDTYPE( P2FTN | P2INT , P2PTR )
857771Speter 				    , "_INCT" );
858771Speter 			}
859771Speter 			p1 = csetd.csettype;
860771Speter 			if (p1 == NIL)
861771Speter 			    return NIL;
862771Speter 			if ( p1 == nl + TSET ) {
863771Speter 			    if ( !inempty ) {
864771Speter 				warning();
865771Speter 				error("... in [] makes little sense, since it is always false!");
866771Speter 				inempty = TRUE;
867771Speter 			    }
868771Speter 			    putleaf( P2ICON , 0 , 0 , P2INT , 0 );
869771Speter 			    return (nl+T1BOOL);
870771Speter 			}
871771Speter 		    } else {
872771Speter 			putleaf( P2ICON , 0 , 0
873771Speter 				, ADDTYPE( P2FTN | P2INT , P2PTR )
874771Speter 				, "_IN" );
875771Speter 			codeoff();
876771Speter 			p1 = rvalue(r[3], NIL , LREQ );
877771Speter 			codeon();
878771Speter 		    }
879771Speter #		endif PC
880771Speter 		p = stkrval(r[2], NIL , RREQ );
881771Speter 		if (p == NIL || p1 == NIL)
882771Speter 			return (NIL);
883771Speter 		if (p1->class != SET) {
884771Speter 			error("Right operand of 'in' must be a set, not %s", nameof(p1));
885771Speter 			return (NIL);
886771Speter 		}
887771Speter 		if (incompat(p, p1->type, r[2])) {
888771Speter 			cerror("Index type clashed with set component type for 'in'");
889771Speter 			return (NIL);
890771Speter 		}
891771Speter 		setran(p1->type);
892771Speter #		ifdef OBJ
893771Speter 		    if (rt == NIL || csetd.comptime)
894771Speter 			    put(4, O_IN, width(p1), set.lwrb, set.uprbp);
895771Speter 		    else
896771Speter 			    put(2, O_INCT, 3 + csetd.singcnt + 2*csetd.paircnt);
897771Speter #		endif OBJ
898771Speter #		ifdef PC
899771Speter 		    if ( rt == NIL || rt[0] != T_CSET ) {
900771Speter 			putleaf( P2ICON , set.lwrb , 0 , P2INT , 0 );
901771Speter 			putop( P2LISTOP , P2INT );
902771Speter 			putleaf( P2ICON , set.uprbp , 0 , P2INT , 0 );
903771Speter 			putop( P2LISTOP , P2INT );
904771Speter 			p1 = rvalue( r[3] , NIL , LREQ );
905771Speter 			putop( P2LISTOP , P2INT );
906771Speter 		    } else if ( csetd.comptime ) {
907771Speter 			putleaf( P2ICON , set.lwrb , 0 , P2INT , 0 );
908771Speter 			putop( P2LISTOP , P2INT );
909771Speter 			putleaf( P2ICON , set.uprbp , 0 , P2INT , 0 );
910771Speter 			putop( P2LISTOP , P2INT );
911771Speter 			postcset( r[3] , &csetd );
912771Speter 			putop( P2LISTOP , P2INT );
913771Speter 		    } else {
914771Speter 			postcset( r[3] , &csetd );
915771Speter 		    }
916771Speter 		    putop( P2CALL , P2INT );
917771Speter #		endif PC
918771Speter 		return (nl+T1BOOL);
919771Speter 	default:
920771Speter 		if (r[2] == NIL)
921771Speter 			return (NIL);
922771Speter 		switch (r[0]) {
923771Speter 		default:
924771Speter 			panic("rval3");
925771Speter 
926771Speter 
927771Speter 		/*
928771Speter 		 * An octal number
929771Speter 		 */
930771Speter 		case T_BINT:
931771Speter 			f = a8tol(r[2]);
932771Speter 			goto conint;
933771Speter 
934771Speter 		/*
935771Speter 		 * A decimal number
936771Speter 		 */
937771Speter 		case T_INT:
938771Speter 			f = atof(r[2]);
939771Speter conint:
940771Speter 			if (f > MAXINT || f < MININT) {
941771Speter 				error("Constant too large for this implementation");
942771Speter 				return (NIL);
943771Speter 			}
944771Speter 			l = f;
945771Speter 			if (bytes(l, l) <= 2) {
946771Speter #				ifdef OBJ
947771Speter 				    put(2, O_CON2, ( short ) l);
948771Speter #				endif OBJ
949771Speter #				ifdef PC
950771Speter 				        /*
951771Speter 					 * short constants are ints
952771Speter 					 */
953771Speter 				    putleaf( P2ICON , l , 0 , P2INT , 0 );
954771Speter #				endif PC
955771Speter 				return (nl+T2INT);
956771Speter 			}
957771Speter #			ifdef OBJ
958771Speter 			    put(2, O_CON4, l);
959771Speter #			endif OBJ
960771Speter #			ifdef PC
961771Speter 			    putleaf( P2ICON , l , 0 , P2INT , 0 );
962771Speter #			endif PC
963771Speter 			return (nl+T4INT);
964771Speter 
965771Speter 		/*
966771Speter 		 * A floating point number
967771Speter 		 */
968771Speter 		case T_FINT:
969771Speter #			ifdef OBJ
970771Speter 			    put(2, O_CON8, atof(r[2]));
971771Speter #			endif OBJ
972771Speter #			ifdef PC
973771Speter 			    putCON8( atof( r[2] ) );
974771Speter #			endif PC
975771Speter 			return (nl+TDOUBLE);
976771Speter 
977771Speter 		/*
978771Speter 		 * Constant strings.  Note that constant characters
979771Speter 		 * are constant strings of length one; there is
980771Speter 		 * no constant string of length one.
981771Speter 		 */
982771Speter 		case T_STRNG:
983771Speter 			cp = r[2];
984771Speter 			if (cp[1] == 0) {
985771Speter #				ifdef OBJ
986771Speter 				    put(2, O_CONC, cp[0]);
987771Speter #				endif OBJ
988771Speter #				ifdef PC
989771Speter 				    putleaf( P2ICON , cp[0] , 0 , P2CHAR , 0 );
990771Speter #				endif PC
991771Speter 				return (nl+T1CHAR);
992771Speter 			}
993771Speter 			goto cstrng;
994771Speter 		}
995771Speter 
996771Speter 	}
997771Speter }
998771Speter 
999771Speter /*
1000771Speter  * Can a class appear
1001771Speter  * in a comparison ?
1002771Speter  */
1003771Speter nocomp(c)
1004771Speter 	int c;
1005771Speter {
1006771Speter 
1007771Speter 	switch (c) {
1008771Speter 		case TREC:
1009771Speter 			if ( opt( 's' ) ) {
1010771Speter 			    standard();
1011771Speter 			    error("record comparison is non-standard");
1012771Speter 			}
1013771Speter 			break;
1014771Speter 		case TFILE:
1015771Speter 		case TARY:
1016771Speter 			error("%ss may not participate in comparisons", clnames[c]);
1017771Speter 			return (1);
1018771Speter 	}
1019771Speter 	return (NIL);
1020771Speter }
1021771Speter 
1022771Speter     /*
1023771Speter      *	this is sort of like gconst, except it works on expression trees
1024771Speter      *	rather than declaration trees, and doesn't give error messages for
1025771Speter      *	non-constant things.
1026771Speter      *	as a side effect this fills in the con structure that gconst uses.
1027771Speter      *	this returns TRUE or FALSE.
1028771Speter      */
1029771Speter constval(r)
1030771Speter 	register int *r;
1031771Speter {
1032771Speter 	register struct nl *np;
1033771Speter 	register *cn;
1034771Speter 	char *cp;
1035771Speter 	int negd, sgnd;
1036771Speter 	long ci;
1037771Speter 
1038771Speter 	con.ctype = NIL;
1039771Speter 	cn = r;
1040771Speter 	negd = sgnd = 0;
1041771Speter loop:
1042771Speter 	    /*
1043771Speter 	     *	cn[2] is nil if error recovery generated a T_STRNG
1044771Speter 	     */
1045771Speter 	if (cn == NIL || cn[2] == NIL)
1046771Speter 		return FALSE;
1047771Speter 	switch (cn[0]) {
1048771Speter 		default:
1049771Speter 			return FALSE;
1050771Speter 		case T_MINUS:
1051771Speter 			negd = 1 - negd;
1052771Speter 			/* and fall through */
1053771Speter 		case T_PLUS:
1054771Speter 			sgnd++;
1055771Speter 			cn = cn[2];
1056771Speter 			goto loop;
1057771Speter 		case T_NIL:
1058771Speter 			con.cpval = NIL;
1059771Speter 			con.cival = 0;
1060771Speter 			con.crval = con.cival;
1061771Speter 			con.ctype = nl + TNIL;
1062771Speter 			break;
1063771Speter 		case T_VAR:
1064771Speter 			np = lookup(cn[2]);
1065771Speter 			if (np == NIL || np->class != CONST) {
1066771Speter 				return FALSE;
1067771Speter 			}
1068771Speter 			if ( cn[3] != NIL ) {
1069771Speter 				return FALSE;
1070771Speter 			}
1071771Speter 			con.ctype = np->type;
1072771Speter 			switch (classify(np->type)) {
1073771Speter 				case TINT:
1074771Speter 					con.crval = np->range[0];
1075771Speter 					break;
1076771Speter 				case TDOUBLE:
1077771Speter 					con.crval = np->real;
1078771Speter 					break;
1079771Speter 				case TBOOL:
1080771Speter 				case TCHAR:
1081771Speter 				case TSCAL:
1082771Speter 					con.cival = np->value[0];
1083771Speter 					con.crval = con.cival;
1084771Speter 					break;
1085771Speter 				case TSTR:
1086771Speter 					con.cpval = np->ptr[0];
1087771Speter 					break;
1088771Speter 				default:
1089771Speter 					con.ctype = NIL;
1090771Speter 					return FALSE;
1091771Speter 			}
1092771Speter 			break;
1093771Speter 		case T_BINT:
1094771Speter 			con.crval = a8tol(cn[2]);
1095771Speter 			goto restcon;
1096771Speter 		case T_INT:
1097771Speter 			con.crval = atof(cn[2]);
1098771Speter 			if (con.crval > MAXINT || con.crval < MININT) {
1099771Speter 				derror("Constant too large for this implementation");
1100771Speter 				con.crval = 0;
1101771Speter 			}
1102771Speter restcon:
1103771Speter 			ci = con.crval;
1104771Speter #ifndef PI0
1105771Speter 			if (bytes(ci, ci) <= 2)
1106771Speter 				con.ctype = nl+T2INT;
1107771Speter 			else
1108771Speter #endif
1109771Speter 				con.ctype = nl+T4INT;
1110771Speter 			break;
1111771Speter 		case T_FINT:
1112771Speter 			con.ctype = nl+TDOUBLE;
1113771Speter 			con.crval = atof(cn[2]);
1114771Speter 			break;
1115771Speter 		case T_STRNG:
1116771Speter 			cp = cn[2];
1117771Speter 			if (cp[1] == 0) {
1118771Speter 				con.ctype = nl+T1CHAR;
1119771Speter 				con.cival = cp[0];
1120771Speter 				con.crval = con.cival;
1121771Speter 				break;
1122771Speter 			}
1123771Speter 			con.ctype = nl+TSTR;
1124771Speter 			con.cpval = cp;
1125771Speter 			break;
1126771Speter 	}
1127771Speter 	if (sgnd) {
1128771Speter 		if (isnta(con.ctype, "id")) {
1129771Speter 			derror("%s constants cannot be signed", nameof(con.ctype));
1130771Speter 			return FALSE;
1131771Speter 		} else if (negd)
1132771Speter 			con.crval = -con.crval;
1133771Speter 	}
1134771Speter 	return TRUE;
1135771Speter }
1136