xref: /csrg-svn/usr.bin/pascal/src/rval.c (revision 62215)
148116Sbostic /*-
2*62215Sbostic  * Copyright (c) 1980, 1993
3*62215Sbostic  *	The Regents of the University of California.  All rights reserved.
448116Sbostic  *
548116Sbostic  * %sccs.include.redist.c%
622188Sdist  */
7771Speter 
815945Speter #ifndef lint
9*62215Sbostic static char sccsid[] = "@(#)rval.c	8.1 (Berkeley) 06/06/93";
1048116Sbostic #endif /* not lint */
11771Speter 
12771Speter #include "whoami.h"
13771Speter #include "0.h"
14771Speter #include "tree.h"
15771Speter #include "opcode.h"
16771Speter #include "objfmt.h"
17771Speter #ifdef PC
18771Speter #   include	"pc.h"
1918468Sralph #   include <pcc.h>
20771Speter #endif PC
2111328Speter #include "tmps.h"
2215931Smckusick #include "tree_ty.h"
23771Speter 
24771Speter extern	char *opnames[];
25771Speter 
261627Speter     /* line number of the last record comparison warning */
271627Speter short reccompline = 0;
283397Speter     /* line number of the last non-standard set comparison */
293397Speter short nssetline = 0;
301627Speter 
31771Speter #ifdef PC
32771Speter     char	*relts[] =  {
33771Speter 				"_RELEQ" , "_RELNE" ,
34771Speter 				"_RELTLT" , "_RELTGT" ,
35771Speter 				"_RELTLE" , "_RELTGE"
36771Speter 			    };
37771Speter     char	*relss[] =  {
38771Speter 				"_RELEQ" , "_RELNE" ,
39771Speter 				"_RELSLT" , "_RELSGT" ,
40771Speter 				"_RELSLE" , "_RELSGE"
41771Speter 			    };
42771Speter     long	relops[] =  {
4318468Sralph 				PCC_EQ , PCC_NE ,
4418468Sralph 				PCC_LT , PCC_GT ,
4518468Sralph 				PCC_LE , PCC_GE
46771Speter 			    };
4718468Sralph     long	mathop[] =  {	PCC_MUL , PCC_PLUS , PCC_MINUS };
48771Speter     char	*setop[] =  {	"_MULT" , "_ADDT" , "_SUBT" };
49771Speter #endif PC
50771Speter /*
51771Speter  * Rvalue - an expression.
52771Speter  *
53771Speter  * Contype is the type that the caller would prefer, nand is important
5416273Speter  * if constant strings are involved, because of string padding.
55771Speter  * required is a flag whether an lvalue or an rvalue is required.
56771Speter  * only VARs and structured things can have gt their lvalue this way.
57771Speter  */
5815931Smckusick /*ARGSUSED*/
59771Speter struct nl *
rvalue(r,contype,required)60771Speter rvalue(r, contype , required )
6115931Smckusick 	struct tnode *r;
62771Speter 	struct nl *contype;
63771Speter 	int	required;
64771Speter {
65771Speter 	register struct nl *p, *p1;
66771Speter 	register struct nl *q;
6715931Smckusick 	int c, c1, w;
6815931Smckusick #ifdef OBJ
6915931Smckusick 	int g;
7015931Smckusick #endif
7115931Smckusick 	struct tnode *rt;
72771Speter 	char *cp, *cp1, *opname;
73771Speter 	long l;
7415931Smckusick 	union
7515931Smckusick 	{
7615931Smckusick 	    long plong[2];
7715931Smckusick 	    double pdouble;
7815931Smckusick 	}f;
79771Speter 	extern int	flagwas;
80771Speter 	struct csetstr	csetd;
81771Speter #	ifdef PC
82771Speter 	    struct nl	*rettype;
83771Speter 	    long	ctype;
843834Speter 	    struct nl	*tempnlp;
85771Speter #	endif PC
86771Speter 
8715931Smckusick 	if (r == TR_NIL)
8815931Smckusick 		return (NLNIL);
89771Speter 	if (nowexp(r))
9015931Smckusick 		return (NLNIL);
91771Speter 	/*
92771Speter 	 * Pick up the name of the operation
93771Speter 	 * for future error messages.
94771Speter 	 */
9515931Smckusick 	if (r->tag <= T_IN)
9615931Smckusick 		opname = opnames[r->tag];
97771Speter 
98771Speter 	/*
99771Speter 	 * The root of the tree tells us what sort of expression we have.
100771Speter 	 */
10115931Smckusick 	switch (r->tag) {
102771Speter 
103771Speter 	/*
104771Speter 	 * The constant nil
105771Speter 	 */
106771Speter 	case T_NIL:
107771Speter #		ifdef OBJ
10815931Smckusick 		    (void) put(2, O_CON2, 0);
109771Speter #		endif OBJ
110771Speter #		ifdef PC
11118468Sralph 		    putleaf( PCC_ICON , 0 , 0 , PCCTM_PTR|PCCT_UNDEF , (char *) 0 );
112771Speter #		endif PC
113771Speter 		return (nl+TNIL);
114771Speter 
115771Speter 	/*
116771Speter 	 * Function call with arguments.
117771Speter 	 */
118771Speter 	case T_FCALL:
119771Speter #	    ifdef OBJ
120771Speter 		return (funccod(r));
121771Speter #	    endif OBJ
122771Speter #	    ifdef PC
123771Speter 		return (pcfunccod( r ));
124771Speter #	    endif PC
125771Speter 
126771Speter 	case T_VAR:
12715931Smckusick 		p = lookup(r->var_node.cptr);
12815931Smckusick 		if (p == NLNIL || p->class == BADUSE)
12915931Smckusick 			return (NLNIL);
130771Speter 		switch (p->class) {
131771Speter 		    case VAR:
132771Speter 			    /*
133771Speter 			     * If a variable is
134771Speter 			     * qualified then get
135771Speter 			     * the rvalue by a
136771Speter 			     * lvalue and an ind.
137771Speter 			     */
13815931Smckusick 			    if (r->var_node.qual != TR_NIL)
139771Speter 				    goto ind;
140771Speter 			    q = p->type;
141771Speter 			    if (q == NIL)
14215931Smckusick 				    return (NLNIL);
143771Speter #			    ifdef OBJ
144771Speter 				w = width(q);
145771Speter 				switch (w) {
146771Speter 				    case 8:
14715931Smckusick 					(void) put(2, O_RV8 | bn << 8+INDX,
1483078Smckusic 						(int)p->value[0]);
149771Speter 					break;
150771Speter 				    case 4:
15115931Smckusick 					(void) put(2, O_RV4 | bn << 8+INDX,
1523078Smckusic 						(int)p->value[0]);
153771Speter 					break;
154771Speter 				    case 2:
15515931Smckusick 					(void) put(2, O_RV2 | bn << 8+INDX,
1563078Smckusic 						(int)p->value[0]);
157771Speter 					break;
158771Speter 				    case 1:
15915931Smckusick 					(void) put(2, O_RV1 | bn << 8+INDX,
1603078Smckusic 						(int)p->value[0]);
161771Speter 					break;
162771Speter 				    default:
16315931Smckusick 					(void) put(3, O_RV | bn << 8+INDX,
1643078Smckusic 						(int)p->value[0], w);
165771Speter 				}
166771Speter #			   endif OBJ
167771Speter #			   ifdef PC
168771Speter 				if ( required == RREQ ) {
1693834Speter 				    putRV( p -> symbol , bn , p -> value[0] ,
1703834Speter 					    p -> extra_flags , p2type( q ) );
171771Speter 				} else {
1723834Speter 				    putLV( p -> symbol , bn , p -> value[0] ,
1733834Speter 					    p -> extra_flags , p2type( q ) );
174771Speter 				}
175771Speter #			   endif PC
176771Speter 			   return (q);
177771Speter 
178771Speter 		    case WITHPTR:
179771Speter 		    case REF:
180771Speter 			    /*
181771Speter 			     * A lvalue for these
182771Speter 			     * is actually what one
183771Speter 			     * might consider a rvalue.
184771Speter 			     */
185771Speter ind:
186771Speter 			    q = lvalue(r, NOFLAGS , LREQ );
187771Speter 			    if (q == NIL)
18815931Smckusick 				    return (NLNIL);
189771Speter #			    ifdef OBJ
190771Speter 				w = width(q);
191771Speter 				switch (w) {
192771Speter 				    case 8:
19315931Smckusick 					    (void) put(1, O_IND8);
194771Speter 					    break;
195771Speter 				    case 4:
19615931Smckusick 					    (void) put(1, O_IND4);
197771Speter 					    break;
198771Speter 				    case 2:
19915931Smckusick 					    (void) put(1, O_IND2);
200771Speter 					    break;
201771Speter 				    case 1:
20215931Smckusick 					    (void) put(1, O_IND1);
203771Speter 					    break;
204771Speter 				    default:
20515931Smckusick 					    (void) put(2, O_IND, w);
206771Speter 				}
207771Speter #			    endif OBJ
208771Speter #			    ifdef PC
209771Speter 				if ( required == RREQ ) {
21018468Sralph 				    putop( PCCOM_UNARY PCC_MUL , p2type( q ) );
211771Speter 				}
212771Speter #			    endif PC
213771Speter 			    return (q);
214771Speter 
215771Speter 		    case CONST:
21615931Smckusick 			    if (r->var_node.qual != TR_NIL) {
21715931Smckusick 				error("%s is a constant and cannot be qualified", r->var_node.cptr);
21815931Smckusick 				return (NLNIL);
219771Speter 			    }
220771Speter 			    q = p->type;
22115931Smckusick 			    if (q == NLNIL)
22215931Smckusick 				    return (NLNIL);
223771Speter 			    if (q == nl+TSTR) {
224771Speter 				    /*
225771Speter 				     * Find the size of the string
226771Speter 				     * constant if needed.
227771Speter 				     */
22815931Smckusick 				    cp = (char *) p->ptr[0];
229771Speter cstrng:
230771Speter 				    cp1 = cp;
231771Speter 				    for (c = 0; *cp++; c++)
232771Speter 					    continue;
2333078Smckusic 				    w = c;
234771Speter 				    if (contype != NIL && !opt('s')) {
235771Speter 					    if (width(contype) < c && classify(contype) == TSTR) {
236771Speter 						    error("Constant string too long");
23715931Smckusick 						    return (NLNIL);
238771Speter 					    }
2393078Smckusic 					    w = width(contype);
240771Speter 				    }
241771Speter #				    ifdef OBJ
24215931Smckusick 					(void) put(2, O_CONG, w);
2433078Smckusic 					putstr(cp1, w - c);
244771Speter #				    endif OBJ
245771Speter #				    ifdef PC
2463155Smckusic 					putCONG( cp1 , w , required );
247771Speter #				    endif PC
248771Speter 				    /*
249771Speter 				     * Define the string temporarily
250771Speter 				     * so later people can know its
251771Speter 				     * width.
252771Speter 				     * cleaned out by stat.
253771Speter 				     */
25415931Smckusick 				    q = defnl((char *) 0, STR, NLNIL, w);
255771Speter 				    q->type = q;
256771Speter 				    return (q);
257771Speter 			    }
258771Speter 			    if (q == nl+T1CHAR) {
259771Speter #				    ifdef OBJ
26015931Smckusick 					(void) put(2, O_CONC, (int)p->value[0]);
261771Speter #				    endif OBJ
262771Speter #				    ifdef PC
26318468Sralph 					putleaf( PCC_ICON , p -> value[0] , 0
26418468Sralph 						, PCCT_CHAR , (char *) 0 );
265771Speter #				    endif PC
266771Speter 				    return (q);
267771Speter 			    }
268771Speter 			    /*
269771Speter 			     * Every other kind of constant here
270771Speter 			     */
271771Speter 			    switch (width(q)) {
272771Speter 			    case 8:
273771Speter #ifndef DEBUG
274771Speter #				    ifdef OBJ
27515931Smckusick 					(void) put(2, O_CON8, p->real);
276771Speter #				    endif OBJ
277771Speter #				    ifdef PC
278771Speter 					putCON8( p -> real );
279771Speter #				    endif PC
280771Speter #else
281771Speter 				    if (hp21mx) {
28215931Smckusick 					    f.pdouble = p->real;
28315931Smckusick 					    conv((int *) (&f.pdouble));
28415931Smckusick 					    l = f.plong[1];
28515931Smckusick 					    (void) put(2, O_CON4, l);
286771Speter 				    } else
287771Speter #					    ifdef OBJ
28815931Smckusick 						(void) put(2, O_CON8, p->real);
289771Speter #					    endif OBJ
290771Speter #					    ifdef PC
291771Speter 						putCON8( p -> real );
292771Speter #					    endif PC
293771Speter #endif
294771Speter 				    break;
295771Speter 			    case 4:
296771Speter #				    ifdef OBJ
29715931Smckusick 					(void) put(2, O_CON4, p->range[0]);
298771Speter #				    endif OBJ
299771Speter #				    ifdef PC
30018468Sralph 					putleaf( PCC_ICON , (int) p->range[0] , 0
30118468Sralph 						, PCCT_INT , (char *) 0 );
302771Speter #				    endif PC
303771Speter 				    break;
304771Speter 			    case 2:
305771Speter #				    ifdef OBJ
30615931Smckusick 					(void) put(2, O_CON2, (short)p->range[0]);
307771Speter #				    endif OBJ
308771Speter #				    ifdef PC
30918468Sralph 					putleaf( PCC_ICON , (short) p -> range[0]
31018468Sralph 						, 0 , PCCT_SHORT , (char *) 0 );
311771Speter #				    endif PC
312771Speter 				    break;
313771Speter 			    case 1:
314771Speter #				    ifdef OBJ
31515931Smckusick 					(void) put(2, O_CON1, p->value[0]);
316771Speter #				    endif OBJ
317771Speter #				    ifdef PC
31818468Sralph 					putleaf( PCC_ICON , p -> value[0] , 0
31918468Sralph 						, PCCT_CHAR , (char *) 0 );
320771Speter #				    endif PC
321771Speter 				    break;
322771Speter 			    default:
323771Speter 				    panic("rval");
324771Speter 			    }
325771Speter 			    return (q);
326771Speter 
327771Speter 		    case FUNC:
3281200Speter 		    case FFUNC:
329771Speter 			    /*
330771Speter 			     * Function call with no arguments.
331771Speter 			     */
33215931Smckusick 			    if (r->var_node.qual != TR_NIL) {
333771Speter 				    error("Can't qualify a function result value");
33415931Smckusick 				    return (NLNIL);
335771Speter 			    }
336771Speter #			    ifdef OBJ
33715931Smckusick 				return (funccod(r));
338771Speter #			    endif OBJ
339771Speter #			    ifdef PC
340771Speter 				return (pcfunccod( r ));
341771Speter #			    endif PC
342771Speter 
343771Speter 		    case TYPE:
344771Speter 			    error("Type names (e.g. %s) allowed only in declarations", p->symbol);
34515931Smckusick 			    return (NLNIL);
346771Speter 
347771Speter 		    case PROC:
3481200Speter 		    case FPROC:
349771Speter 			    error("Procedure %s found where expression required", p->symbol);
35015931Smckusick 			    return (NLNIL);
351771Speter 		    default:
352771Speter 			    panic("rvid");
353771Speter 		}
354771Speter 	/*
355771Speter 	 * Constant sets
356771Speter 	 */
357771Speter 	case T_CSET:
358771Speter #		ifdef OBJ
359771Speter 		    if ( precset( r , contype , &csetd ) ) {
360771Speter 			if ( csetd.csettype == NIL ) {
36115931Smckusick 			    return (NLNIL);
362771Speter 			}
363771Speter 			postcset( r , &csetd );
364771Speter 		    } else {
36515931Smckusick 			(void) put( 2, O_PUSH, -lwidth(csetd.csettype));
366771Speter 			postcset( r , &csetd );
367771Speter 			setran( ( csetd.csettype ) -> type );
36815931Smckusick 			(void) put( 2, O_CON24, set.uprbp);
36915931Smckusick 			(void) put( 2, O_CON24, set.lwrb);
37015931Smckusick 			(void) put( 2, O_CTTOT,
3713078Smckusic 				(int)(4 + csetd.singcnt + 2 * csetd.paircnt));
372771Speter 		    }
373771Speter 		    return csetd.csettype;
374771Speter #		endif OBJ
375771Speter #		ifdef PC
376771Speter 		    if ( precset( r , contype , &csetd ) ) {
377771Speter 			if ( csetd.csettype == NIL ) {
37815931Smckusick 			    return (NLNIL);
379771Speter 			}
380771Speter 			postcset( r , &csetd );
381771Speter 		    } else {
38218468Sralph 			putleaf( PCC_ICON , 0 , 0
38318468Sralph 				, PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR )
384771Speter 				, "_CTTOT" );
385771Speter 			/*
386771Speter 			 *	allocate a temporary and use it
387771Speter 			 */
3883834Speter 			tempnlp = tmpalloc(lwidth(csetd.csettype),
3893227Smckusic 				csetd.csettype, NOREG);
39015931Smckusick 			putLV( (char *) 0 , cbn , tempnlp -> value[ NL_OFFS ] ,
39118468Sralph 				tempnlp -> extra_flags , PCCTM_PTR|PCCT_STRTY );
392771Speter 			setran( ( csetd.csettype ) -> type );
39318468Sralph 			putleaf( PCC_ICON , set.lwrb , 0 , PCCT_INT , (char *) 0 );
39418468Sralph 			putop( PCC_CM , PCCT_INT );
39518468Sralph 			putleaf( PCC_ICON , set.uprbp , 0 , PCCT_INT , (char *) 0 );
39618468Sralph 			putop( PCC_CM , PCCT_INT );
397771Speter 			postcset( r , &csetd );
39818468Sralph 			putop( PCC_CALL , PCCT_INT );
399771Speter 		    }
400771Speter 		    return csetd.csettype;
401771Speter #		endif PC
402771Speter 
403771Speter 	/*
404771Speter 	 * Unary plus and minus
405771Speter 	 */
406771Speter 	case T_PLUS:
407771Speter 	case T_MINUS:
40815931Smckusick 		q = rvalue(r->un_expr.expr, NLNIL , RREQ );
40915931Smckusick 		if (q == NLNIL)
41015931Smckusick 			return (NLNIL);
411771Speter 		if (isnta(q, "id")) {
412771Speter 			error("Operand of %s must be integer or real, not %s", opname, nameof(q));
41315931Smckusick 			return (NLNIL);
414771Speter 		}
41515931Smckusick 		if (r->tag == T_MINUS) {
416771Speter #		    ifdef OBJ
41715931Smckusick 			(void) put(1, O_NEG2 + (width(q) >> 2));
41810670Speter 			return (isa(q, "d") ? q : nl+T4INT);
419771Speter #		    endif OBJ
420771Speter #		    ifdef PC
42110670Speter 			if (isa(q, "i")) {
42218468Sralph 			    sconv(p2type(q), PCCT_INT);
42318468Sralph 			    putop( PCCOM_UNARY PCC_MINUS, PCCT_INT);
42410670Speter 			    return nl+T4INT;
42510670Speter 			}
42618468Sralph 			putop( PCCOM_UNARY PCC_MINUS, PCCT_DOUBLE);
42710670Speter 			return nl+TDOUBLE;
428771Speter #		    endif PC
429771Speter 		}
430771Speter 		return (q);
431771Speter 
432771Speter 	case T_NOT:
43315931Smckusick 		q = rvalue(r->un_expr.expr, NLNIL , RREQ );
43415931Smckusick 		if (q == NLNIL)
43515931Smckusick 			return (NLNIL);
436771Speter 		if (isnta(q, "b")) {
437771Speter 			error("not must operate on a Boolean, not %s", nameof(q));
43815931Smckusick 			return (NLNIL);
439771Speter 		}
440771Speter #		ifdef OBJ
44115931Smckusick 		    (void) put(1, O_NOT);
442771Speter #		endif OBJ
443771Speter #		ifdef PC
44418468Sralph 		    sconv(p2type(q), PCCT_INT);
44518468Sralph 		    putop( PCC_NOT , PCCT_INT);
44618468Sralph 		    sconv(PCCT_INT, p2type(q));
447771Speter #		endif PC
448771Speter 		return (nl+T1BOOL);
449771Speter 
450771Speter 	case T_AND:
451771Speter 	case T_OR:
45215931Smckusick 		p = rvalue(r->expr_node.lhs, NLNIL , RREQ );
45310364Smckusick #		ifdef PC
45418468Sralph 		    sconv(p2type(p),PCCT_INT);
45510364Smckusick #		endif PC
45615931Smckusick 		p1 = rvalue(r->expr_node.rhs, NLNIL , RREQ );
45710364Smckusick #		ifdef PC
45818468Sralph 		    sconv(p2type(p1),PCCT_INT);
45910364Smckusick #		endif PC
46015931Smckusick 		if (p == NLNIL || p1 == NLNIL)
46115931Smckusick 			return (NLNIL);
462771Speter 		if (isnta(p, "b")) {
463771Speter 			error("Left operand of %s must be Boolean, not %s", opname, nameof(p));
46415931Smckusick 			return (NLNIL);
465771Speter 		}
466771Speter 		if (isnta(p1, "b")) {
467771Speter 			error("Right operand of %s must be Boolean, not %s", opname, nameof(p1));
46815931Smckusick 			return (NLNIL);
469771Speter 		}
470771Speter #		ifdef OBJ
47115931Smckusick 		    (void) put(1, r->tag == T_AND ? O_AND : O_OR);
472771Speter #		endif OBJ
473771Speter #		ifdef PC
474771Speter 			/*
475771Speter 			 * note the use of & and | rather than && and ||
476771Speter 			 * to force evaluation of all the expressions.
477771Speter 			 */
47818468Sralph 		    putop( r->tag == T_AND ? PCC_AND : PCC_OR , PCCT_INT );
47918468Sralph 		    sconv(PCCT_INT, p2type(p));
480771Speter #		endif PC
481771Speter 		return (nl+T1BOOL);
482771Speter 
483771Speter 	case T_DIVD:
484771Speter #		ifdef OBJ
48515931Smckusick 		    p = rvalue(r->expr_node.lhs, NLNIL , RREQ );
48615931Smckusick 		    p1 = rvalue(r->expr_node.rhs, NLNIL , RREQ );
487771Speter #		endif OBJ
488771Speter #		ifdef PC
489771Speter 			/*
490771Speter 			 *	force these to be doubles for the divide
491771Speter 			 */
49215931Smckusick 		    p = rvalue( r->expr_node.lhs , NLNIL , RREQ );
49318468Sralph 		    sconv(p2type(p), PCCT_DOUBLE);
49415931Smckusick 		    p1 = rvalue( r->expr_node.rhs , NLNIL , RREQ );
49518468Sralph 		    sconv(p2type(p1), PCCT_DOUBLE);
496771Speter #		endif PC
49715931Smckusick 		if (p == NLNIL || p1 == NLNIL)
49815931Smckusick 			return (NLNIL);
499771Speter 		if (isnta(p, "id")) {
500771Speter 			error("Left operand of / must be integer or real, not %s", nameof(p));
50115931Smckusick 			return (NLNIL);
502771Speter 		}
503771Speter 		if (isnta(p1, "id")) {
504771Speter 			error("Right operand of / must be integer or real, not %s", nameof(p1));
50515931Smckusick 			return (NLNIL);
506771Speter 		}
507771Speter #		ifdef OBJ
50815931Smckusick 		    return gen(NIL, r->tag, width(p), width(p1));
509771Speter #		endif OBJ
510771Speter #		ifdef PC
51118468Sralph 		    putop( PCC_DIV , PCCT_DOUBLE );
512771Speter 		    return nl + TDOUBLE;
513771Speter #		endif PC
514771Speter 
515771Speter 	case T_MULT:
516771Speter 	case T_ADD:
517771Speter 	case T_SUB:
518771Speter #		ifdef OBJ
519771Speter 		    /*
52016273Speter 		     * get the type of the right hand side.
52116273Speter 		     * if it turns out to be a set,
52216273Speter 		     * use that type when getting
52316273Speter 		     * the type of the left hand side.
52416273Speter 		     * and then use the type of the left hand side
52516273Speter 		     * when generating code.
52616273Speter 		     * this will correctly decide the type of any
52716273Speter 		     * empty sets in the tree, since if the empty set
52816273Speter 		     * is on the left hand side it will inherit
52916273Speter 		     * the type of the right hand side,
53016273Speter 		     * and if it's on the right hand side, its type (intset)
53116273Speter 		     * will be overridden by the type of the left hand side.
53216273Speter 		     * this is an awful lot of tree traversing,
53316273Speter 		     * but it works.
534771Speter 		     */
53516273Speter 		    codeoff();
53616273Speter 		    p1 = rvalue( r->expr_node.rhs , NLNIL , RREQ );
53716273Speter 		    codeon();
53816273Speter 		    if ( p1 == NLNIL ) {
53915931Smckusick 			return NLNIL;
5401555Speter 		    }
54116273Speter 		    if (isa(p1, "t")) {
54216273Speter 			codeoff();
54316273Speter 			contype = rvalue(r->expr_node.lhs, p1, RREQ);
54416273Speter 			codeon();
54516273Speter 			if (contype == NLNIL) {
54616273Speter 			    return NLNIL;
54716273Speter 			}
54816273Speter 		    }
54915931Smckusick 		    p = rvalue( r->expr_node.lhs , contype , RREQ );
55015931Smckusick 		    p1 = rvalue( r->expr_node.rhs , p , RREQ );
55115937Smckusick 		    if ( p == NLNIL || p1 == NLNIL )
55215931Smckusick 			    return NLNIL;
553771Speter 		    if (isa(p, "id") && isa(p1, "id"))
55415931Smckusick 			return (gen(NIL, r->tag, width(p), width(p1)));
555771Speter 		    if (isa(p, "t") && isa(p1, "t")) {
556771Speter 			    if (p != p1) {
557771Speter 				    error("Set types of operands of %s must be identical", opname);
55815931Smckusick 				    return (NLNIL);
559771Speter 			    }
56015931Smckusick 			    (void) gen(TSET, r->tag, width(p), 0);
561771Speter 			    return (p);
562771Speter 		    }
563771Speter #		endif OBJ
564771Speter #		ifdef PC
565771Speter 			/*
566771Speter 			 * the second pass can't do
567771Speter 			 *	long op double  or  double op long
56816273Speter 			 * so we have to know the type of both operands.
56916273Speter 			 * also, see the note for obj above on determining
57016273Speter 			 * the type of empty sets.
571771Speter 			 */
572771Speter 		    codeoff();
57316273Speter 		    p1 = rvalue(r->expr_node.rhs, NLNIL, RREQ);
574771Speter 		    codeon();
575771Speter 		    if ( isa( p1 , "id" ) ) {
57615931Smckusick 			p = rvalue( r->expr_node.lhs , contype , RREQ );
57715937Smckusick 			if ( ( p == NLNIL ) || ( p1 == NLNIL ) ) {
57815931Smckusick 			    return NLNIL;
579771Speter 			}
58015931Smckusick 			tuac(p, p1, &rettype, (int *) (&ctype));
58115931Smckusick 			p1 = rvalue( r->expr_node.rhs , contype , RREQ );
58215931Smckusick 			tuac(p1, p, &rettype, (int *) (&ctype));
583771Speter 			if ( isa( p , "id" ) ) {
58415931Smckusick 			    putop( (int) mathop[r->tag - T_MULT], (int) ctype);
585771Speter 			    return rettype;
586771Speter 			}
587771Speter 		    }
588771Speter 		    if ( isa( p1 , "t" ) ) {
58918468Sralph 			putleaf( PCC_ICON , 0 , 0
59018468Sralph 			    , PCCM_ADDTYPE( PCCM_ADDTYPE( PCCTM_PTR | PCCT_STRTY , PCCTM_FTN )
59118468Sralph 					, PCCTM_PTR )
59215931Smckusick 			    , setop[ r->tag - T_MULT ] );
59316273Speter 			codeoff();
59416273Speter 			contype = rvalue( r->expr_node.lhs, p1 , LREQ );
59516273Speter 			codeon();
59615937Smckusick 			if ( contype == NLNIL ) {
59715931Smckusick 			    return NLNIL;
5981555Speter 			}
5991555Speter 			    /*
6001555Speter 			     *	allocate a temporary and use it
6011555Speter 			     */
6023834Speter 			tempnlp = tmpalloc(lwidth(contype), contype, NOREG);
60315931Smckusick 			putLV((char *) 0 , cbn , tempnlp -> value[ NL_OFFS ] ,
60418468Sralph 				tempnlp -> extra_flags , PCCTM_PTR|PCCT_STRTY );
60515931Smckusick 			p = rvalue( r->expr_node.lhs , contype , LREQ );
606771Speter 			if ( isa( p , "t" ) ) {
60718468Sralph 			    putop( PCC_CM , PCCT_INT );
60815937Smckusick 			    if ( p == NLNIL || p1 == NLNIL ) {
60915931Smckusick 				return NLNIL;
610771Speter 			    }
61115931Smckusick 			    p1 = rvalue( r->expr_node.rhs , p , LREQ );
612771Speter 			    if ( p != p1 ) {
613771Speter 				error("Set types of operands of %s must be identical", opname);
61415931Smckusick 				return NLNIL;
615771Speter 			    }
61618468Sralph 			    putop( PCC_CM , PCCT_INT );
61718468Sralph 			    putleaf( PCC_ICON , (int) (lwidth(p1)) / sizeof( long ) , 0
61818468Sralph 				    , PCCT_INT , (char *) 0 );
61918468Sralph 			    putop( PCC_CM , PCCT_INT );
62018468Sralph 			    putop( PCC_CALL , PCCTM_PTR | PCCT_STRTY );
621771Speter 			    return p;
622771Speter 			}
623771Speter 		    }
624771Speter 		    if ( isnta( p1 , "idt" ) ) {
625771Speter 			    /*
626771Speter 			     *	find type of left operand for error message.
627771Speter 			     */
62815931Smckusick 			p = rvalue( r->expr_node.lhs , contype , RREQ );
629771Speter 		    }
630771Speter 			/*
631771Speter 			 *	don't give spurious error messages.
632771Speter 			 */
63315937Smckusick 		    if ( p == NLNIL || p1 == NLNIL ) {
63415931Smckusick 			return NLNIL;
635771Speter 		    }
636771Speter #		endif PC
637771Speter 		if (isnta(p, "idt")) {
638771Speter 			error("Left operand of %s must be integer, real or set, not %s", opname, nameof(p));
63915931Smckusick 			return (NLNIL);
640771Speter 		}
641771Speter 		if (isnta(p1, "idt")) {
642771Speter 			error("Right operand of %s must be integer, real or set, not %s", opname, nameof(p1));
64315931Smckusick 			return (NLNIL);
644771Speter 		}
645771Speter 		error("Cannot mix sets with integers and reals as operands of %s", opname);
64615931Smckusick 		return (NLNIL);
647771Speter 
648771Speter 	case T_MOD:
649771Speter 	case T_DIV:
65015931Smckusick 		p = rvalue(r->expr_node.lhs, NLNIL , RREQ );
65110364Smckusick #		ifdef PC
65218468Sralph 		    sconv(p2type(p), PCCT_INT);
65330839Smckusick #		ifdef tahoe
65430839Smckusick 		    /* prepare for ediv workaround, see below. */
65530839Smckusick 		    if (r->tag == T_MOD) {
65630839Smckusick 			(void) rvalue(r->expr_node.lhs, NLNIL, RREQ);
65730839Smckusick 			sconv(p2type(p), PCCT_INT);
65830839Smckusick 		    }
65930839Smckusick #		endif tahoe
66010364Smckusick #		endif PC
66115931Smckusick 		p1 = rvalue(r->expr_node.rhs, NLNIL , RREQ );
66210364Smckusick #		ifdef PC
66318468Sralph 		    sconv(p2type(p1), PCCT_INT);
66410364Smckusick #		endif PC
66515937Smckusick 		if (p == NLNIL || p1 == NLNIL)
66615931Smckusick 			return (NLNIL);
667771Speter 		if (isnta(p, "i")) {
668771Speter 			error("Left operand of %s must be integer, not %s", opname, nameof(p));
66915931Smckusick 			return (NLNIL);
670771Speter 		}
671771Speter 		if (isnta(p1, "i")) {
672771Speter 			error("Right operand of %s must be integer, not %s", opname, nameof(p1));
67315931Smckusick 			return (NLNIL);
674771Speter 		}
675771Speter #		ifdef OBJ
67615931Smckusick 		    return (gen(NIL, r->tag, width(p), width(p1)));
677771Speter #		endif OBJ
678771Speter #		ifdef PC
67930839Smckusick #		ifndef tahoe
68018468Sralph 		    putop( r->tag == T_DIV ? PCC_DIV : PCC_MOD , PCCT_INT );
681771Speter 		    return ( nl + T4INT );
68230839Smckusick #		else tahoe
68330839Smckusick 		    putop( PCC_DIV , PCCT_INT );
68430839Smckusick 		    if (r->tag == T_MOD) {
68530839Smckusick 		    /*
68630839Smckusick 		     * avoid f1 bug: PCC_MOD would generate an 'ediv',
68730839Smckusick 		     * which would reuire too many registers to evaluate
68830839Smckusick 		     * things like
68930839Smckusick 		     * var i:boolean;j:integer; i := (j+1) = (j mod 2);
69030839Smckusick 		     * so, instead of
69130839Smckusick 		     *                PCC_MOD
69230839Smckusick 		     *		        / \
69330839Smckusick 		     *	               p   p1
69430839Smckusick 		     * we put
69530839Smckusick 		     *                  PCC_MINUS
69630839Smckusick 		     *                    /   \
69730839Smckusick 		     *			 p   PCC_MUL
69830839Smckusick 		     *			      /   \
69930839Smckusick 		     *			  PCC_DIV  p1
70030839Smckusick 		     *                      / \
70130839Smckusick 		     *                     p  p1
70230839Smckusick 		     *
70330839Smckusick 		     * we already have put p, p, p1, PCC_DIV. and now...
70430839Smckusick 		     */
70530839Smckusick 			    rvalue(r->expr_node.rhs, NLNIL , RREQ );
70630839Smckusick 			    sconv(p2type(p1), PCCT_INT);
70730839Smckusick 			    putop( PCC_MUL, PCCT_INT );
70830839Smckusick 			    putop( PCC_MINUS, PCCT_INT );
70930839Smckusick 		    }
71030839Smckusick 		    return ( nl + T4INT );
71130839Smckusick #		endif tahoe
712771Speter #		endif PC
713771Speter 
714771Speter 	case T_EQ:
715771Speter 	case T_NE:
716771Speter 	case T_LT:
717771Speter 	case T_GT:
718771Speter 	case T_LE:
719771Speter 	case T_GE:
720771Speter 		/*
721771Speter 		 * Since there can be no, a priori, knowledge
722771Speter 		 * of the context type should a constant string
723771Speter 		 * or set arise, we must poke around to find such
724771Speter 		 * a type if possible.  Since constant strings can
725771Speter 		 * always masquerade as identifiers, this is always
726771Speter 		 * necessary.
72716273Speter 		 * see the note in the obj section of case T_MULT above
72816273Speter 		 * for the determination of the base type of empty sets.
729771Speter 		 */
730771Speter 		codeoff();
73115931Smckusick 		p1 = rvalue(r->expr_node.rhs, NLNIL , RREQ );
732771Speter 		codeon();
73315931Smckusick 		if (p1 == NLNIL)
73415931Smckusick 			return (NLNIL);
735771Speter 		contype = p1;
736771Speter #		ifdef OBJ
7371555Speter 		    if (p1->class == STR) {
738771Speter 			    /*
739771Speter 			     * For constant strings we want
740771Speter 			     * the longest type so as to be
741771Speter 			     * able to do padding (more importantly
742771Speter 			     * avoiding truncation). For clarity,
743771Speter 			     * we get this length here.
744771Speter 			     */
745771Speter 			    codeoff();
74615931Smckusick 			    p = rvalue(r->expr_node.lhs, NLNIL , RREQ );
747771Speter 			    codeon();
74815931Smckusick 			    if (p == NLNIL)
74915931Smckusick 				    return (NLNIL);
7501555Speter 			    if (width(p) > width(p1))
751771Speter 				    contype = p;
752771Speter 		    }
75316273Speter 		    if (isa(p1, "t")) {
75416273Speter 			codeoff();
75516273Speter 			contype = rvalue(r->expr_node.lhs, p1, RREQ);
75616273Speter 			codeon();
75716273Speter 			if (contype == NLNIL) {
75816273Speter 			    return NLNIL;
75916273Speter 			}
76016273Speter 		    }
761771Speter 		    /*
762771Speter 		     * Now we generate code for
763771Speter 		     * the operands of the relational
764771Speter 		     * operation.
765771Speter 		     */
76615931Smckusick 		    p = rvalue(r->expr_node.lhs, contype , RREQ );
76715931Smckusick 		    if (p == NLNIL)
76815931Smckusick 			    return (NLNIL);
76915931Smckusick 		    p1 = rvalue(r->expr_node.rhs, p , RREQ );
77015931Smckusick 		    if (p1 == NLNIL)
77115931Smckusick 			    return (NLNIL);
772771Speter #		endif OBJ
773771Speter #		ifdef PC
774771Speter 		    c1 = classify( p1 );
775771Speter 		    if ( c1 == TSET || c1 == TSTR || c1 == TREC ) {
77618468Sralph 			putleaf( PCC_ICON , 0 , 0
77718468Sralph 				, PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR )
77815931Smckusick 				, c1 == TSET  ? relts[ r->tag - T_EQ ]
77915931Smckusick 					      : relss[ r->tag - T_EQ ] );
780771Speter 			    /*
781771Speter 			     *	for [] and strings, comparisons are done on
782771Speter 			     *	the maximum width of the two sides.
783771Speter 			     *	for other sets, we have to ask the left side
784771Speter 			     *	what type it is based on the type of the right.
785771Speter 			     *	(this matters for intsets).
786771Speter 			     */
7871555Speter 			if ( c1 == TSTR ) {
788771Speter 			    codeoff();
78915931Smckusick 			    p = rvalue( r->expr_node.lhs , NLNIL , LREQ );
790771Speter 			    codeon();
79115931Smckusick 			    if ( p == NLNIL ) {
79215931Smckusick 				return NLNIL;
7931555Speter 			    }
7941555Speter 			    if ( lwidth( p ) > lwidth( p1 ) ) {
795771Speter 				contype = p;
796771Speter 			    }
7971555Speter 			} else if ( c1 == TSET ) {
79815937Smckusick 			    codeoff();
79916273Speter 			    contype = rvalue(r->expr_node.lhs, p1, LREQ);
80015937Smckusick 			    codeon();
80116273Speter 			    if (contype == NLNIL) {
80215937Smckusick 				return NLNIL;
8031555Speter 			    }
8041627Speter 			}
805771Speter 			    /*
806771Speter 			     *	put out the width of the comparison.
807771Speter 			     */
80818468Sralph 			putleaf(PCC_ICON, (int) lwidth(contype), 0, PCCT_INT, (char *) 0);
809771Speter 			    /*
810771Speter 			     *	and the left hand side,
811771Speter 			     *	for sets, strings, records
812771Speter 			     */
81315931Smckusick 			p = rvalue( r->expr_node.lhs , contype , LREQ );
81415931Smckusick 			if ( p == NLNIL ) {
81515931Smckusick 			    return NLNIL;
8165413Speter 			}
81718468Sralph 			putop( PCC_CM , PCCT_INT );
81815931Smckusick 			p1 = rvalue( r->expr_node.rhs , p , LREQ );
81915931Smckusick 			if ( p1 == NLNIL ) {
82015931Smckusick 			    return NLNIL;
8215413Speter 			}
82218468Sralph 			putop( PCC_CM , PCCT_INT );
82318468Sralph 			putop( PCC_CALL , PCCT_INT );
824771Speter 		    } else {
825771Speter 			    /*
826771Speter 			     *	the easy (scalar or error) case
827771Speter 			     */
82815931Smckusick 			p = rvalue( r->expr_node.lhs , contype , RREQ );
82915931Smckusick 			if ( p == NLNIL ) {
83015931Smckusick 			    return NLNIL;
8312056Speter 			}
832771Speter 			    /*
833771Speter 			     * since the second pass can't do
834771Speter 			     *	long op double  or  double op long
835771Speter 			     * we may have to do some coercing.
836771Speter 			     */
83715931Smckusick 			tuac(p, p1, &rettype, (int *) (&ctype));
83815931Smckusick 			p1 = rvalue( r->expr_node.rhs , p , RREQ );
83915931Smckusick 			if ( p1 == NLNIL ) {
84015931Smckusick 			    return NLNIL;
8415413Speter 			}
84215931Smckusick 			tuac(p1, p, &rettype, (int *) (&ctype));
84318468Sralph 			putop((int) relops[ r->tag - T_EQ ] , PCCT_INT );
84418468Sralph 			sconv(PCCT_INT, PCCT_CHAR);
845771Speter 		    }
846771Speter #		endif PC
847771Speter 		c = classify(p);
848771Speter 		c1 = classify(p1);
849771Speter 		if (nocomp(c) || nocomp(c1))
85015931Smckusick 			return (NLNIL);
85115931Smckusick #		ifdef OBJ
85215931Smckusick 		    g = NIL;
85315931Smckusick #		endif
854771Speter 		switch (c) {
855771Speter 			case TBOOL:
856771Speter 			case TCHAR:
857771Speter 				if (c != c1)
858771Speter 					goto clash;
859771Speter 				break;
860771Speter 			case TINT:
861771Speter 			case TDOUBLE:
862771Speter 				if (c1 != TINT && c1 != TDOUBLE)
863771Speter 					goto clash;
864771Speter 				break;
865771Speter 			case TSCAL:
866771Speter 				if (c1 != TSCAL)
867771Speter 					goto clash;
868771Speter 				if (scalar(p) != scalar(p1))
869771Speter 					goto nonident;
870771Speter 				break;
871771Speter 			case TSET:
872771Speter 				if (c1 != TSET)
873771Speter 					goto clash;
8743397Speter 				if ( opt( 's' ) &&
87515931Smckusick 				    ( ( r->tag == T_LT) || (r->tag == T_GT) ) &&
8763397Speter 				    ( line != nssetline ) ) {
8773397Speter 				    nssetline = line;
8783397Speter 				    standard();
8793397Speter 				    error("%s comparison on sets is non-standard" , opname );
8803397Speter 				}
881771Speter 				if (p != p1)
882771Speter 					goto nonident;
88315931Smckusick #				ifdef OBJ
88415931Smckusick 				    g = TSET;
88515931Smckusick #				endif
886771Speter 				break;
887771Speter 			case TREC:
888771Speter 				if ( c1 != TREC ) {
889771Speter 				    goto clash;
890771Speter 				}
891771Speter 				if ( p != p1 ) {
892771Speter 				    goto nonident;
893771Speter 				}
89415931Smckusick 				if (r->tag != T_EQ && r->tag != T_NE) {
895771Speter 					error("%s not allowed on records - only allow = and <>" , opname );
89615931Smckusick 					return (NLNIL);
897771Speter 				}
89815931Smckusick #				ifdef OBJ
89915931Smckusick 				    g = TREC;
90015931Smckusick #				endif
901771Speter 				break;
902771Speter 			case TPTR:
903771Speter 			case TNIL:
904771Speter 				if (c1 != TPTR && c1 != TNIL)
905771Speter 					goto clash;
90615931Smckusick 				if (r->tag != T_EQ && r->tag != T_NE) {
907771Speter 					error("%s not allowed on pointers - only allow = and <>" , opname );
90815931Smckusick 					return (NLNIL);
909771Speter 				}
91015937Smckusick 				if (p != nl+TNIL && p1 != nl+TNIL && p != p1)
91115937Smckusick 					goto nonident;
912771Speter 				break;
913771Speter 			case TSTR:
914771Speter 				if (c1 != TSTR)
915771Speter 					goto clash;
916771Speter 				if (width(p) != width(p1)) {
917771Speter 					error("Strings not same length in %s comparison", opname);
91815931Smckusick 					return (NLNIL);
919771Speter 				}
92015931Smckusick #				ifdef OBJ
92115931Smckusick 				    g = TSTR;
92215931Smckusick #				endif OBJ
923771Speter 				break;
924771Speter 			default:
925771Speter 				panic("rval2");
926771Speter 		}
927771Speter #		ifdef OBJ
92815931Smckusick 		    return (gen(g, r->tag, width(p), width(p1)));
929771Speter #		endif OBJ
930771Speter #		ifdef PC
931771Speter 		    return nl + TBOOL;
932771Speter #		endif PC
933771Speter clash:
934771Speter 		error("%ss and %ss cannot be compared - operator was %s", clnames[c], clnames[c1], opname);
93515931Smckusick 		return (NLNIL);
936771Speter nonident:
937771Speter 		error("%s types must be identical in comparisons - operator was %s", clnames[c1], opname);
93815931Smckusick 		return (NLNIL);
939771Speter 
940771Speter 	case T_IN:
94115931Smckusick 	    rt = r->expr_node.rhs;
942771Speter #	    ifdef OBJ
94315931Smckusick 		if (rt != TR_NIL && rt->tag == T_CSET) {
94415931Smckusick 			(void) precset( rt , NLNIL , &csetd );
945771Speter 			p1 = csetd.csettype;
94615931Smckusick 			if (p1 == NLNIL)
94715931Smckusick 			    return NLNIL;
948771Speter 			postcset( rt, &csetd);
949771Speter 		    } else {
95015931Smckusick 			p1 = stkrval(r->expr_node.rhs, NLNIL , (long) RREQ );
95115931Smckusick 			rt = TR_NIL;
952771Speter 		    }
953771Speter #		endif OBJ
954771Speter #		ifdef PC
95515931Smckusick 		    if (rt != TR_NIL && rt->tag == T_CSET) {
95615931Smckusick 			if ( precset( rt , NLNIL , &csetd ) ) {
95718468Sralph 			    putleaf( PCC_ICON , 0 , 0
95818468Sralph 				    , PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR )
9591555Speter 				    , "_IN" );
960771Speter 			} else {
96118468Sralph 			    putleaf( PCC_ICON , 0 , 0
96218468Sralph 				    , PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR )
963771Speter 				    , "_INCT" );
964771Speter 			}
965771Speter 			p1 = csetd.csettype;
966771Speter 			if (p1 == NIL)
96715931Smckusick 			    return NLNIL;
968771Speter 		    } else {
96918468Sralph 			putleaf( PCC_ICON , 0 , 0
97018468Sralph 				, PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR )
971771Speter 				, "_IN" );
972771Speter 			codeoff();
97315931Smckusick 			p1 = rvalue(r->expr_node.rhs, NLNIL , LREQ );
974771Speter 			codeon();
975771Speter 		    }
976771Speter #		endif PC
97715931Smckusick 		p = stkrval(r->expr_node.lhs, NLNIL , (long) RREQ );
978771Speter 		if (p == NIL || p1 == NIL)
97915931Smckusick 			return (NLNIL);
98015931Smckusick 		if (p1->class != (char) SET) {
981771Speter 			error("Right operand of 'in' must be a set, not %s", nameof(p1));
98215931Smckusick 			return (NLNIL);
983771Speter 		}
98415931Smckusick 		if (incompat(p, p1->type, r->expr_node.lhs)) {
985771Speter 			cerror("Index type clashed with set component type for 'in'");
98615931Smckusick 			return (NLNIL);
987771Speter 		}
988771Speter 		setran(p1->type);
989771Speter #		ifdef OBJ
99015931Smckusick 		    if (rt == TR_NIL || csetd.comptime)
99115931Smckusick 			    (void) put(4, O_IN, width(p1), set.lwrb, set.uprbp);
992771Speter 		    else
99315931Smckusick 			    (void) put(2, O_INCT,
9943078Smckusic 				(int)(3 + csetd.singcnt + 2*csetd.paircnt));
995771Speter #		endif OBJ
996771Speter #		ifdef PC
99715931Smckusick 		    if ( rt == TR_NIL || rt->tag != T_CSET ) {
99818468Sralph 			putleaf( PCC_ICON , set.lwrb , 0 , PCCT_INT , (char *) 0 );
99918468Sralph 			putop( PCC_CM , PCCT_INT );
100018468Sralph 			putleaf( PCC_ICON , set.uprbp , 0 , PCCT_INT , (char *) 0 );
100118468Sralph 			putop( PCC_CM , PCCT_INT );
100215931Smckusick 			p1 = rvalue( r->expr_node.rhs , NLNIL , LREQ );
100315931Smckusick 			if ( p1 == NLNIL ) {
100415931Smckusick 			    return NLNIL;
10055413Speter 			}
100618468Sralph 			putop( PCC_CM , PCCT_INT );
1007771Speter 		    } else if ( csetd.comptime ) {
100818468Sralph 			putleaf( PCC_ICON , set.lwrb , 0 , PCCT_INT , (char *) 0 );
100918468Sralph 			putop( PCC_CM , PCCT_INT );
101018468Sralph 			putleaf( PCC_ICON , set.uprbp , 0 , PCCT_INT , (char *) 0 );
101118468Sralph 			putop( PCC_CM , PCCT_INT );
101215931Smckusick 			postcset( r->expr_node.rhs , &csetd );
101318468Sralph 			putop( PCC_CM , PCCT_INT );
1014771Speter 		    } else {
101515931Smckusick 			postcset( r->expr_node.rhs , &csetd );
1016771Speter 		    }
101718468Sralph 		    putop( PCC_CALL , PCCT_INT );
101818468Sralph 		    sconv(PCCT_INT, PCCT_CHAR);
1019771Speter #		endif PC
1020771Speter 		return (nl+T1BOOL);
1021771Speter 	default:
102215931Smckusick 		if (r->expr_node.lhs == TR_NIL)
102315931Smckusick 			return (NLNIL);
102415931Smckusick 		switch (r->tag) {
1025771Speter 		default:
1026771Speter 			panic("rval3");
1027771Speter 
1028771Speter 
1029771Speter 		/*
1030771Speter 		 * An octal number
1031771Speter 		 */
1032771Speter 		case T_BINT:
103315931Smckusick 			f.pdouble = a8tol(r->const_node.cptr);
1034771Speter 			goto conint;
1035771Speter 
1036771Speter 		/*
1037771Speter 		 * A decimal number
1038771Speter 		 */
1039771Speter 		case T_INT:
104015931Smckusick 			f.pdouble = atof(r->const_node.cptr);
1041771Speter conint:
104215931Smckusick 			if (f.pdouble > MAXINT || f.pdouble < MININT) {
1043771Speter 				error("Constant too large for this implementation");
104415931Smckusick 				return (NLNIL);
1045771Speter 			}
104615931Smckusick 			l = f.pdouble;
104710364Smckusick #			ifdef OBJ
104810364Smckusick 			    if (bytes(l, l) <= 2) {
104915931Smckusick 				    (void) put(2, O_CON2, ( short ) l);
105010364Smckusick 				    return (nl+T2INT);
105110364Smckusick 			    }
105215931Smckusick 			    (void) put(2, O_CON4, l);
105310364Smckusick 			    return (nl+T4INT);
1054771Speter #			endif OBJ
1055771Speter #			ifdef PC
105610364Smckusick 			    switch (bytes(l, l)) {
105710364Smckusick 				case 1:
105818468Sralph 				    putleaf(PCC_ICON, (int) l, 0, PCCT_CHAR,
105915931Smckusick 						(char *) 0);
106010364Smckusick 				    return nl+T1INT;
106110364Smckusick 				case 2:
106218468Sralph 				    putleaf(PCC_ICON, (int) l, 0, PCCT_SHORT,
106315931Smckusick 						(char *) 0);
106410364Smckusick 				    return nl+T2INT;
106510364Smckusick 				case 4:
106618468Sralph 				    putleaf(PCC_ICON, (int) l, 0, PCCT_INT,
106715931Smckusick 						(char *) 0);
106810364Smckusick 				    return nl+T4INT;
106910364Smckusick 			    }
1070771Speter #			endif PC
1071771Speter 
1072771Speter 		/*
1073771Speter 		 * A floating point number
1074771Speter 		 */
1075771Speter 		case T_FINT:
1076771Speter #			ifdef OBJ
107715931Smckusick 			    (void) put(2, O_CON8, atof(r->const_node.cptr));
1078771Speter #			endif OBJ
1079771Speter #			ifdef PC
108015931Smckusick 			    putCON8( atof( r->const_node.cptr ) );
1081771Speter #			endif PC
1082771Speter 			return (nl+TDOUBLE);
1083771Speter 
1084771Speter 		/*
1085771Speter 		 * Constant strings.  Note that constant characters
1086771Speter 		 * are constant strings of length one; there is
1087771Speter 		 * no constant string of length one.
1088771Speter 		 */
1089771Speter 		case T_STRNG:
109015931Smckusick 			cp = r->const_node.cptr;
1091771Speter 			if (cp[1] == 0) {
1092771Speter #				ifdef OBJ
109315931Smckusick 				    (void) put(2, O_CONC, cp[0]);
1094771Speter #				endif OBJ
1095771Speter #				ifdef PC
109618468Sralph 				    putleaf( PCC_ICON , cp[0] , 0 , PCCT_CHAR ,
109715931Smckusick 						(char *) 0 );
1098771Speter #				endif PC
1099771Speter 				return (nl+T1CHAR);
1100771Speter 			}
1101771Speter 			goto cstrng;
1102771Speter 		}
1103771Speter 
1104771Speter 	}
1105771Speter }
1106771Speter 
1107771Speter /*
1108771Speter  * Can a class appear
1109771Speter  * in a comparison ?
1110771Speter  */
nocomp(c)1111771Speter nocomp(c)
1112771Speter 	int c;
1113771Speter {
1114771Speter 
1115771Speter 	switch (c) {
1116771Speter 		case TREC:
11171627Speter 			if ( line != reccompline ) {
11181627Speter 			    reccompline = line;
11191627Speter 			    warning();
11201627Speter 			    if ( opt( 's' ) ) {
11211627Speter 				standard();
11221627Speter 			    }
1123771Speter 			    error("record comparison is non-standard");
1124771Speter 			}
1125771Speter 			break;
1126771Speter 		case TFILE:
1127771Speter 		case TARY:
1128771Speter 			error("%ss may not participate in comparisons", clnames[c]);
1129771Speter 			return (1);
1130771Speter 	}
1131771Speter 	return (NIL);
1132771Speter }
1133771Speter 
1134771Speter     /*
1135771Speter      *	this is sort of like gconst, except it works on expression trees
1136771Speter      *	rather than declaration trees, and doesn't give error messages for
1137771Speter      *	non-constant things.
1138771Speter      *	as a side effect this fills in the con structure that gconst uses.
1139771Speter      *	this returns TRUE or FALSE.
1140771Speter      */
114115931Smckusick 
114215931Smckusick bool
constval(r)1143771Speter constval(r)
114415931Smckusick 	register struct tnode *r;
1145771Speter {
1146771Speter 	register struct nl *np;
114715931Smckusick 	register struct tnode *cn;
1148771Speter 	char *cp;
1149771Speter 	int negd, sgnd;
1150771Speter 	long ci;
1151771Speter 
1152771Speter 	con.ctype = NIL;
1153771Speter 	cn = r;
1154771Speter 	negd = sgnd = 0;
1155771Speter loop:
1156771Speter 	    /*
1157771Speter 	     *	cn[2] is nil if error recovery generated a T_STRNG
1158771Speter 	     */
115915931Smckusick 	if (cn == TR_NIL || cn->expr_node.lhs == TR_NIL)
1160771Speter 		return FALSE;
116115931Smckusick 	switch (cn->tag) {
1162771Speter 		default:
1163771Speter 			return FALSE;
1164771Speter 		case T_MINUS:
1165771Speter 			negd = 1 - negd;
1166771Speter 			/* and fall through */
1167771Speter 		case T_PLUS:
1168771Speter 			sgnd++;
116915931Smckusick 			cn = cn->un_expr.expr;
1170771Speter 			goto loop;
1171771Speter 		case T_NIL:
1172771Speter 			con.cpval = NIL;
1173771Speter 			con.cival = 0;
1174771Speter 			con.crval = con.cival;
1175771Speter 			con.ctype = nl + TNIL;
1176771Speter 			break;
1177771Speter 		case T_VAR:
117815931Smckusick 			np = lookup(cn->var_node.cptr);
117915931Smckusick 			if (np == NLNIL || np->class != CONST) {
1180771Speter 				return FALSE;
1181771Speter 			}
118215931Smckusick 			if ( cn->var_node.qual != TR_NIL ) {
1183771Speter 				return FALSE;
1184771Speter 			}
1185771Speter 			con.ctype = np->type;
1186771Speter 			switch (classify(np->type)) {
1187771Speter 				case TINT:
1188771Speter 					con.crval = np->range[0];
1189771Speter 					break;
1190771Speter 				case TDOUBLE:
1191771Speter 					con.crval = np->real;
1192771Speter 					break;
1193771Speter 				case TBOOL:
1194771Speter 				case TCHAR:
1195771Speter 				case TSCAL:
1196771Speter 					con.cival = np->value[0];
1197771Speter 					con.crval = con.cival;
1198771Speter 					break;
1199771Speter 				case TSTR:
120015931Smckusick 					con.cpval = (char *) np->ptr[0];
1201771Speter 					break;
1202771Speter 				default:
1203771Speter 					con.ctype = NIL;
1204771Speter 					return FALSE;
1205771Speter 			}
1206771Speter 			break;
1207771Speter 		case T_BINT:
120815931Smckusick 			con.crval = a8tol(cn->const_node.cptr);
1209771Speter 			goto restcon;
1210771Speter 		case T_INT:
121115931Smckusick 			con.crval = atof(cn->const_node.cptr);
1212771Speter 			if (con.crval > MAXINT || con.crval < MININT) {
1213771Speter 				derror("Constant too large for this implementation");
1214771Speter 				con.crval = 0;
1215771Speter 			}
1216771Speter restcon:
1217771Speter 			ci = con.crval;
1218771Speter #ifndef PI0
1219771Speter 			if (bytes(ci, ci) <= 2)
1220771Speter 				con.ctype = nl+T2INT;
1221771Speter 			else
1222771Speter #endif
1223771Speter 				con.ctype = nl+T4INT;
1224771Speter 			break;
1225771Speter 		case T_FINT:
1226771Speter 			con.ctype = nl+TDOUBLE;
122715931Smckusick 			con.crval = atof(cn->const_node.cptr);
1228771Speter 			break;
1229771Speter 		case T_STRNG:
123015931Smckusick 			cp = cn->const_node.cptr;
1231771Speter 			if (cp[1] == 0) {
1232771Speter 				con.ctype = nl+T1CHAR;
1233771Speter 				con.cival = cp[0];
1234771Speter 				con.crval = con.cival;
1235771Speter 				break;
1236771Speter 			}
1237771Speter 			con.ctype = nl+TSTR;
1238771Speter 			con.cpval = cp;
1239771Speter 			break;
1240771Speter 	}
1241771Speter 	if (sgnd) {
1242771Speter 		if (isnta(con.ctype, "id")) {
1243771Speter 			derror("%s constants cannot be signed", nameof(con.ctype));
1244771Speter 			return FALSE;
1245771Speter 		} else if (negd)
1246771Speter 			con.crval = -con.crval;
1247771Speter 	}
1248771Speter 	return TRUE;
1249771Speter }
1250