xref: /csrg-svn/usr.bin/pascal/src/rval.c (revision 15945)
1771Speter /* Copyright (c) 1979 Regents of the University of California */
2771Speter 
3*15945Speter #ifndef lint
4*15945Speter static char sccsid[] = "@(#)rval.c 1.20 02/05/84";
515931Smckusick #endif
6771Speter 
7771Speter #include "whoami.h"
8771Speter #include "0.h"
9771Speter #include "tree.h"
10771Speter #include "opcode.h"
11771Speter #include "objfmt.h"
12771Speter #ifdef PC
13771Speter #   include	"pc.h"
14771Speter #   include "pcops.h"
15771Speter #endif PC
1611328Speter #include "tmps.h"
1715931Smckusick #include "tree_ty.h"
18771Speter 
19771Speter extern	char *opnames[];
20771Speter 
211627Speter     /* line number of the last record comparison warning */
221627Speter short reccompline = 0;
233397Speter     /* line number of the last non-standard set comparison */
243397Speter short nssetline = 0;
251627Speter 
26771Speter #ifdef PC
27771Speter     char	*relts[] =  {
28771Speter 				"_RELEQ" , "_RELNE" ,
29771Speter 				"_RELTLT" , "_RELTGT" ,
30771Speter 				"_RELTLE" , "_RELTGE"
31771Speter 			    };
32771Speter     char	*relss[] =  {
33771Speter 				"_RELEQ" , "_RELNE" ,
34771Speter 				"_RELSLT" , "_RELSGT" ,
35771Speter 				"_RELSLE" , "_RELSGE"
36771Speter 			    };
37771Speter     long	relops[] =  {
38771Speter 				P2EQ , P2NE ,
39771Speter 				P2LT , P2GT ,
40771Speter 				P2LE , P2GE
41771Speter 			    };
42771Speter     long	mathop[] =  {	P2MUL , P2PLUS , P2MINUS };
43771Speter     char	*setop[] =  {	"_MULT" , "_ADDT" , "_SUBT" };
44771Speter #endif PC
45771Speter /*
46771Speter  * Rvalue - an expression.
47771Speter  *
48771Speter  * Contype is the type that the caller would prefer, nand is important
49771Speter  * if constant sets or constant strings are involved, the latter
50771Speter  * because of string padding.
51771Speter  * required is a flag whether an lvalue or an rvalue is required.
52771Speter  * only VARs and structured things can have gt their lvalue this way.
53771Speter  */
5415931Smckusick /*ARGSUSED*/
55771Speter struct nl *
56771Speter rvalue(r, contype , required )
5715931Smckusick 	struct tnode *r;
58771Speter 	struct nl *contype;
59771Speter 	int	required;
60771Speter {
61771Speter 	register struct nl *p, *p1;
62771Speter 	register struct nl *q;
6315931Smckusick 	int c, c1, w;
6415931Smckusick #ifdef OBJ
6515931Smckusick 	int g;
6615931Smckusick #endif
6715931Smckusick 	struct tnode *rt;
68771Speter 	char *cp, *cp1, *opname;
69771Speter 	long l;
7015931Smckusick 	union
7115931Smckusick 	{
7215931Smckusick 	    long plong[2];
7315931Smckusick 	    double pdouble;
7415931Smckusick 	}f;
75771Speter 	extern int	flagwas;
76771Speter 	struct csetstr	csetd;
77771Speter #	ifdef PC
78771Speter 	    struct nl	*rettype;
79771Speter 	    long	ctype;
803834Speter 	    struct nl	*tempnlp;
81771Speter #	endif PC
82771Speter 
8315931Smckusick 	if (r == TR_NIL)
8415931Smckusick 		return (NLNIL);
85771Speter 	if (nowexp(r))
8615931Smckusick 		return (NLNIL);
87771Speter 	/*
88771Speter 	 * Pick up the name of the operation
89771Speter 	 * for future error messages.
90771Speter 	 */
9115931Smckusick 	if (r->tag <= T_IN)
9215931Smckusick 		opname = opnames[r->tag];
93771Speter 
94771Speter 	/*
95771Speter 	 * The root of the tree tells us what sort of expression we have.
96771Speter 	 */
9715931Smckusick 	switch (r->tag) {
98771Speter 
99771Speter 	/*
100771Speter 	 * The constant nil
101771Speter 	 */
102771Speter 	case T_NIL:
103771Speter #		ifdef OBJ
10415931Smckusick 		    (void) put(2, O_CON2, 0);
105771Speter #		endif OBJ
106771Speter #		ifdef PC
10715931Smckusick 		    putleaf( P2ICON , 0 , 0 , P2PTR|P2UNDEF , (char *) 0 );
108771Speter #		endif PC
109771Speter 		return (nl+TNIL);
110771Speter 
111771Speter 	/*
112771Speter 	 * Function call with arguments.
113771Speter 	 */
114771Speter 	case T_FCALL:
115771Speter #	    ifdef OBJ
116771Speter 		return (funccod(r));
117771Speter #	    endif OBJ
118771Speter #	    ifdef PC
119771Speter 		return (pcfunccod( r ));
120771Speter #	    endif PC
121771Speter 
122771Speter 	case T_VAR:
12315931Smckusick 		p = lookup(r->var_node.cptr);
12415931Smckusick 		if (p == NLNIL || p->class == BADUSE)
12515931Smckusick 			return (NLNIL);
126771Speter 		switch (p->class) {
127771Speter 		    case VAR:
128771Speter 			    /*
129771Speter 			     * If a variable is
130771Speter 			     * qualified then get
131771Speter 			     * the rvalue by a
132771Speter 			     * lvalue and an ind.
133771Speter 			     */
13415931Smckusick 			    if (r->var_node.qual != TR_NIL)
135771Speter 				    goto ind;
136771Speter 			    q = p->type;
137771Speter 			    if (q == NIL)
13815931Smckusick 				    return (NLNIL);
139771Speter #			    ifdef OBJ
140771Speter 				w = width(q);
141771Speter 				switch (w) {
142771Speter 				    case 8:
14315931Smckusick 					(void) put(2, O_RV8 | bn << 8+INDX,
1443078Smckusic 						(int)p->value[0]);
145771Speter 					break;
146771Speter 				    case 4:
14715931Smckusick 					(void) put(2, O_RV4 | bn << 8+INDX,
1483078Smckusic 						(int)p->value[0]);
149771Speter 					break;
150771Speter 				    case 2:
15115931Smckusick 					(void) put(2, O_RV2 | bn << 8+INDX,
1523078Smckusic 						(int)p->value[0]);
153771Speter 					break;
154771Speter 				    case 1:
15515931Smckusick 					(void) put(2, O_RV1 | bn << 8+INDX,
1563078Smckusic 						(int)p->value[0]);
157771Speter 					break;
158771Speter 				    default:
15915931Smckusick 					(void) put(3, O_RV | bn << 8+INDX,
1603078Smckusic 						(int)p->value[0], w);
161771Speter 				}
162771Speter #			   endif OBJ
163771Speter #			   ifdef PC
164771Speter 				if ( required == RREQ ) {
1653834Speter 				    putRV( p -> symbol , bn , p -> value[0] ,
1663834Speter 					    p -> extra_flags , p2type( q ) );
167771Speter 				} else {
1683834Speter 				    putLV( p -> symbol , bn , p -> value[0] ,
1693834Speter 					    p -> extra_flags , p2type( q ) );
170771Speter 				}
171771Speter #			   endif PC
172771Speter 			   return (q);
173771Speter 
174771Speter 		    case WITHPTR:
175771Speter 		    case REF:
176771Speter 			    /*
177771Speter 			     * A lvalue for these
178771Speter 			     * is actually what one
179771Speter 			     * might consider a rvalue.
180771Speter 			     */
181771Speter ind:
182771Speter 			    q = lvalue(r, NOFLAGS , LREQ );
183771Speter 			    if (q == NIL)
18415931Smckusick 				    return (NLNIL);
185771Speter #			    ifdef OBJ
186771Speter 				w = width(q);
187771Speter 				switch (w) {
188771Speter 				    case 8:
18915931Smckusick 					    (void) put(1, O_IND8);
190771Speter 					    break;
191771Speter 				    case 4:
19215931Smckusick 					    (void) put(1, O_IND4);
193771Speter 					    break;
194771Speter 				    case 2:
19515931Smckusick 					    (void) put(1, O_IND2);
196771Speter 					    break;
197771Speter 				    case 1:
19815931Smckusick 					    (void) put(1, O_IND1);
199771Speter 					    break;
200771Speter 				    default:
20115931Smckusick 					    (void) put(2, O_IND, w);
202771Speter 				}
203771Speter #			    endif OBJ
204771Speter #			    ifdef PC
205771Speter 				if ( required == RREQ ) {
206771Speter 				    putop( P2UNARY P2MUL , p2type( q ) );
207771Speter 				}
208771Speter #			    endif PC
209771Speter 			    return (q);
210771Speter 
211771Speter 		    case CONST:
21215931Smckusick 			    if (r->var_node.qual != TR_NIL) {
21315931Smckusick 				error("%s is a constant and cannot be qualified", r->var_node.cptr);
21415931Smckusick 				return (NLNIL);
215771Speter 			    }
216771Speter 			    q = p->type;
21715931Smckusick 			    if (q == NLNIL)
21815931Smckusick 				    return (NLNIL);
219771Speter 			    if (q == nl+TSTR) {
220771Speter 				    /*
221771Speter 				     * Find the size of the string
222771Speter 				     * constant if needed.
223771Speter 				     */
22415931Smckusick 				    cp = (char *) p->ptr[0];
225771Speter cstrng:
226771Speter 				    cp1 = cp;
227771Speter 				    for (c = 0; *cp++; c++)
228771Speter 					    continue;
2293078Smckusic 				    w = c;
230771Speter 				    if (contype != NIL && !opt('s')) {
231771Speter 					    if (width(contype) < c && classify(contype) == TSTR) {
232771Speter 						    error("Constant string too long");
23315931Smckusick 						    return (NLNIL);
234771Speter 					    }
2353078Smckusic 					    w = width(contype);
236771Speter 				    }
237771Speter #				    ifdef OBJ
23815931Smckusick 					(void) put(2, O_CONG, w);
2393078Smckusic 					putstr(cp1, w - c);
240771Speter #				    endif OBJ
241771Speter #				    ifdef PC
2423155Smckusic 					putCONG( cp1 , w , required );
243771Speter #				    endif PC
244771Speter 				    /*
245771Speter 				     * Define the string temporarily
246771Speter 				     * so later people can know its
247771Speter 				     * width.
248771Speter 				     * cleaned out by stat.
249771Speter 				     */
25015931Smckusick 				    q = defnl((char *) 0, STR, NLNIL, w);
251771Speter 				    q->type = q;
252771Speter 				    return (q);
253771Speter 			    }
254771Speter 			    if (q == nl+T1CHAR) {
255771Speter #				    ifdef OBJ
25615931Smckusick 					(void) put(2, O_CONC, (int)p->value[0]);
257771Speter #				    endif OBJ
258771Speter #				    ifdef PC
259771Speter 					putleaf( P2ICON , p -> value[0] , 0
26015931Smckusick 						, P2CHAR , (char *) 0 );
261771Speter #				    endif PC
262771Speter 				    return (q);
263771Speter 			    }
264771Speter 			    /*
265771Speter 			     * Every other kind of constant here
266771Speter 			     */
267771Speter 			    switch (width(q)) {
268771Speter 			    case 8:
269771Speter #ifndef DEBUG
270771Speter #				    ifdef OBJ
27115931Smckusick 					(void) put(2, O_CON8, p->real);
272771Speter #				    endif OBJ
273771Speter #				    ifdef PC
274771Speter 					putCON8( p -> real );
275771Speter #				    endif PC
276771Speter #else
277771Speter 				    if (hp21mx) {
27815931Smckusick 					    f.pdouble = p->real;
27915931Smckusick 					    conv((int *) (&f.pdouble));
28015931Smckusick 					    l = f.plong[1];
28115931Smckusick 					    (void) put(2, O_CON4, l);
282771Speter 				    } else
283771Speter #					    ifdef OBJ
28415931Smckusick 						(void) put(2, O_CON8, p->real);
285771Speter #					    endif OBJ
286771Speter #					    ifdef PC
287771Speter 						putCON8( p -> real );
288771Speter #					    endif PC
289771Speter #endif
290771Speter 				    break;
291771Speter 			    case 4:
292771Speter #				    ifdef OBJ
29315931Smckusick 					(void) put(2, O_CON4, p->range[0]);
294771Speter #				    endif OBJ
295771Speter #				    ifdef PC
29615931Smckusick 					putleaf( P2ICON , (int) p->range[0] , 0
29715931Smckusick 						, P2INT , (char *) 0 );
298771Speter #				    endif PC
299771Speter 				    break;
300771Speter 			    case 2:
301771Speter #				    ifdef OBJ
30215931Smckusick 					(void) put(2, O_CON2, (short)p->range[0]);
303771Speter #				    endif OBJ
304771Speter #				    ifdef PC
305771Speter 					putleaf( P2ICON , (short) p -> range[0]
30615931Smckusick 						, 0 , P2SHORT , (char *) 0 );
307771Speter #				    endif PC
308771Speter 				    break;
309771Speter 			    case 1:
310771Speter #				    ifdef OBJ
31115931Smckusick 					(void) put(2, O_CON1, p->value[0]);
312771Speter #				    endif OBJ
313771Speter #				    ifdef PC
314771Speter 					putleaf( P2ICON , p -> value[0] , 0
31515931Smckusick 						, P2CHAR , (char *) 0 );
316771Speter #				    endif PC
317771Speter 				    break;
318771Speter 			    default:
319771Speter 				    panic("rval");
320771Speter 			    }
321771Speter 			    return (q);
322771Speter 
323771Speter 		    case FUNC:
3241200Speter 		    case FFUNC:
325771Speter 			    /*
326771Speter 			     * Function call with no arguments.
327771Speter 			     */
32815931Smckusick 			    if (r->var_node.qual != TR_NIL) {
329771Speter 				    error("Can't qualify a function result value");
33015931Smckusick 				    return (NLNIL);
331771Speter 			    }
332771Speter #			    ifdef OBJ
33315931Smckusick 				return (funccod(r));
334771Speter #			    endif OBJ
335771Speter #			    ifdef PC
336771Speter 				return (pcfunccod( r ));
337771Speter #			    endif PC
338771Speter 
339771Speter 		    case TYPE:
340771Speter 			    error("Type names (e.g. %s) allowed only in declarations", p->symbol);
34115931Smckusick 			    return (NLNIL);
342771Speter 
343771Speter 		    case PROC:
3441200Speter 		    case FPROC:
345771Speter 			    error("Procedure %s found where expression required", p->symbol);
34615931Smckusick 			    return (NLNIL);
347771Speter 		    default:
348771Speter 			    panic("rvid");
349771Speter 		}
350771Speter 	/*
351771Speter 	 * Constant sets
352771Speter 	 */
353771Speter 	case T_CSET:
354771Speter #		ifdef OBJ
355771Speter 		    if ( precset( r , contype , &csetd ) ) {
356771Speter 			if ( csetd.csettype == NIL ) {
35715931Smckusick 			    return (NLNIL);
358771Speter 			}
359771Speter 			postcset( r , &csetd );
360771Speter 		    } else {
36115931Smckusick 			(void) put( 2, O_PUSH, -lwidth(csetd.csettype));
362771Speter 			postcset( r , &csetd );
363771Speter 			setran( ( csetd.csettype ) -> type );
36415931Smckusick 			(void) put( 2, O_CON24, set.uprbp);
36515931Smckusick 			(void) put( 2, O_CON24, set.lwrb);
36615931Smckusick 			(void) put( 2, O_CTTOT,
3673078Smckusic 				(int)(4 + csetd.singcnt + 2 * csetd.paircnt));
368771Speter 		    }
369771Speter 		    return csetd.csettype;
370771Speter #		endif OBJ
371771Speter #		ifdef PC
372771Speter 		    if ( precset( r , contype , &csetd ) ) {
373771Speter 			if ( csetd.csettype == NIL ) {
37415931Smckusick 			    return (NLNIL);
375771Speter 			}
376771Speter 			postcset( r , &csetd );
377771Speter 		    } else {
378771Speter 			putleaf( P2ICON , 0 , 0
379771Speter 				, ADDTYPE( P2FTN | P2INT , P2PTR )
380771Speter 				, "_CTTOT" );
381771Speter 			/*
382771Speter 			 *	allocate a temporary and use it
383771Speter 			 */
3843834Speter 			tempnlp = tmpalloc(lwidth(csetd.csettype),
3853227Smckusic 				csetd.csettype, NOREG);
38615931Smckusick 			putLV( (char *) 0 , cbn , tempnlp -> value[ NL_OFFS ] ,
3873834Speter 				tempnlp -> extra_flags , P2PTR|P2STRTY );
388771Speter 			setran( ( csetd.csettype ) -> type );
38915931Smckusick 			putleaf( P2ICON , set.lwrb , 0 , P2INT , (char *) 0 );
390771Speter 			putop( P2LISTOP , P2INT );
39115931Smckusick 			putleaf( P2ICON , set.uprbp , 0 , P2INT , (char *) 0 );
392771Speter 			putop( P2LISTOP , P2INT );
393771Speter 			postcset( r , &csetd );
394771Speter 			putop( P2CALL , P2INT );
395771Speter 		    }
396771Speter 		    return csetd.csettype;
397771Speter #		endif PC
398771Speter 
399771Speter 	/*
400771Speter 	 * Unary plus and minus
401771Speter 	 */
402771Speter 	case T_PLUS:
403771Speter 	case T_MINUS:
40415931Smckusick 		q = rvalue(r->un_expr.expr, NLNIL , RREQ );
40515931Smckusick 		if (q == NLNIL)
40615931Smckusick 			return (NLNIL);
407771Speter 		if (isnta(q, "id")) {
408771Speter 			error("Operand of %s must be integer or real, not %s", opname, nameof(q));
40915931Smckusick 			return (NLNIL);
410771Speter 		}
41115931Smckusick 		if (r->tag == T_MINUS) {
412771Speter #		    ifdef OBJ
41315931Smckusick 			(void) put(1, O_NEG2 + (width(q) >> 2));
41410670Speter 			return (isa(q, "d") ? q : nl+T4INT);
415771Speter #		    endif OBJ
416771Speter #		    ifdef PC
41710670Speter 			if (isa(q, "i")) {
41810670Speter 			    sconv(p2type(q), P2INT);
41910670Speter 			    putop( P2UNARY P2MINUS, P2INT);
42010670Speter 			    return nl+T4INT;
42110670Speter 			}
42210670Speter 			putop( P2UNARY P2MINUS, P2DOUBLE);
42310670Speter 			return nl+TDOUBLE;
424771Speter #		    endif PC
425771Speter 		}
426771Speter 		return (q);
427771Speter 
428771Speter 	case T_NOT:
42915931Smckusick 		q = rvalue(r->un_expr.expr, NLNIL , RREQ );
43015931Smckusick 		if (q == NLNIL)
43115931Smckusick 			return (NLNIL);
432771Speter 		if (isnta(q, "b")) {
433771Speter 			error("not must operate on a Boolean, not %s", nameof(q));
43415931Smckusick 			return (NLNIL);
435771Speter 		}
436771Speter #		ifdef OBJ
43715931Smckusick 		    (void) put(1, O_NOT);
438771Speter #		endif OBJ
439771Speter #		ifdef PC
44010364Smckusick 		    sconv(p2type(q), P2INT);
44110364Smckusick 		    putop( P2NOT , P2INT);
44210364Smckusick 		    sconv(P2INT, p2type(q));
443771Speter #		endif PC
444771Speter 		return (nl+T1BOOL);
445771Speter 
446771Speter 	case T_AND:
447771Speter 	case T_OR:
44815931Smckusick 		p = rvalue(r->expr_node.lhs, NLNIL , RREQ );
44910364Smckusick #		ifdef PC
45010364Smckusick 		    sconv(p2type(p),P2INT);
45110364Smckusick #		endif PC
45215931Smckusick 		p1 = rvalue(r->expr_node.rhs, NLNIL , RREQ );
45310364Smckusick #		ifdef PC
45410364Smckusick 		    sconv(p2type(p1),P2INT);
45510364Smckusick #		endif PC
45615931Smckusick 		if (p == NLNIL || p1 == NLNIL)
45715931Smckusick 			return (NLNIL);
458771Speter 		if (isnta(p, "b")) {
459771Speter 			error("Left operand of %s must be Boolean, not %s", opname, nameof(p));
46015931Smckusick 			return (NLNIL);
461771Speter 		}
462771Speter 		if (isnta(p1, "b")) {
463771Speter 			error("Right operand of %s must be Boolean, not %s", opname, nameof(p1));
46415931Smckusick 			return (NLNIL);
465771Speter 		}
466771Speter #		ifdef OBJ
46715931Smckusick 		    (void) put(1, r->tag == T_AND ? O_AND : O_OR);
468771Speter #		endif OBJ
469771Speter #		ifdef PC
470771Speter 			/*
471771Speter 			 * note the use of & and | rather than && and ||
472771Speter 			 * to force evaluation of all the expressions.
473771Speter 			 */
47415931Smckusick 		    putop( r->tag == T_AND ? P2AND : P2OR , P2INT );
47510364Smckusick 		    sconv(P2INT, p2type(p));
476771Speter #		endif PC
477771Speter 		return (nl+T1BOOL);
478771Speter 
479771Speter 	case T_DIVD:
480771Speter #		ifdef OBJ
48115931Smckusick 		    p = rvalue(r->expr_node.lhs, NLNIL , RREQ );
48215931Smckusick 		    p1 = rvalue(r->expr_node.rhs, NLNIL , RREQ );
483771Speter #		endif OBJ
484771Speter #		ifdef PC
485771Speter 			/*
486771Speter 			 *	force these to be doubles for the divide
487771Speter 			 */
48815931Smckusick 		    p = rvalue( r->expr_node.lhs , NLNIL , RREQ );
48910364Smckusick 		    sconv(p2type(p), P2DOUBLE);
49015931Smckusick 		    p1 = rvalue( r->expr_node.rhs , NLNIL , RREQ );
49110364Smckusick 		    sconv(p2type(p1), P2DOUBLE);
492771Speter #		endif PC
49315931Smckusick 		if (p == NLNIL || p1 == NLNIL)
49415931Smckusick 			return (NLNIL);
495771Speter 		if (isnta(p, "id")) {
496771Speter 			error("Left operand of / must be integer or real, not %s", nameof(p));
49715931Smckusick 			return (NLNIL);
498771Speter 		}
499771Speter 		if (isnta(p1, "id")) {
500771Speter 			error("Right operand of / must be integer or real, not %s", nameof(p1));
50115931Smckusick 			return (NLNIL);
502771Speter 		}
503771Speter #		ifdef OBJ
50415931Smckusick 		    return gen(NIL, r->tag, width(p), width(p1));
505771Speter #		endif OBJ
506771Speter #		ifdef PC
507771Speter 		    putop( P2DIV , P2DOUBLE );
508771Speter 		    return nl + TDOUBLE;
509771Speter #		endif PC
510771Speter 
511771Speter 	case T_MULT:
512771Speter 	case T_ADD:
513771Speter 	case T_SUB:
514771Speter #		ifdef OBJ
515771Speter 		    /*
5161555Speter 		     * If the context hasn't told us the type
5171555Speter 		     * and a constant set is present
5181555Speter 		     * we need to infer the type
5191555Speter 		     * before generating code.
520771Speter 		     */
52115937Smckusick 		    if ( contype == NLNIL ) {
522771Speter 			    codeoff();
52315931Smckusick 			    contype = rvalue( r->expr_node.rhs , NLNIL , RREQ );
524771Speter 			    codeon();
525771Speter 		    }
52615937Smckusick 		    if ( contype == NLNIL ) {
52715931Smckusick 			return NLNIL;
5281555Speter 		    }
52915931Smckusick 		    p = rvalue( r->expr_node.lhs , contype , RREQ );
53015931Smckusick 		    p1 = rvalue( r->expr_node.rhs , p , RREQ );
53115937Smckusick 		    if ( p == NLNIL || p1 == NLNIL )
53215931Smckusick 			    return NLNIL;
533771Speter 		    if (isa(p, "id") && isa(p1, "id"))
53415931Smckusick 			return (gen(NIL, r->tag, width(p), width(p1)));
535771Speter 		    if (isa(p, "t") && isa(p1, "t")) {
536771Speter 			    if (p != p1) {
537771Speter 				    error("Set types of operands of %s must be identical", opname);
53815931Smckusick 				    return (NLNIL);
539771Speter 			    }
54015931Smckusick 			    (void) gen(TSET, r->tag, width(p), 0);
541771Speter 			    return (p);
542771Speter 		    }
543771Speter #		endif OBJ
544771Speter #		ifdef PC
545771Speter 			/*
546771Speter 			 * the second pass can't do
547771Speter 			 *	long op double  or  double op long
548771Speter 			 * so we have to know the type of both operands
549771Speter 			 * also, it gets tricky for sets, which are done
550771Speter 			 * by function calls.
551771Speter 			 */
552771Speter 		    codeoff();
55315931Smckusick 		    p1 = rvalue( r->expr_node.rhs , contype , RREQ );
554771Speter 		    codeon();
555771Speter 		    if ( isa( p1 , "id" ) ) {
55615931Smckusick 			p = rvalue( r->expr_node.lhs , contype , RREQ );
55715937Smckusick 			if ( ( p == NLNIL ) || ( p1 == NLNIL ) ) {
55815931Smckusick 			    return NLNIL;
559771Speter 			}
56015931Smckusick 			tuac(p, p1, &rettype, (int *) (&ctype));
56115931Smckusick 			p1 = rvalue( r->expr_node.rhs , contype , RREQ );
56215931Smckusick 			tuac(p1, p, &rettype, (int *) (&ctype));
563771Speter 			if ( isa( p , "id" ) ) {
56415931Smckusick 			    putop( (int) mathop[r->tag - T_MULT], (int) ctype);
565771Speter 			    return rettype;
566771Speter 			}
567771Speter 		    }
568771Speter 		    if ( isa( p1 , "t" ) ) {
569771Speter 			putleaf( P2ICON , 0 , 0
570771Speter 			    , ADDTYPE( ADDTYPE( P2PTR | P2STRTY , P2FTN )
571771Speter 					, P2PTR )
57215931Smckusick 			    , setop[ r->tag - T_MULT ] );
57315937Smckusick 			if ( contype == NLNIL ) {
57415937Smckusick 			    codeoff();
57515937Smckusick 			    contype = rvalue( r->expr_node.lhs, p1 , LREQ );
57615937Smckusick 			    codeon();
5771555Speter 			}
57815937Smckusick 			if ( contype == NLNIL ) {
57915931Smckusick 			    return NLNIL;
5801555Speter 			}
5811555Speter 			    /*
5821555Speter 			     *	allocate a temporary and use it
5831555Speter 			     */
5843834Speter 			tempnlp = tmpalloc(lwidth(contype), contype, NOREG);
58515931Smckusick 			putLV((char *) 0 , cbn , tempnlp -> value[ NL_OFFS ] ,
5863834Speter 				tempnlp -> extra_flags , P2PTR|P2STRTY );
58715931Smckusick 			p = rvalue( r->expr_node.lhs , contype , LREQ );
588771Speter 			if ( isa( p , "t" ) ) {
589771Speter 			    putop( P2LISTOP , P2INT );
59015937Smckusick 			    if ( p == NLNIL || p1 == NLNIL ) {
59115931Smckusick 				return NLNIL;
592771Speter 			    }
59315931Smckusick 			    p1 = rvalue( r->expr_node.rhs , p , LREQ );
594771Speter 			    if ( p != p1 ) {
595771Speter 				error("Set types of operands of %s must be identical", opname);
59615931Smckusick 				return NLNIL;
597771Speter 			    }
598771Speter 			    putop( P2LISTOP , P2INT );
59915931Smckusick 			    putleaf( P2ICON , (int) (lwidth(p1)) / sizeof( long ) , 0
60015931Smckusick 				    , P2INT , (char *) 0 );
601771Speter 			    putop( P2LISTOP , P2INT );
602771Speter 			    putop( P2CALL , P2PTR | P2STRTY );
603771Speter 			    return p;
604771Speter 			}
605771Speter 		    }
606771Speter 		    if ( isnta( p1 , "idt" ) ) {
607771Speter 			    /*
608771Speter 			     *	find type of left operand for error message.
609771Speter 			     */
61015931Smckusick 			p = rvalue( r->expr_node.lhs , contype , RREQ );
611771Speter 		    }
612771Speter 			/*
613771Speter 			 *	don't give spurious error messages.
614771Speter 			 */
61515937Smckusick 		    if ( p == NLNIL || p1 == NLNIL ) {
61615931Smckusick 			return NLNIL;
617771Speter 		    }
618771Speter #		endif PC
619771Speter 		if (isnta(p, "idt")) {
620771Speter 			error("Left operand of %s must be integer, real or set, not %s", opname, nameof(p));
62115931Smckusick 			return (NLNIL);
622771Speter 		}
623771Speter 		if (isnta(p1, "idt")) {
624771Speter 			error("Right operand of %s must be integer, real or set, not %s", opname, nameof(p1));
62515931Smckusick 			return (NLNIL);
626771Speter 		}
627771Speter 		error("Cannot mix sets with integers and reals as operands of %s", opname);
62815931Smckusick 		return (NLNIL);
629771Speter 
630771Speter 	case T_MOD:
631771Speter 	case T_DIV:
63215931Smckusick 		p = rvalue(r->expr_node.lhs, NLNIL , RREQ );
63310364Smckusick #		ifdef PC
63410364Smckusick 		    sconv(p2type(p), P2INT);
63510364Smckusick #		endif PC
63615931Smckusick 		p1 = rvalue(r->expr_node.rhs, NLNIL , RREQ );
63710364Smckusick #		ifdef PC
63810364Smckusick 		    sconv(p2type(p1), P2INT);
63910364Smckusick #		endif PC
64015937Smckusick 		if (p == NLNIL || p1 == NLNIL)
64115931Smckusick 			return (NLNIL);
642771Speter 		if (isnta(p, "i")) {
643771Speter 			error("Left operand of %s must be integer, not %s", opname, nameof(p));
64415931Smckusick 			return (NLNIL);
645771Speter 		}
646771Speter 		if (isnta(p1, "i")) {
647771Speter 			error("Right operand of %s must be integer, not %s", opname, nameof(p1));
64815931Smckusick 			return (NLNIL);
649771Speter 		}
650771Speter #		ifdef OBJ
65115931Smckusick 		    return (gen(NIL, r->tag, width(p), width(p1)));
652771Speter #		endif OBJ
653771Speter #		ifdef PC
65415931Smckusick 		    putop( r->tag == T_DIV ? P2DIV : P2MOD , P2INT );
655771Speter 		    return ( nl + T4INT );
656771Speter #		endif PC
657771Speter 
658771Speter 	case T_EQ:
659771Speter 	case T_NE:
660771Speter 	case T_LT:
661771Speter 	case T_GT:
662771Speter 	case T_LE:
663771Speter 	case T_GE:
664771Speter 		/*
665771Speter 		 * Since there can be no, a priori, knowledge
666771Speter 		 * of the context type should a constant string
667771Speter 		 * or set arise, we must poke around to find such
668771Speter 		 * a type if possible.  Since constant strings can
669771Speter 		 * always masquerade as identifiers, this is always
670771Speter 		 * necessary.
671771Speter 		 */
672771Speter 		codeoff();
67315931Smckusick 		p1 = rvalue(r->expr_node.rhs, NLNIL , RREQ );
674771Speter 		codeon();
67515931Smckusick 		if (p1 == NLNIL)
67615931Smckusick 			return (NLNIL);
677771Speter 		contype = p1;
678771Speter #		ifdef OBJ
6791555Speter 		    if (p1->class == STR) {
680771Speter 			    /*
681771Speter 			     * For constant strings we want
682771Speter 			     * the longest type so as to be
683771Speter 			     * able to do padding (more importantly
684771Speter 			     * avoiding truncation). For clarity,
685771Speter 			     * we get this length here.
686771Speter 			     */
687771Speter 			    codeoff();
68815931Smckusick 			    p = rvalue(r->expr_node.lhs, NLNIL , RREQ );
689771Speter 			    codeon();
69015931Smckusick 			    if (p == NLNIL)
69115931Smckusick 				    return (NLNIL);
6921555Speter 			    if (width(p) > width(p1))
693771Speter 				    contype = p;
694771Speter 		    }
695771Speter 		    /*
696771Speter 		     * Now we generate code for
697771Speter 		     * the operands of the relational
698771Speter 		     * operation.
699771Speter 		     */
70015931Smckusick 		    p = rvalue(r->expr_node.lhs, contype , RREQ );
70115931Smckusick 		    if (p == NLNIL)
70215931Smckusick 			    return (NLNIL);
70315931Smckusick 		    p1 = rvalue(r->expr_node.rhs, p , RREQ );
70415931Smckusick 		    if (p1 == NLNIL)
70515931Smckusick 			    return (NLNIL);
706771Speter #		endif OBJ
707771Speter #		ifdef PC
708771Speter 		    c1 = classify( p1 );
709771Speter 		    if ( c1 == TSET || c1 == TSTR || c1 == TREC ) {
710771Speter 			putleaf( P2ICON , 0 , 0
711771Speter 				, ADDTYPE( P2FTN | P2INT , P2PTR )
71215931Smckusick 				, c1 == TSET  ? relts[ r->tag - T_EQ ]
71315931Smckusick 					      : relss[ r->tag - T_EQ ] );
714771Speter 			    /*
715771Speter 			     *	for [] and strings, comparisons are done on
716771Speter 			     *	the maximum width of the two sides.
717771Speter 			     *	for other sets, we have to ask the left side
718771Speter 			     *	what type it is based on the type of the right.
719771Speter 			     *	(this matters for intsets).
720771Speter 			     */
7211555Speter 			if ( c1 == TSTR ) {
722771Speter 			    codeoff();
72315931Smckusick 			    p = rvalue( r->expr_node.lhs , NLNIL , LREQ );
724771Speter 			    codeon();
72515931Smckusick 			    if ( p == NLNIL ) {
72615931Smckusick 				return NLNIL;
7271555Speter 			    }
7281555Speter 			    if ( lwidth( p ) > lwidth( p1 ) ) {
729771Speter 				contype = p;
730771Speter 			    }
7311555Speter 			} else if ( c1 == TSET ) {
73215937Smckusick 			    codeoff();
73315937Smckusick 			    p = rvalue( r->expr_node.lhs , contype , LREQ );
73415937Smckusick 			    codeon();
73515937Smckusick 			    if ( p == NLNIL ) {
73615937Smckusick 				return NLNIL;
7371555Speter 			    }
73815937Smckusick 			    contype = p;
7391627Speter 			}
740771Speter 			    /*
741771Speter 			     *	put out the width of the comparison.
742771Speter 			     */
74315931Smckusick 			putleaf(P2ICON, (int) lwidth(contype), 0, P2INT, (char *) 0);
744771Speter 			    /*
745771Speter 			     *	and the left hand side,
746771Speter 			     *	for sets, strings, records
747771Speter 			     */
74815931Smckusick 			p = rvalue( r->expr_node.lhs , contype , LREQ );
74915931Smckusick 			if ( p == NLNIL ) {
75015931Smckusick 			    return NLNIL;
7515413Speter 			}
752771Speter 			putop( P2LISTOP , P2INT );
75315931Smckusick 			p1 = rvalue( r->expr_node.rhs , p , LREQ );
75415931Smckusick 			if ( p1 == NLNIL ) {
75515931Smckusick 			    return NLNIL;
7565413Speter 			}
757771Speter 			putop( P2LISTOP , P2INT );
758771Speter 			putop( P2CALL , P2INT );
759771Speter 		    } else {
760771Speter 			    /*
761771Speter 			     *	the easy (scalar or error) case
762771Speter 			     */
76315931Smckusick 			p = rvalue( r->expr_node.lhs , contype , RREQ );
76415931Smckusick 			if ( p == NLNIL ) {
76515931Smckusick 			    return NLNIL;
7662056Speter 			}
767771Speter 			    /*
768771Speter 			     * since the second pass can't do
769771Speter 			     *	long op double  or  double op long
770771Speter 			     * we may have to do some coercing.
771771Speter 			     */
77215931Smckusick 			tuac(p, p1, &rettype, (int *) (&ctype));
77315931Smckusick 			p1 = rvalue( r->expr_node.rhs , p , RREQ );
77415931Smckusick 			if ( p1 == NLNIL ) {
77515931Smckusick 			    return NLNIL;
7765413Speter 			}
77715931Smckusick 			tuac(p1, p, &rettype, (int *) (&ctype));
77815931Smckusick 			putop((int) relops[ r->tag - T_EQ ] , P2INT );
77910364Smckusick 			sconv(P2INT, P2CHAR);
780771Speter 		    }
781771Speter #		endif PC
782771Speter 		c = classify(p);
783771Speter 		c1 = classify(p1);
784771Speter 		if (nocomp(c) || nocomp(c1))
78515931Smckusick 			return (NLNIL);
78615931Smckusick #		ifdef OBJ
78715931Smckusick 		    g = NIL;
78815931Smckusick #		endif
789771Speter 		switch (c) {
790771Speter 			case TBOOL:
791771Speter 			case TCHAR:
792771Speter 				if (c != c1)
793771Speter 					goto clash;
794771Speter 				break;
795771Speter 			case TINT:
796771Speter 			case TDOUBLE:
797771Speter 				if (c1 != TINT && c1 != TDOUBLE)
798771Speter 					goto clash;
799771Speter 				break;
800771Speter 			case TSCAL:
801771Speter 				if (c1 != TSCAL)
802771Speter 					goto clash;
803771Speter 				if (scalar(p) != scalar(p1))
804771Speter 					goto nonident;
805771Speter 				break;
806771Speter 			case TSET:
807771Speter 				if (c1 != TSET)
808771Speter 					goto clash;
8093397Speter 				if ( opt( 's' ) &&
81015931Smckusick 				    ( ( r->tag == T_LT) || (r->tag == T_GT) ) &&
8113397Speter 				    ( line != nssetline ) ) {
8123397Speter 				    nssetline = line;
8133397Speter 				    standard();
8143397Speter 				    error("%s comparison on sets is non-standard" , opname );
8153397Speter 				}
816771Speter 				if (p != p1)
817771Speter 					goto nonident;
81815931Smckusick #				ifdef OBJ
81915931Smckusick 				    g = TSET;
82015931Smckusick #				endif
821771Speter 				break;
822771Speter 			case TREC:
823771Speter 				if ( c1 != TREC ) {
824771Speter 				    goto clash;
825771Speter 				}
826771Speter 				if ( p != p1 ) {
827771Speter 				    goto nonident;
828771Speter 				}
82915931Smckusick 				if (r->tag != T_EQ && r->tag != T_NE) {
830771Speter 					error("%s not allowed on records - only allow = and <>" , opname );
83115931Smckusick 					return (NLNIL);
832771Speter 				}
83315931Smckusick #				ifdef OBJ
83415931Smckusick 				    g = TREC;
83515931Smckusick #				endif
836771Speter 				break;
837771Speter 			case TPTR:
838771Speter 			case TNIL:
839771Speter 				if (c1 != TPTR && c1 != TNIL)
840771Speter 					goto clash;
84115931Smckusick 				if (r->tag != T_EQ && r->tag != T_NE) {
842771Speter 					error("%s not allowed on pointers - only allow = and <>" , opname );
84315931Smckusick 					return (NLNIL);
844771Speter 				}
84515937Smckusick 				if (p != nl+TNIL && p1 != nl+TNIL && p != p1)
84615937Smckusick 					goto nonident;
847771Speter 				break;
848771Speter 			case TSTR:
849771Speter 				if (c1 != TSTR)
850771Speter 					goto clash;
851771Speter 				if (width(p) != width(p1)) {
852771Speter 					error("Strings not same length in %s comparison", opname);
85315931Smckusick 					return (NLNIL);
854771Speter 				}
85515931Smckusick #				ifdef OBJ
85615931Smckusick 				    g = TSTR;
85715931Smckusick #				endif OBJ
858771Speter 				break;
859771Speter 			default:
860771Speter 				panic("rval2");
861771Speter 		}
862771Speter #		ifdef OBJ
86315931Smckusick 		    return (gen(g, r->tag, width(p), width(p1)));
864771Speter #		endif OBJ
865771Speter #		ifdef PC
866771Speter 		    return nl + TBOOL;
867771Speter #		endif PC
868771Speter clash:
869771Speter 		error("%ss and %ss cannot be compared - operator was %s", clnames[c], clnames[c1], opname);
87015931Smckusick 		return (NLNIL);
871771Speter nonident:
872771Speter 		error("%s types must be identical in comparisons - operator was %s", clnames[c1], opname);
87315931Smckusick 		return (NLNIL);
874771Speter 
875771Speter 	case T_IN:
87615931Smckusick 	    rt = r->expr_node.rhs;
877771Speter #	    ifdef OBJ
87815931Smckusick 		if (rt != TR_NIL && rt->tag == T_CSET) {
87915931Smckusick 			(void) precset( rt , NLNIL , &csetd );
880771Speter 			p1 = csetd.csettype;
88115931Smckusick 			if (p1 == NLNIL)
88215931Smckusick 			    return NLNIL;
883771Speter 			postcset( rt, &csetd);
884771Speter 		    } else {
88515931Smckusick 			p1 = stkrval(r->expr_node.rhs, NLNIL , (long) RREQ );
88615931Smckusick 			rt = TR_NIL;
887771Speter 		    }
888771Speter #		endif OBJ
889771Speter #		ifdef PC
89015931Smckusick 		    if (rt != TR_NIL && rt->tag == T_CSET) {
89115931Smckusick 			if ( precset( rt , NLNIL , &csetd ) ) {
8921555Speter 			    putleaf( P2ICON , 0 , 0
8931555Speter 				    , ADDTYPE( P2FTN | P2INT , P2PTR )
8941555Speter 				    , "_IN" );
895771Speter 			} else {
896771Speter 			    putleaf( P2ICON , 0 , 0
897771Speter 				    , ADDTYPE( P2FTN | P2INT , P2PTR )
898771Speter 				    , "_INCT" );
899771Speter 			}
900771Speter 			p1 = csetd.csettype;
901771Speter 			if (p1 == NIL)
90215931Smckusick 			    return NLNIL;
903771Speter 		    } else {
904771Speter 			putleaf( P2ICON , 0 , 0
905771Speter 				, ADDTYPE( P2FTN | P2INT , P2PTR )
906771Speter 				, "_IN" );
907771Speter 			codeoff();
90815931Smckusick 			p1 = rvalue(r->expr_node.rhs, NLNIL , LREQ );
909771Speter 			codeon();
910771Speter 		    }
911771Speter #		endif PC
91215931Smckusick 		p = stkrval(r->expr_node.lhs, NLNIL , (long) RREQ );
913771Speter 		if (p == NIL || p1 == NIL)
91415931Smckusick 			return (NLNIL);
91515931Smckusick 		if (p1->class != (char) SET) {
916771Speter 			error("Right operand of 'in' must be a set, not %s", nameof(p1));
91715931Smckusick 			return (NLNIL);
918771Speter 		}
91915931Smckusick 		if (incompat(p, p1->type, r->expr_node.lhs)) {
920771Speter 			cerror("Index type clashed with set component type for 'in'");
92115931Smckusick 			return (NLNIL);
922771Speter 		}
923771Speter 		setran(p1->type);
924771Speter #		ifdef OBJ
92515931Smckusick 		    if (rt == TR_NIL || csetd.comptime)
92615931Smckusick 			    (void) put(4, O_IN, width(p1), set.lwrb, set.uprbp);
927771Speter 		    else
92815931Smckusick 			    (void) put(2, O_INCT,
9293078Smckusic 				(int)(3 + csetd.singcnt + 2*csetd.paircnt));
930771Speter #		endif OBJ
931771Speter #		ifdef PC
93215931Smckusick 		    if ( rt == TR_NIL || rt->tag != T_CSET ) {
93315931Smckusick 			putleaf( P2ICON , set.lwrb , 0 , P2INT , (char *) 0 );
934771Speter 			putop( P2LISTOP , P2INT );
93515931Smckusick 			putleaf( P2ICON , set.uprbp , 0 , P2INT , (char *) 0 );
936771Speter 			putop( P2LISTOP , P2INT );
93715931Smckusick 			p1 = rvalue( r->expr_node.rhs , NLNIL , LREQ );
93815931Smckusick 			if ( p1 == NLNIL ) {
93915931Smckusick 			    return NLNIL;
9405413Speter 			}
941771Speter 			putop( P2LISTOP , P2INT );
942771Speter 		    } else if ( csetd.comptime ) {
94315931Smckusick 			putleaf( P2ICON , set.lwrb , 0 , P2INT , (char *) 0 );
944771Speter 			putop( P2LISTOP , P2INT );
94515931Smckusick 			putleaf( P2ICON , set.uprbp , 0 , P2INT , (char *) 0 );
946771Speter 			putop( P2LISTOP , P2INT );
94715931Smckusick 			postcset( r->expr_node.rhs , &csetd );
948771Speter 			putop( P2LISTOP , P2INT );
949771Speter 		    } else {
95015931Smckusick 			postcset( r->expr_node.rhs , &csetd );
951771Speter 		    }
952771Speter 		    putop( P2CALL , P2INT );
95310364Smckusick 		    sconv(P2INT, P2CHAR);
954771Speter #		endif PC
955771Speter 		return (nl+T1BOOL);
956771Speter 	default:
95715931Smckusick 		if (r->expr_node.lhs == TR_NIL)
95815931Smckusick 			return (NLNIL);
95915931Smckusick 		switch (r->tag) {
960771Speter 		default:
961771Speter 			panic("rval3");
962771Speter 
963771Speter 
964771Speter 		/*
965771Speter 		 * An octal number
966771Speter 		 */
967771Speter 		case T_BINT:
96815931Smckusick 			f.pdouble = a8tol(r->const_node.cptr);
969771Speter 			goto conint;
970771Speter 
971771Speter 		/*
972771Speter 		 * A decimal number
973771Speter 		 */
974771Speter 		case T_INT:
97515931Smckusick 			f.pdouble = atof(r->const_node.cptr);
976771Speter conint:
97715931Smckusick 			if (f.pdouble > MAXINT || f.pdouble < MININT) {
978771Speter 				error("Constant too large for this implementation");
97915931Smckusick 				return (NLNIL);
980771Speter 			}
98115931Smckusick 			l = f.pdouble;
98210364Smckusick #			ifdef OBJ
98310364Smckusick 			    if (bytes(l, l) <= 2) {
98415931Smckusick 				    (void) put(2, O_CON2, ( short ) l);
98510364Smckusick 				    return (nl+T2INT);
98610364Smckusick 			    }
98715931Smckusick 			    (void) put(2, O_CON4, l);
98810364Smckusick 			    return (nl+T4INT);
989771Speter #			endif OBJ
990771Speter #			ifdef PC
99110364Smckusick 			    switch (bytes(l, l)) {
99210364Smckusick 				case 1:
99315931Smckusick 				    putleaf(P2ICON, (int) l, 0, P2CHAR,
99415931Smckusick 						(char *) 0);
99510364Smckusick 				    return nl+T1INT;
99610364Smckusick 				case 2:
99715931Smckusick 				    putleaf(P2ICON, (int) l, 0, P2SHORT,
99815931Smckusick 						(char *) 0);
99910364Smckusick 				    return nl+T2INT;
100010364Smckusick 				case 4:
100115931Smckusick 				    putleaf(P2ICON, (int) l, 0, P2INT,
100215931Smckusick 						(char *) 0);
100310364Smckusick 				    return nl+T4INT;
100410364Smckusick 			    }
1005771Speter #			endif PC
1006771Speter 
1007771Speter 		/*
1008771Speter 		 * A floating point number
1009771Speter 		 */
1010771Speter 		case T_FINT:
1011771Speter #			ifdef OBJ
101215931Smckusick 			    (void) put(2, O_CON8, atof(r->const_node.cptr));
1013771Speter #			endif OBJ
1014771Speter #			ifdef PC
101515931Smckusick 			    putCON8( atof( r->const_node.cptr ) );
1016771Speter #			endif PC
1017771Speter 			return (nl+TDOUBLE);
1018771Speter 
1019771Speter 		/*
1020771Speter 		 * Constant strings.  Note that constant characters
1021771Speter 		 * are constant strings of length one; there is
1022771Speter 		 * no constant string of length one.
1023771Speter 		 */
1024771Speter 		case T_STRNG:
102515931Smckusick 			cp = r->const_node.cptr;
1026771Speter 			if (cp[1] == 0) {
1027771Speter #				ifdef OBJ
102815931Smckusick 				    (void) put(2, O_CONC, cp[0]);
1029771Speter #				endif OBJ
1030771Speter #				ifdef PC
103115931Smckusick 				    putleaf( P2ICON , cp[0] , 0 , P2CHAR ,
103215931Smckusick 						(char *) 0 );
1033771Speter #				endif PC
1034771Speter 				return (nl+T1CHAR);
1035771Speter 			}
1036771Speter 			goto cstrng;
1037771Speter 		}
1038771Speter 
1039771Speter 	}
1040771Speter }
1041771Speter 
1042771Speter /*
1043771Speter  * Can a class appear
1044771Speter  * in a comparison ?
1045771Speter  */
1046771Speter nocomp(c)
1047771Speter 	int c;
1048771Speter {
1049771Speter 
1050771Speter 	switch (c) {
1051771Speter 		case TREC:
10521627Speter 			if ( line != reccompline ) {
10531627Speter 			    reccompline = line;
10541627Speter 			    warning();
10551627Speter 			    if ( opt( 's' ) ) {
10561627Speter 				standard();
10571627Speter 			    }
1058771Speter 			    error("record comparison is non-standard");
1059771Speter 			}
1060771Speter 			break;
1061771Speter 		case TFILE:
1062771Speter 		case TARY:
1063771Speter 			error("%ss may not participate in comparisons", clnames[c]);
1064771Speter 			return (1);
1065771Speter 	}
1066771Speter 	return (NIL);
1067771Speter }
1068771Speter 
1069771Speter     /*
1070771Speter      *	this is sort of like gconst, except it works on expression trees
1071771Speter      *	rather than declaration trees, and doesn't give error messages for
1072771Speter      *	non-constant things.
1073771Speter      *	as a side effect this fills in the con structure that gconst uses.
1074771Speter      *	this returns TRUE or FALSE.
1075771Speter      */
107615931Smckusick 
107715931Smckusick bool
1078771Speter constval(r)
107915931Smckusick 	register struct tnode *r;
1080771Speter {
1081771Speter 	register struct nl *np;
108215931Smckusick 	register struct tnode *cn;
1083771Speter 	char *cp;
1084771Speter 	int negd, sgnd;
1085771Speter 	long ci;
1086771Speter 
1087771Speter 	con.ctype = NIL;
1088771Speter 	cn = r;
1089771Speter 	negd = sgnd = 0;
1090771Speter loop:
1091771Speter 	    /*
1092771Speter 	     *	cn[2] is nil if error recovery generated a T_STRNG
1093771Speter 	     */
109415931Smckusick 	if (cn == TR_NIL || cn->expr_node.lhs == TR_NIL)
1095771Speter 		return FALSE;
109615931Smckusick 	switch (cn->tag) {
1097771Speter 		default:
1098771Speter 			return FALSE;
1099771Speter 		case T_MINUS:
1100771Speter 			negd = 1 - negd;
1101771Speter 			/* and fall through */
1102771Speter 		case T_PLUS:
1103771Speter 			sgnd++;
110415931Smckusick 			cn = cn->un_expr.expr;
1105771Speter 			goto loop;
1106771Speter 		case T_NIL:
1107771Speter 			con.cpval = NIL;
1108771Speter 			con.cival = 0;
1109771Speter 			con.crval = con.cival;
1110771Speter 			con.ctype = nl + TNIL;
1111771Speter 			break;
1112771Speter 		case T_VAR:
111315931Smckusick 			np = lookup(cn->var_node.cptr);
111415931Smckusick 			if (np == NLNIL || np->class != CONST) {
1115771Speter 				return FALSE;
1116771Speter 			}
111715931Smckusick 			if ( cn->var_node.qual != TR_NIL ) {
1118771Speter 				return FALSE;
1119771Speter 			}
1120771Speter 			con.ctype = np->type;
1121771Speter 			switch (classify(np->type)) {
1122771Speter 				case TINT:
1123771Speter 					con.crval = np->range[0];
1124771Speter 					break;
1125771Speter 				case TDOUBLE:
1126771Speter 					con.crval = np->real;
1127771Speter 					break;
1128771Speter 				case TBOOL:
1129771Speter 				case TCHAR:
1130771Speter 				case TSCAL:
1131771Speter 					con.cival = np->value[0];
1132771Speter 					con.crval = con.cival;
1133771Speter 					break;
1134771Speter 				case TSTR:
113515931Smckusick 					con.cpval = (char *) np->ptr[0];
1136771Speter 					break;
1137771Speter 				default:
1138771Speter 					con.ctype = NIL;
1139771Speter 					return FALSE;
1140771Speter 			}
1141771Speter 			break;
1142771Speter 		case T_BINT:
114315931Smckusick 			con.crval = a8tol(cn->const_node.cptr);
1144771Speter 			goto restcon;
1145771Speter 		case T_INT:
114615931Smckusick 			con.crval = atof(cn->const_node.cptr);
1147771Speter 			if (con.crval > MAXINT || con.crval < MININT) {
1148771Speter 				derror("Constant too large for this implementation");
1149771Speter 				con.crval = 0;
1150771Speter 			}
1151771Speter restcon:
1152771Speter 			ci = con.crval;
1153771Speter #ifndef PI0
1154771Speter 			if (bytes(ci, ci) <= 2)
1155771Speter 				con.ctype = nl+T2INT;
1156771Speter 			else
1157771Speter #endif
1158771Speter 				con.ctype = nl+T4INT;
1159771Speter 			break;
1160771Speter 		case T_FINT:
1161771Speter 			con.ctype = nl+TDOUBLE;
116215931Smckusick 			con.crval = atof(cn->const_node.cptr);
1163771Speter 			break;
1164771Speter 		case T_STRNG:
116515931Smckusick 			cp = cn->const_node.cptr;
1166771Speter 			if (cp[1] == 0) {
1167771Speter 				con.ctype = nl+T1CHAR;
1168771Speter 				con.cival = cp[0];
1169771Speter 				con.crval = con.cival;
1170771Speter 				break;
1171771Speter 			}
1172771Speter 			con.ctype = nl+TSTR;
1173771Speter 			con.cpval = cp;
1174771Speter 			break;
1175771Speter 	}
1176771Speter 	if (sgnd) {
1177771Speter 		if (isnta(con.ctype, "id")) {
1178771Speter 			derror("%s constants cannot be signed", nameof(con.ctype));
1179771Speter 			return FALSE;
1180771Speter 		} else if (negd)
1181771Speter 			con.crval = -con.crval;
1182771Speter 	}
1183771Speter 	return TRUE;
1184771Speter }
1185