xref: /csrg-svn/usr.bin/pascal/src/rval.c (revision 22188)
1*22188Sdist /*
2*22188Sdist  * Copyright (c) 1980 Regents of the University of California.
3*22188Sdist  * All rights reserved.  The Berkeley software License Agreement
4*22188Sdist  * specifies the terms and conditions for redistribution.
5*22188Sdist  */
6771Speter 
715945Speter #ifndef lint
8*22188Sdist static char sccsid[] = "@(#)rval.c	5.1 (Berkeley) 06/05/85";
9*22188Sdist #endif not lint
10771Speter 
11771Speter #include "whoami.h"
12771Speter #include "0.h"
13771Speter #include "tree.h"
14771Speter #include "opcode.h"
15771Speter #include "objfmt.h"
16771Speter #ifdef PC
17771Speter #   include	"pc.h"
1818468Sralph #   include <pcc.h>
19771Speter #endif PC
2011328Speter #include "tmps.h"
2115931Smckusick #include "tree_ty.h"
22771Speter 
23771Speter extern	char *opnames[];
24771Speter 
251627Speter     /* line number of the last record comparison warning */
261627Speter short reccompline = 0;
273397Speter     /* line number of the last non-standard set comparison */
283397Speter short nssetline = 0;
291627Speter 
30771Speter #ifdef PC
31771Speter     char	*relts[] =  {
32771Speter 				"_RELEQ" , "_RELNE" ,
33771Speter 				"_RELTLT" , "_RELTGT" ,
34771Speter 				"_RELTLE" , "_RELTGE"
35771Speter 			    };
36771Speter     char	*relss[] =  {
37771Speter 				"_RELEQ" , "_RELNE" ,
38771Speter 				"_RELSLT" , "_RELSGT" ,
39771Speter 				"_RELSLE" , "_RELSGE"
40771Speter 			    };
41771Speter     long	relops[] =  {
4218468Sralph 				PCC_EQ , PCC_NE ,
4318468Sralph 				PCC_LT , PCC_GT ,
4418468Sralph 				PCC_LE , PCC_GE
45771Speter 			    };
4618468Sralph     long	mathop[] =  {	PCC_MUL , PCC_PLUS , PCC_MINUS };
47771Speter     char	*setop[] =  {	"_MULT" , "_ADDT" , "_SUBT" };
48771Speter #endif PC
49771Speter /*
50771Speter  * Rvalue - an expression.
51771Speter  *
52771Speter  * Contype is the type that the caller would prefer, nand is important
5316273Speter  * if constant strings are involved, because of string padding.
54771Speter  * required is a flag whether an lvalue or an rvalue is required.
55771Speter  * only VARs and structured things can have gt their lvalue this way.
56771Speter  */
5715931Smckusick /*ARGSUSED*/
58771Speter struct nl *
59771Speter rvalue(r, contype , required )
6015931Smckusick 	struct tnode *r;
61771Speter 	struct nl *contype;
62771Speter 	int	required;
63771Speter {
64771Speter 	register struct nl *p, *p1;
65771Speter 	register struct nl *q;
6615931Smckusick 	int c, c1, w;
6715931Smckusick #ifdef OBJ
6815931Smckusick 	int g;
6915931Smckusick #endif
7015931Smckusick 	struct tnode *rt;
71771Speter 	char *cp, *cp1, *opname;
72771Speter 	long l;
7315931Smckusick 	union
7415931Smckusick 	{
7515931Smckusick 	    long plong[2];
7615931Smckusick 	    double pdouble;
7715931Smckusick 	}f;
78771Speter 	extern int	flagwas;
79771Speter 	struct csetstr	csetd;
80771Speter #	ifdef PC
81771Speter 	    struct nl	*rettype;
82771Speter 	    long	ctype;
833834Speter 	    struct nl	*tempnlp;
84771Speter #	endif PC
85771Speter 
8615931Smckusick 	if (r == TR_NIL)
8715931Smckusick 		return (NLNIL);
88771Speter 	if (nowexp(r))
8915931Smckusick 		return (NLNIL);
90771Speter 	/*
91771Speter 	 * Pick up the name of the operation
92771Speter 	 * for future error messages.
93771Speter 	 */
9415931Smckusick 	if (r->tag <= T_IN)
9515931Smckusick 		opname = opnames[r->tag];
96771Speter 
97771Speter 	/*
98771Speter 	 * The root of the tree tells us what sort of expression we have.
99771Speter 	 */
10015931Smckusick 	switch (r->tag) {
101771Speter 
102771Speter 	/*
103771Speter 	 * The constant nil
104771Speter 	 */
105771Speter 	case T_NIL:
106771Speter #		ifdef OBJ
10715931Smckusick 		    (void) put(2, O_CON2, 0);
108771Speter #		endif OBJ
109771Speter #		ifdef PC
11018468Sralph 		    putleaf( PCC_ICON , 0 , 0 , PCCTM_PTR|PCCT_UNDEF , (char *) 0 );
111771Speter #		endif PC
112771Speter 		return (nl+TNIL);
113771Speter 
114771Speter 	/*
115771Speter 	 * Function call with arguments.
116771Speter 	 */
117771Speter 	case T_FCALL:
118771Speter #	    ifdef OBJ
119771Speter 		return (funccod(r));
120771Speter #	    endif OBJ
121771Speter #	    ifdef PC
122771Speter 		return (pcfunccod( r ));
123771Speter #	    endif PC
124771Speter 
125771Speter 	case T_VAR:
12615931Smckusick 		p = lookup(r->var_node.cptr);
12715931Smckusick 		if (p == NLNIL || p->class == BADUSE)
12815931Smckusick 			return (NLNIL);
129771Speter 		switch (p->class) {
130771Speter 		    case VAR:
131771Speter 			    /*
132771Speter 			     * If a variable is
133771Speter 			     * qualified then get
134771Speter 			     * the rvalue by a
135771Speter 			     * lvalue and an ind.
136771Speter 			     */
13715931Smckusick 			    if (r->var_node.qual != TR_NIL)
138771Speter 				    goto ind;
139771Speter 			    q = p->type;
140771Speter 			    if (q == NIL)
14115931Smckusick 				    return (NLNIL);
142771Speter #			    ifdef OBJ
143771Speter 				w = width(q);
144771Speter 				switch (w) {
145771Speter 				    case 8:
14615931Smckusick 					(void) put(2, O_RV8 | bn << 8+INDX,
1473078Smckusic 						(int)p->value[0]);
148771Speter 					break;
149771Speter 				    case 4:
15015931Smckusick 					(void) put(2, O_RV4 | bn << 8+INDX,
1513078Smckusic 						(int)p->value[0]);
152771Speter 					break;
153771Speter 				    case 2:
15415931Smckusick 					(void) put(2, O_RV2 | bn << 8+INDX,
1553078Smckusic 						(int)p->value[0]);
156771Speter 					break;
157771Speter 				    case 1:
15815931Smckusick 					(void) put(2, O_RV1 | bn << 8+INDX,
1593078Smckusic 						(int)p->value[0]);
160771Speter 					break;
161771Speter 				    default:
16215931Smckusick 					(void) put(3, O_RV | bn << 8+INDX,
1633078Smckusic 						(int)p->value[0], w);
164771Speter 				}
165771Speter #			   endif OBJ
166771Speter #			   ifdef PC
167771Speter 				if ( required == RREQ ) {
1683834Speter 				    putRV( p -> symbol , bn , p -> value[0] ,
1693834Speter 					    p -> extra_flags , p2type( q ) );
170771Speter 				} else {
1713834Speter 				    putLV( p -> symbol , bn , p -> value[0] ,
1723834Speter 					    p -> extra_flags , p2type( q ) );
173771Speter 				}
174771Speter #			   endif PC
175771Speter 			   return (q);
176771Speter 
177771Speter 		    case WITHPTR:
178771Speter 		    case REF:
179771Speter 			    /*
180771Speter 			     * A lvalue for these
181771Speter 			     * is actually what one
182771Speter 			     * might consider a rvalue.
183771Speter 			     */
184771Speter ind:
185771Speter 			    q = lvalue(r, NOFLAGS , LREQ );
186771Speter 			    if (q == NIL)
18715931Smckusick 				    return (NLNIL);
188771Speter #			    ifdef OBJ
189771Speter 				w = width(q);
190771Speter 				switch (w) {
191771Speter 				    case 8:
19215931Smckusick 					    (void) put(1, O_IND8);
193771Speter 					    break;
194771Speter 				    case 4:
19515931Smckusick 					    (void) put(1, O_IND4);
196771Speter 					    break;
197771Speter 				    case 2:
19815931Smckusick 					    (void) put(1, O_IND2);
199771Speter 					    break;
200771Speter 				    case 1:
20115931Smckusick 					    (void) put(1, O_IND1);
202771Speter 					    break;
203771Speter 				    default:
20415931Smckusick 					    (void) put(2, O_IND, w);
205771Speter 				}
206771Speter #			    endif OBJ
207771Speter #			    ifdef PC
208771Speter 				if ( required == RREQ ) {
20918468Sralph 				    putop( PCCOM_UNARY PCC_MUL , p2type( q ) );
210771Speter 				}
211771Speter #			    endif PC
212771Speter 			    return (q);
213771Speter 
214771Speter 		    case CONST:
21515931Smckusick 			    if (r->var_node.qual != TR_NIL) {
21615931Smckusick 				error("%s is a constant and cannot be qualified", r->var_node.cptr);
21715931Smckusick 				return (NLNIL);
218771Speter 			    }
219771Speter 			    q = p->type;
22015931Smckusick 			    if (q == NLNIL)
22115931Smckusick 				    return (NLNIL);
222771Speter 			    if (q == nl+TSTR) {
223771Speter 				    /*
224771Speter 				     * Find the size of the string
225771Speter 				     * constant if needed.
226771Speter 				     */
22715931Smckusick 				    cp = (char *) p->ptr[0];
228771Speter cstrng:
229771Speter 				    cp1 = cp;
230771Speter 				    for (c = 0; *cp++; c++)
231771Speter 					    continue;
2323078Smckusic 				    w = c;
233771Speter 				    if (contype != NIL && !opt('s')) {
234771Speter 					    if (width(contype) < c && classify(contype) == TSTR) {
235771Speter 						    error("Constant string too long");
23615931Smckusick 						    return (NLNIL);
237771Speter 					    }
2383078Smckusic 					    w = width(contype);
239771Speter 				    }
240771Speter #				    ifdef OBJ
24115931Smckusick 					(void) put(2, O_CONG, w);
2423078Smckusic 					putstr(cp1, w - c);
243771Speter #				    endif OBJ
244771Speter #				    ifdef PC
2453155Smckusic 					putCONG( cp1 , w , required );
246771Speter #				    endif PC
247771Speter 				    /*
248771Speter 				     * Define the string temporarily
249771Speter 				     * so later people can know its
250771Speter 				     * width.
251771Speter 				     * cleaned out by stat.
252771Speter 				     */
25315931Smckusick 				    q = defnl((char *) 0, STR, NLNIL, w);
254771Speter 				    q->type = q;
255771Speter 				    return (q);
256771Speter 			    }
257771Speter 			    if (q == nl+T1CHAR) {
258771Speter #				    ifdef OBJ
25915931Smckusick 					(void) put(2, O_CONC, (int)p->value[0]);
260771Speter #				    endif OBJ
261771Speter #				    ifdef PC
26218468Sralph 					putleaf( PCC_ICON , p -> value[0] , 0
26318468Sralph 						, PCCT_CHAR , (char *) 0 );
264771Speter #				    endif PC
265771Speter 				    return (q);
266771Speter 			    }
267771Speter 			    /*
268771Speter 			     * Every other kind of constant here
269771Speter 			     */
270771Speter 			    switch (width(q)) {
271771Speter 			    case 8:
272771Speter #ifndef DEBUG
273771Speter #				    ifdef OBJ
27415931Smckusick 					(void) put(2, O_CON8, p->real);
275771Speter #				    endif OBJ
276771Speter #				    ifdef PC
277771Speter 					putCON8( p -> real );
278771Speter #				    endif PC
279771Speter #else
280771Speter 				    if (hp21mx) {
28115931Smckusick 					    f.pdouble = p->real;
28215931Smckusick 					    conv((int *) (&f.pdouble));
28315931Smckusick 					    l = f.plong[1];
28415931Smckusick 					    (void) put(2, O_CON4, l);
285771Speter 				    } else
286771Speter #					    ifdef OBJ
28715931Smckusick 						(void) put(2, O_CON8, p->real);
288771Speter #					    endif OBJ
289771Speter #					    ifdef PC
290771Speter 						putCON8( p -> real );
291771Speter #					    endif PC
292771Speter #endif
293771Speter 				    break;
294771Speter 			    case 4:
295771Speter #				    ifdef OBJ
29615931Smckusick 					(void) put(2, O_CON4, p->range[0]);
297771Speter #				    endif OBJ
298771Speter #				    ifdef PC
29918468Sralph 					putleaf( PCC_ICON , (int) p->range[0] , 0
30018468Sralph 						, PCCT_INT , (char *) 0 );
301771Speter #				    endif PC
302771Speter 				    break;
303771Speter 			    case 2:
304771Speter #				    ifdef OBJ
30515931Smckusick 					(void) put(2, O_CON2, (short)p->range[0]);
306771Speter #				    endif OBJ
307771Speter #				    ifdef PC
30818468Sralph 					putleaf( PCC_ICON , (short) p -> range[0]
30918468Sralph 						, 0 , PCCT_SHORT , (char *) 0 );
310771Speter #				    endif PC
311771Speter 				    break;
312771Speter 			    case 1:
313771Speter #				    ifdef OBJ
31415931Smckusick 					(void) put(2, O_CON1, p->value[0]);
315771Speter #				    endif OBJ
316771Speter #				    ifdef PC
31718468Sralph 					putleaf( PCC_ICON , p -> value[0] , 0
31818468Sralph 						, PCCT_CHAR , (char *) 0 );
319771Speter #				    endif PC
320771Speter 				    break;
321771Speter 			    default:
322771Speter 				    panic("rval");
323771Speter 			    }
324771Speter 			    return (q);
325771Speter 
326771Speter 		    case FUNC:
3271200Speter 		    case FFUNC:
328771Speter 			    /*
329771Speter 			     * Function call with no arguments.
330771Speter 			     */
33115931Smckusick 			    if (r->var_node.qual != TR_NIL) {
332771Speter 				    error("Can't qualify a function result value");
33315931Smckusick 				    return (NLNIL);
334771Speter 			    }
335771Speter #			    ifdef OBJ
33615931Smckusick 				return (funccod(r));
337771Speter #			    endif OBJ
338771Speter #			    ifdef PC
339771Speter 				return (pcfunccod( r ));
340771Speter #			    endif PC
341771Speter 
342771Speter 		    case TYPE:
343771Speter 			    error("Type names (e.g. %s) allowed only in declarations", p->symbol);
34415931Smckusick 			    return (NLNIL);
345771Speter 
346771Speter 		    case PROC:
3471200Speter 		    case FPROC:
348771Speter 			    error("Procedure %s found where expression required", p->symbol);
34915931Smckusick 			    return (NLNIL);
350771Speter 		    default:
351771Speter 			    panic("rvid");
352771Speter 		}
353771Speter 	/*
354771Speter 	 * Constant sets
355771Speter 	 */
356771Speter 	case T_CSET:
357771Speter #		ifdef OBJ
358771Speter 		    if ( precset( r , contype , &csetd ) ) {
359771Speter 			if ( csetd.csettype == NIL ) {
36015931Smckusick 			    return (NLNIL);
361771Speter 			}
362771Speter 			postcset( r , &csetd );
363771Speter 		    } else {
36415931Smckusick 			(void) put( 2, O_PUSH, -lwidth(csetd.csettype));
365771Speter 			postcset( r , &csetd );
366771Speter 			setran( ( csetd.csettype ) -> type );
36715931Smckusick 			(void) put( 2, O_CON24, set.uprbp);
36815931Smckusick 			(void) put( 2, O_CON24, set.lwrb);
36915931Smckusick 			(void) put( 2, O_CTTOT,
3703078Smckusic 				(int)(4 + csetd.singcnt + 2 * csetd.paircnt));
371771Speter 		    }
372771Speter 		    return csetd.csettype;
373771Speter #		endif OBJ
374771Speter #		ifdef PC
375771Speter 		    if ( precset( r , contype , &csetd ) ) {
376771Speter 			if ( csetd.csettype == NIL ) {
37715931Smckusick 			    return (NLNIL);
378771Speter 			}
379771Speter 			postcset( r , &csetd );
380771Speter 		    } else {
38118468Sralph 			putleaf( PCC_ICON , 0 , 0
38218468Sralph 				, PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR )
383771Speter 				, "_CTTOT" );
384771Speter 			/*
385771Speter 			 *	allocate a temporary and use it
386771Speter 			 */
3873834Speter 			tempnlp = tmpalloc(lwidth(csetd.csettype),
3883227Smckusic 				csetd.csettype, NOREG);
38915931Smckusick 			putLV( (char *) 0 , cbn , tempnlp -> value[ NL_OFFS ] ,
39018468Sralph 				tempnlp -> extra_flags , PCCTM_PTR|PCCT_STRTY );
391771Speter 			setran( ( csetd.csettype ) -> type );
39218468Sralph 			putleaf( PCC_ICON , set.lwrb , 0 , PCCT_INT , (char *) 0 );
39318468Sralph 			putop( PCC_CM , PCCT_INT );
39418468Sralph 			putleaf( PCC_ICON , set.uprbp , 0 , PCCT_INT , (char *) 0 );
39518468Sralph 			putop( PCC_CM , PCCT_INT );
396771Speter 			postcset( r , &csetd );
39718468Sralph 			putop( PCC_CALL , PCCT_INT );
398771Speter 		    }
399771Speter 		    return csetd.csettype;
400771Speter #		endif PC
401771Speter 
402771Speter 	/*
403771Speter 	 * Unary plus and minus
404771Speter 	 */
405771Speter 	case T_PLUS:
406771Speter 	case T_MINUS:
40715931Smckusick 		q = rvalue(r->un_expr.expr, NLNIL , RREQ );
40815931Smckusick 		if (q == NLNIL)
40915931Smckusick 			return (NLNIL);
410771Speter 		if (isnta(q, "id")) {
411771Speter 			error("Operand of %s must be integer or real, not %s", opname, nameof(q));
41215931Smckusick 			return (NLNIL);
413771Speter 		}
41415931Smckusick 		if (r->tag == T_MINUS) {
415771Speter #		    ifdef OBJ
41615931Smckusick 			(void) put(1, O_NEG2 + (width(q) >> 2));
41710670Speter 			return (isa(q, "d") ? q : nl+T4INT);
418771Speter #		    endif OBJ
419771Speter #		    ifdef PC
42010670Speter 			if (isa(q, "i")) {
42118468Sralph 			    sconv(p2type(q), PCCT_INT);
42218468Sralph 			    putop( PCCOM_UNARY PCC_MINUS, PCCT_INT);
42310670Speter 			    return nl+T4INT;
42410670Speter 			}
42518468Sralph 			putop( PCCOM_UNARY PCC_MINUS, PCCT_DOUBLE);
42610670Speter 			return nl+TDOUBLE;
427771Speter #		    endif PC
428771Speter 		}
429771Speter 		return (q);
430771Speter 
431771Speter 	case T_NOT:
43215931Smckusick 		q = rvalue(r->un_expr.expr, NLNIL , RREQ );
43315931Smckusick 		if (q == NLNIL)
43415931Smckusick 			return (NLNIL);
435771Speter 		if (isnta(q, "b")) {
436771Speter 			error("not must operate on a Boolean, not %s", nameof(q));
43715931Smckusick 			return (NLNIL);
438771Speter 		}
439771Speter #		ifdef OBJ
44015931Smckusick 		    (void) put(1, O_NOT);
441771Speter #		endif OBJ
442771Speter #		ifdef PC
44318468Sralph 		    sconv(p2type(q), PCCT_INT);
44418468Sralph 		    putop( PCC_NOT , PCCT_INT);
44518468Sralph 		    sconv(PCCT_INT, p2type(q));
446771Speter #		endif PC
447771Speter 		return (nl+T1BOOL);
448771Speter 
449771Speter 	case T_AND:
450771Speter 	case T_OR:
45115931Smckusick 		p = rvalue(r->expr_node.lhs, NLNIL , RREQ );
45210364Smckusick #		ifdef PC
45318468Sralph 		    sconv(p2type(p),PCCT_INT);
45410364Smckusick #		endif PC
45515931Smckusick 		p1 = rvalue(r->expr_node.rhs, NLNIL , RREQ );
45610364Smckusick #		ifdef PC
45718468Sralph 		    sconv(p2type(p1),PCCT_INT);
45810364Smckusick #		endif PC
45915931Smckusick 		if (p == NLNIL || p1 == NLNIL)
46015931Smckusick 			return (NLNIL);
461771Speter 		if (isnta(p, "b")) {
462771Speter 			error("Left operand of %s must be Boolean, not %s", opname, nameof(p));
46315931Smckusick 			return (NLNIL);
464771Speter 		}
465771Speter 		if (isnta(p1, "b")) {
466771Speter 			error("Right operand of %s must be Boolean, not %s", opname, nameof(p1));
46715931Smckusick 			return (NLNIL);
468771Speter 		}
469771Speter #		ifdef OBJ
47015931Smckusick 		    (void) put(1, r->tag == T_AND ? O_AND : O_OR);
471771Speter #		endif OBJ
472771Speter #		ifdef PC
473771Speter 			/*
474771Speter 			 * note the use of & and | rather than && and ||
475771Speter 			 * to force evaluation of all the expressions.
476771Speter 			 */
47718468Sralph 		    putop( r->tag == T_AND ? PCC_AND : PCC_OR , PCCT_INT );
47818468Sralph 		    sconv(PCCT_INT, p2type(p));
479771Speter #		endif PC
480771Speter 		return (nl+T1BOOL);
481771Speter 
482771Speter 	case T_DIVD:
483771Speter #		ifdef OBJ
48415931Smckusick 		    p = rvalue(r->expr_node.lhs, NLNIL , RREQ );
48515931Smckusick 		    p1 = rvalue(r->expr_node.rhs, NLNIL , RREQ );
486771Speter #		endif OBJ
487771Speter #		ifdef PC
488771Speter 			/*
489771Speter 			 *	force these to be doubles for the divide
490771Speter 			 */
49115931Smckusick 		    p = rvalue( r->expr_node.lhs , NLNIL , RREQ );
49218468Sralph 		    sconv(p2type(p), PCCT_DOUBLE);
49315931Smckusick 		    p1 = rvalue( r->expr_node.rhs , NLNIL , RREQ );
49418468Sralph 		    sconv(p2type(p1), PCCT_DOUBLE);
495771Speter #		endif PC
49615931Smckusick 		if (p == NLNIL || p1 == NLNIL)
49715931Smckusick 			return (NLNIL);
498771Speter 		if (isnta(p, "id")) {
499771Speter 			error("Left operand of / must be integer or real, not %s", nameof(p));
50015931Smckusick 			return (NLNIL);
501771Speter 		}
502771Speter 		if (isnta(p1, "id")) {
503771Speter 			error("Right operand of / must be integer or real, not %s", nameof(p1));
50415931Smckusick 			return (NLNIL);
505771Speter 		}
506771Speter #		ifdef OBJ
50715931Smckusick 		    return gen(NIL, r->tag, width(p), width(p1));
508771Speter #		endif OBJ
509771Speter #		ifdef PC
51018468Sralph 		    putop( PCC_DIV , PCCT_DOUBLE );
511771Speter 		    return nl + TDOUBLE;
512771Speter #		endif PC
513771Speter 
514771Speter 	case T_MULT:
515771Speter 	case T_ADD:
516771Speter 	case T_SUB:
517771Speter #		ifdef OBJ
518771Speter 		    /*
51916273Speter 		     * get the type of the right hand side.
52016273Speter 		     * if it turns out to be a set,
52116273Speter 		     * use that type when getting
52216273Speter 		     * the type of the left hand side.
52316273Speter 		     * and then use the type of the left hand side
52416273Speter 		     * when generating code.
52516273Speter 		     * this will correctly decide the type of any
52616273Speter 		     * empty sets in the tree, since if the empty set
52716273Speter 		     * is on the left hand side it will inherit
52816273Speter 		     * the type of the right hand side,
52916273Speter 		     * and if it's on the right hand side, its type (intset)
53016273Speter 		     * will be overridden by the type of the left hand side.
53116273Speter 		     * this is an awful lot of tree traversing,
53216273Speter 		     * but it works.
533771Speter 		     */
53416273Speter 		    codeoff();
53516273Speter 		    p1 = rvalue( r->expr_node.rhs , NLNIL , RREQ );
53616273Speter 		    codeon();
53716273Speter 		    if ( p1 == NLNIL ) {
53815931Smckusick 			return NLNIL;
5391555Speter 		    }
54016273Speter 		    if (isa(p1, "t")) {
54116273Speter 			codeoff();
54216273Speter 			contype = rvalue(r->expr_node.lhs, p1, RREQ);
54316273Speter 			codeon();
54416273Speter 			if (contype == NLNIL) {
54516273Speter 			    return NLNIL;
54616273Speter 			}
54716273Speter 		    }
54815931Smckusick 		    p = rvalue( r->expr_node.lhs , contype , RREQ );
54915931Smckusick 		    p1 = rvalue( r->expr_node.rhs , p , RREQ );
55015937Smckusick 		    if ( p == NLNIL || p1 == NLNIL )
55115931Smckusick 			    return NLNIL;
552771Speter 		    if (isa(p, "id") && isa(p1, "id"))
55315931Smckusick 			return (gen(NIL, r->tag, width(p), width(p1)));
554771Speter 		    if (isa(p, "t") && isa(p1, "t")) {
555771Speter 			    if (p != p1) {
556771Speter 				    error("Set types of operands of %s must be identical", opname);
55715931Smckusick 				    return (NLNIL);
558771Speter 			    }
55915931Smckusick 			    (void) gen(TSET, r->tag, width(p), 0);
560771Speter 			    return (p);
561771Speter 		    }
562771Speter #		endif OBJ
563771Speter #		ifdef PC
564771Speter 			/*
565771Speter 			 * the second pass can't do
566771Speter 			 *	long op double  or  double op long
56716273Speter 			 * so we have to know the type of both operands.
56816273Speter 			 * also, see the note for obj above on determining
56916273Speter 			 * the type of empty sets.
570771Speter 			 */
571771Speter 		    codeoff();
57216273Speter 		    p1 = rvalue(r->expr_node.rhs, NLNIL, RREQ);
573771Speter 		    codeon();
574771Speter 		    if ( isa( p1 , "id" ) ) {
57515931Smckusick 			p = rvalue( r->expr_node.lhs , contype , RREQ );
57615937Smckusick 			if ( ( p == NLNIL ) || ( p1 == NLNIL ) ) {
57715931Smckusick 			    return NLNIL;
578771Speter 			}
57915931Smckusick 			tuac(p, p1, &rettype, (int *) (&ctype));
58015931Smckusick 			p1 = rvalue( r->expr_node.rhs , contype , RREQ );
58115931Smckusick 			tuac(p1, p, &rettype, (int *) (&ctype));
582771Speter 			if ( isa( p , "id" ) ) {
58315931Smckusick 			    putop( (int) mathop[r->tag - T_MULT], (int) ctype);
584771Speter 			    return rettype;
585771Speter 			}
586771Speter 		    }
587771Speter 		    if ( isa( p1 , "t" ) ) {
58818468Sralph 			putleaf( PCC_ICON , 0 , 0
58918468Sralph 			    , PCCM_ADDTYPE( PCCM_ADDTYPE( PCCTM_PTR | PCCT_STRTY , PCCTM_FTN )
59018468Sralph 					, PCCTM_PTR )
59115931Smckusick 			    , setop[ r->tag - T_MULT ] );
59216273Speter 			codeoff();
59316273Speter 			contype = rvalue( r->expr_node.lhs, p1 , LREQ );
59416273Speter 			codeon();
59515937Smckusick 			if ( contype == NLNIL ) {
59615931Smckusick 			    return NLNIL;
5971555Speter 			}
5981555Speter 			    /*
5991555Speter 			     *	allocate a temporary and use it
6001555Speter 			     */
6013834Speter 			tempnlp = tmpalloc(lwidth(contype), contype, NOREG);
60215931Smckusick 			putLV((char *) 0 , cbn , tempnlp -> value[ NL_OFFS ] ,
60318468Sralph 				tempnlp -> extra_flags , PCCTM_PTR|PCCT_STRTY );
60415931Smckusick 			p = rvalue( r->expr_node.lhs , contype , LREQ );
605771Speter 			if ( isa( p , "t" ) ) {
60618468Sralph 			    putop( PCC_CM , PCCT_INT );
60715937Smckusick 			    if ( p == NLNIL || p1 == NLNIL ) {
60815931Smckusick 				return NLNIL;
609771Speter 			    }
61015931Smckusick 			    p1 = rvalue( r->expr_node.rhs , p , LREQ );
611771Speter 			    if ( p != p1 ) {
612771Speter 				error("Set types of operands of %s must be identical", opname);
61315931Smckusick 				return NLNIL;
614771Speter 			    }
61518468Sralph 			    putop( PCC_CM , PCCT_INT );
61618468Sralph 			    putleaf( PCC_ICON , (int) (lwidth(p1)) / sizeof( long ) , 0
61718468Sralph 				    , PCCT_INT , (char *) 0 );
61818468Sralph 			    putop( PCC_CM , PCCT_INT );
61918468Sralph 			    putop( PCC_CALL , PCCTM_PTR | PCCT_STRTY );
620771Speter 			    return p;
621771Speter 			}
622771Speter 		    }
623771Speter 		    if ( isnta( p1 , "idt" ) ) {
624771Speter 			    /*
625771Speter 			     *	find type of left operand for error message.
626771Speter 			     */
62715931Smckusick 			p = rvalue( r->expr_node.lhs , contype , RREQ );
628771Speter 		    }
629771Speter 			/*
630771Speter 			 *	don't give spurious error messages.
631771Speter 			 */
63215937Smckusick 		    if ( p == NLNIL || p1 == NLNIL ) {
63315931Smckusick 			return NLNIL;
634771Speter 		    }
635771Speter #		endif PC
636771Speter 		if (isnta(p, "idt")) {
637771Speter 			error("Left operand of %s must be integer, real or set, not %s", opname, nameof(p));
63815931Smckusick 			return (NLNIL);
639771Speter 		}
640771Speter 		if (isnta(p1, "idt")) {
641771Speter 			error("Right operand of %s must be integer, real or set, not %s", opname, nameof(p1));
64215931Smckusick 			return (NLNIL);
643771Speter 		}
644771Speter 		error("Cannot mix sets with integers and reals as operands of %s", opname);
64515931Smckusick 		return (NLNIL);
646771Speter 
647771Speter 	case T_MOD:
648771Speter 	case T_DIV:
64915931Smckusick 		p = rvalue(r->expr_node.lhs, NLNIL , RREQ );
65010364Smckusick #		ifdef PC
65118468Sralph 		    sconv(p2type(p), PCCT_INT);
65210364Smckusick #		endif PC
65315931Smckusick 		p1 = rvalue(r->expr_node.rhs, NLNIL , RREQ );
65410364Smckusick #		ifdef PC
65518468Sralph 		    sconv(p2type(p1), PCCT_INT);
65610364Smckusick #		endif PC
65715937Smckusick 		if (p == NLNIL || p1 == NLNIL)
65815931Smckusick 			return (NLNIL);
659771Speter 		if (isnta(p, "i")) {
660771Speter 			error("Left operand of %s must be integer, not %s", opname, nameof(p));
66115931Smckusick 			return (NLNIL);
662771Speter 		}
663771Speter 		if (isnta(p1, "i")) {
664771Speter 			error("Right operand of %s must be integer, not %s", opname, nameof(p1));
66515931Smckusick 			return (NLNIL);
666771Speter 		}
667771Speter #		ifdef OBJ
66815931Smckusick 		    return (gen(NIL, r->tag, width(p), width(p1)));
669771Speter #		endif OBJ
670771Speter #		ifdef PC
67118468Sralph 		    putop( r->tag == T_DIV ? PCC_DIV : PCC_MOD , PCCT_INT );
672771Speter 		    return ( nl + T4INT );
673771Speter #		endif PC
674771Speter 
675771Speter 	case T_EQ:
676771Speter 	case T_NE:
677771Speter 	case T_LT:
678771Speter 	case T_GT:
679771Speter 	case T_LE:
680771Speter 	case T_GE:
681771Speter 		/*
682771Speter 		 * Since there can be no, a priori, knowledge
683771Speter 		 * of the context type should a constant string
684771Speter 		 * or set arise, we must poke around to find such
685771Speter 		 * a type if possible.  Since constant strings can
686771Speter 		 * always masquerade as identifiers, this is always
687771Speter 		 * necessary.
68816273Speter 		 * see the note in the obj section of case T_MULT above
68916273Speter 		 * for the determination of the base type of empty sets.
690771Speter 		 */
691771Speter 		codeoff();
69215931Smckusick 		p1 = rvalue(r->expr_node.rhs, NLNIL , RREQ );
693771Speter 		codeon();
69415931Smckusick 		if (p1 == NLNIL)
69515931Smckusick 			return (NLNIL);
696771Speter 		contype = p1;
697771Speter #		ifdef OBJ
6981555Speter 		    if (p1->class == STR) {
699771Speter 			    /*
700771Speter 			     * For constant strings we want
701771Speter 			     * the longest type so as to be
702771Speter 			     * able to do padding (more importantly
703771Speter 			     * avoiding truncation). For clarity,
704771Speter 			     * we get this length here.
705771Speter 			     */
706771Speter 			    codeoff();
70715931Smckusick 			    p = rvalue(r->expr_node.lhs, NLNIL , RREQ );
708771Speter 			    codeon();
70915931Smckusick 			    if (p == NLNIL)
71015931Smckusick 				    return (NLNIL);
7111555Speter 			    if (width(p) > width(p1))
712771Speter 				    contype = p;
713771Speter 		    }
71416273Speter 		    if (isa(p1, "t")) {
71516273Speter 			codeoff();
71616273Speter 			contype = rvalue(r->expr_node.lhs, p1, RREQ);
71716273Speter 			codeon();
71816273Speter 			if (contype == NLNIL) {
71916273Speter 			    return NLNIL;
72016273Speter 			}
72116273Speter 		    }
722771Speter 		    /*
723771Speter 		     * Now we generate code for
724771Speter 		     * the operands of the relational
725771Speter 		     * operation.
726771Speter 		     */
72715931Smckusick 		    p = rvalue(r->expr_node.lhs, contype , RREQ );
72815931Smckusick 		    if (p == NLNIL)
72915931Smckusick 			    return (NLNIL);
73015931Smckusick 		    p1 = rvalue(r->expr_node.rhs, p , RREQ );
73115931Smckusick 		    if (p1 == NLNIL)
73215931Smckusick 			    return (NLNIL);
733771Speter #		endif OBJ
734771Speter #		ifdef PC
735771Speter 		    c1 = classify( p1 );
736771Speter 		    if ( c1 == TSET || c1 == TSTR || c1 == TREC ) {
73718468Sralph 			putleaf( PCC_ICON , 0 , 0
73818468Sralph 				, PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR )
73915931Smckusick 				, c1 == TSET  ? relts[ r->tag - T_EQ ]
74015931Smckusick 					      : relss[ r->tag - T_EQ ] );
741771Speter 			    /*
742771Speter 			     *	for [] and strings, comparisons are done on
743771Speter 			     *	the maximum width of the two sides.
744771Speter 			     *	for other sets, we have to ask the left side
745771Speter 			     *	what type it is based on the type of the right.
746771Speter 			     *	(this matters for intsets).
747771Speter 			     */
7481555Speter 			if ( c1 == TSTR ) {
749771Speter 			    codeoff();
75015931Smckusick 			    p = rvalue( r->expr_node.lhs , NLNIL , LREQ );
751771Speter 			    codeon();
75215931Smckusick 			    if ( p == NLNIL ) {
75315931Smckusick 				return NLNIL;
7541555Speter 			    }
7551555Speter 			    if ( lwidth( p ) > lwidth( p1 ) ) {
756771Speter 				contype = p;
757771Speter 			    }
7581555Speter 			} else if ( c1 == TSET ) {
75915937Smckusick 			    codeoff();
76016273Speter 			    contype = rvalue(r->expr_node.lhs, p1, LREQ);
76115937Smckusick 			    codeon();
76216273Speter 			    if (contype == NLNIL) {
76315937Smckusick 				return NLNIL;
7641555Speter 			    }
7651627Speter 			}
766771Speter 			    /*
767771Speter 			     *	put out the width of the comparison.
768771Speter 			     */
76918468Sralph 			putleaf(PCC_ICON, (int) lwidth(contype), 0, PCCT_INT, (char *) 0);
770771Speter 			    /*
771771Speter 			     *	and the left hand side,
772771Speter 			     *	for sets, strings, records
773771Speter 			     */
77415931Smckusick 			p = rvalue( r->expr_node.lhs , contype , LREQ );
77515931Smckusick 			if ( p == NLNIL ) {
77615931Smckusick 			    return NLNIL;
7775413Speter 			}
77818468Sralph 			putop( PCC_CM , PCCT_INT );
77915931Smckusick 			p1 = rvalue( r->expr_node.rhs , p , LREQ );
78015931Smckusick 			if ( p1 == NLNIL ) {
78115931Smckusick 			    return NLNIL;
7825413Speter 			}
78318468Sralph 			putop( PCC_CM , PCCT_INT );
78418468Sralph 			putop( PCC_CALL , PCCT_INT );
785771Speter 		    } else {
786771Speter 			    /*
787771Speter 			     *	the easy (scalar or error) case
788771Speter 			     */
78915931Smckusick 			p = rvalue( r->expr_node.lhs , contype , RREQ );
79015931Smckusick 			if ( p == NLNIL ) {
79115931Smckusick 			    return NLNIL;
7922056Speter 			}
793771Speter 			    /*
794771Speter 			     * since the second pass can't do
795771Speter 			     *	long op double  or  double op long
796771Speter 			     * we may have to do some coercing.
797771Speter 			     */
79815931Smckusick 			tuac(p, p1, &rettype, (int *) (&ctype));
79915931Smckusick 			p1 = rvalue( r->expr_node.rhs , p , RREQ );
80015931Smckusick 			if ( p1 == NLNIL ) {
80115931Smckusick 			    return NLNIL;
8025413Speter 			}
80315931Smckusick 			tuac(p1, p, &rettype, (int *) (&ctype));
80418468Sralph 			putop((int) relops[ r->tag - T_EQ ] , PCCT_INT );
80518468Sralph 			sconv(PCCT_INT, PCCT_CHAR);
806771Speter 		    }
807771Speter #		endif PC
808771Speter 		c = classify(p);
809771Speter 		c1 = classify(p1);
810771Speter 		if (nocomp(c) || nocomp(c1))
81115931Smckusick 			return (NLNIL);
81215931Smckusick #		ifdef OBJ
81315931Smckusick 		    g = NIL;
81415931Smckusick #		endif
815771Speter 		switch (c) {
816771Speter 			case TBOOL:
817771Speter 			case TCHAR:
818771Speter 				if (c != c1)
819771Speter 					goto clash;
820771Speter 				break;
821771Speter 			case TINT:
822771Speter 			case TDOUBLE:
823771Speter 				if (c1 != TINT && c1 != TDOUBLE)
824771Speter 					goto clash;
825771Speter 				break;
826771Speter 			case TSCAL:
827771Speter 				if (c1 != TSCAL)
828771Speter 					goto clash;
829771Speter 				if (scalar(p) != scalar(p1))
830771Speter 					goto nonident;
831771Speter 				break;
832771Speter 			case TSET:
833771Speter 				if (c1 != TSET)
834771Speter 					goto clash;
8353397Speter 				if ( opt( 's' ) &&
83615931Smckusick 				    ( ( r->tag == T_LT) || (r->tag == T_GT) ) &&
8373397Speter 				    ( line != nssetline ) ) {
8383397Speter 				    nssetline = line;
8393397Speter 				    standard();
8403397Speter 				    error("%s comparison on sets is non-standard" , opname );
8413397Speter 				}
842771Speter 				if (p != p1)
843771Speter 					goto nonident;
84415931Smckusick #				ifdef OBJ
84515931Smckusick 				    g = TSET;
84615931Smckusick #				endif
847771Speter 				break;
848771Speter 			case TREC:
849771Speter 				if ( c1 != TREC ) {
850771Speter 				    goto clash;
851771Speter 				}
852771Speter 				if ( p != p1 ) {
853771Speter 				    goto nonident;
854771Speter 				}
85515931Smckusick 				if (r->tag != T_EQ && r->tag != T_NE) {
856771Speter 					error("%s not allowed on records - only allow = and <>" , opname );
85715931Smckusick 					return (NLNIL);
858771Speter 				}
85915931Smckusick #				ifdef OBJ
86015931Smckusick 				    g = TREC;
86115931Smckusick #				endif
862771Speter 				break;
863771Speter 			case TPTR:
864771Speter 			case TNIL:
865771Speter 				if (c1 != TPTR && c1 != TNIL)
866771Speter 					goto clash;
86715931Smckusick 				if (r->tag != T_EQ && r->tag != T_NE) {
868771Speter 					error("%s not allowed on pointers - only allow = and <>" , opname );
86915931Smckusick 					return (NLNIL);
870771Speter 				}
87115937Smckusick 				if (p != nl+TNIL && p1 != nl+TNIL && p != p1)
87215937Smckusick 					goto nonident;
873771Speter 				break;
874771Speter 			case TSTR:
875771Speter 				if (c1 != TSTR)
876771Speter 					goto clash;
877771Speter 				if (width(p) != width(p1)) {
878771Speter 					error("Strings not same length in %s comparison", opname);
87915931Smckusick 					return (NLNIL);
880771Speter 				}
88115931Smckusick #				ifdef OBJ
88215931Smckusick 				    g = TSTR;
88315931Smckusick #				endif OBJ
884771Speter 				break;
885771Speter 			default:
886771Speter 				panic("rval2");
887771Speter 		}
888771Speter #		ifdef OBJ
88915931Smckusick 		    return (gen(g, r->tag, width(p), width(p1)));
890771Speter #		endif OBJ
891771Speter #		ifdef PC
892771Speter 		    return nl + TBOOL;
893771Speter #		endif PC
894771Speter clash:
895771Speter 		error("%ss and %ss cannot be compared - operator was %s", clnames[c], clnames[c1], opname);
89615931Smckusick 		return (NLNIL);
897771Speter nonident:
898771Speter 		error("%s types must be identical in comparisons - operator was %s", clnames[c1], opname);
89915931Smckusick 		return (NLNIL);
900771Speter 
901771Speter 	case T_IN:
90215931Smckusick 	    rt = r->expr_node.rhs;
903771Speter #	    ifdef OBJ
90415931Smckusick 		if (rt != TR_NIL && rt->tag == T_CSET) {
90515931Smckusick 			(void) precset( rt , NLNIL , &csetd );
906771Speter 			p1 = csetd.csettype;
90715931Smckusick 			if (p1 == NLNIL)
90815931Smckusick 			    return NLNIL;
909771Speter 			postcset( rt, &csetd);
910771Speter 		    } else {
91115931Smckusick 			p1 = stkrval(r->expr_node.rhs, NLNIL , (long) RREQ );
91215931Smckusick 			rt = TR_NIL;
913771Speter 		    }
914771Speter #		endif OBJ
915771Speter #		ifdef PC
91615931Smckusick 		    if (rt != TR_NIL && rt->tag == T_CSET) {
91715931Smckusick 			if ( precset( rt , NLNIL , &csetd ) ) {
91818468Sralph 			    putleaf( PCC_ICON , 0 , 0
91918468Sralph 				    , PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR )
9201555Speter 				    , "_IN" );
921771Speter 			} else {
92218468Sralph 			    putleaf( PCC_ICON , 0 , 0
92318468Sralph 				    , PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR )
924771Speter 				    , "_INCT" );
925771Speter 			}
926771Speter 			p1 = csetd.csettype;
927771Speter 			if (p1 == NIL)
92815931Smckusick 			    return NLNIL;
929771Speter 		    } else {
93018468Sralph 			putleaf( PCC_ICON , 0 , 0
93118468Sralph 				, PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR )
932771Speter 				, "_IN" );
933771Speter 			codeoff();
93415931Smckusick 			p1 = rvalue(r->expr_node.rhs, NLNIL , LREQ );
935771Speter 			codeon();
936771Speter 		    }
937771Speter #		endif PC
93815931Smckusick 		p = stkrval(r->expr_node.lhs, NLNIL , (long) RREQ );
939771Speter 		if (p == NIL || p1 == NIL)
94015931Smckusick 			return (NLNIL);
94115931Smckusick 		if (p1->class != (char) SET) {
942771Speter 			error("Right operand of 'in' must be a set, not %s", nameof(p1));
94315931Smckusick 			return (NLNIL);
944771Speter 		}
94515931Smckusick 		if (incompat(p, p1->type, r->expr_node.lhs)) {
946771Speter 			cerror("Index type clashed with set component type for 'in'");
94715931Smckusick 			return (NLNIL);
948771Speter 		}
949771Speter 		setran(p1->type);
950771Speter #		ifdef OBJ
95115931Smckusick 		    if (rt == TR_NIL || csetd.comptime)
95215931Smckusick 			    (void) put(4, O_IN, width(p1), set.lwrb, set.uprbp);
953771Speter 		    else
95415931Smckusick 			    (void) put(2, O_INCT,
9553078Smckusic 				(int)(3 + csetd.singcnt + 2*csetd.paircnt));
956771Speter #		endif OBJ
957771Speter #		ifdef PC
95815931Smckusick 		    if ( rt == TR_NIL || rt->tag != T_CSET ) {
95918468Sralph 			putleaf( PCC_ICON , set.lwrb , 0 , PCCT_INT , (char *) 0 );
96018468Sralph 			putop( PCC_CM , PCCT_INT );
96118468Sralph 			putleaf( PCC_ICON , set.uprbp , 0 , PCCT_INT , (char *) 0 );
96218468Sralph 			putop( PCC_CM , PCCT_INT );
96315931Smckusick 			p1 = rvalue( r->expr_node.rhs , NLNIL , LREQ );
96415931Smckusick 			if ( p1 == NLNIL ) {
96515931Smckusick 			    return NLNIL;
9665413Speter 			}
96718468Sralph 			putop( PCC_CM , PCCT_INT );
968771Speter 		    } else if ( csetd.comptime ) {
96918468Sralph 			putleaf( PCC_ICON , set.lwrb , 0 , PCCT_INT , (char *) 0 );
97018468Sralph 			putop( PCC_CM , PCCT_INT );
97118468Sralph 			putleaf( PCC_ICON , set.uprbp , 0 , PCCT_INT , (char *) 0 );
97218468Sralph 			putop( PCC_CM , PCCT_INT );
97315931Smckusick 			postcset( r->expr_node.rhs , &csetd );
97418468Sralph 			putop( PCC_CM , PCCT_INT );
975771Speter 		    } else {
97615931Smckusick 			postcset( r->expr_node.rhs , &csetd );
977771Speter 		    }
97818468Sralph 		    putop( PCC_CALL , PCCT_INT );
97918468Sralph 		    sconv(PCCT_INT, PCCT_CHAR);
980771Speter #		endif PC
981771Speter 		return (nl+T1BOOL);
982771Speter 	default:
98315931Smckusick 		if (r->expr_node.lhs == TR_NIL)
98415931Smckusick 			return (NLNIL);
98515931Smckusick 		switch (r->tag) {
986771Speter 		default:
987771Speter 			panic("rval3");
988771Speter 
989771Speter 
990771Speter 		/*
991771Speter 		 * An octal number
992771Speter 		 */
993771Speter 		case T_BINT:
99415931Smckusick 			f.pdouble = a8tol(r->const_node.cptr);
995771Speter 			goto conint;
996771Speter 
997771Speter 		/*
998771Speter 		 * A decimal number
999771Speter 		 */
1000771Speter 		case T_INT:
100115931Smckusick 			f.pdouble = atof(r->const_node.cptr);
1002771Speter conint:
100315931Smckusick 			if (f.pdouble > MAXINT || f.pdouble < MININT) {
1004771Speter 				error("Constant too large for this implementation");
100515931Smckusick 				return (NLNIL);
1006771Speter 			}
100715931Smckusick 			l = f.pdouble;
100810364Smckusick #			ifdef OBJ
100910364Smckusick 			    if (bytes(l, l) <= 2) {
101015931Smckusick 				    (void) put(2, O_CON2, ( short ) l);
101110364Smckusick 				    return (nl+T2INT);
101210364Smckusick 			    }
101315931Smckusick 			    (void) put(2, O_CON4, l);
101410364Smckusick 			    return (nl+T4INT);
1015771Speter #			endif OBJ
1016771Speter #			ifdef PC
101710364Smckusick 			    switch (bytes(l, l)) {
101810364Smckusick 				case 1:
101918468Sralph 				    putleaf(PCC_ICON, (int) l, 0, PCCT_CHAR,
102015931Smckusick 						(char *) 0);
102110364Smckusick 				    return nl+T1INT;
102210364Smckusick 				case 2:
102318468Sralph 				    putleaf(PCC_ICON, (int) l, 0, PCCT_SHORT,
102415931Smckusick 						(char *) 0);
102510364Smckusick 				    return nl+T2INT;
102610364Smckusick 				case 4:
102718468Sralph 				    putleaf(PCC_ICON, (int) l, 0, PCCT_INT,
102815931Smckusick 						(char *) 0);
102910364Smckusick 				    return nl+T4INT;
103010364Smckusick 			    }
1031771Speter #			endif PC
1032771Speter 
1033771Speter 		/*
1034771Speter 		 * A floating point number
1035771Speter 		 */
1036771Speter 		case T_FINT:
1037771Speter #			ifdef OBJ
103815931Smckusick 			    (void) put(2, O_CON8, atof(r->const_node.cptr));
1039771Speter #			endif OBJ
1040771Speter #			ifdef PC
104115931Smckusick 			    putCON8( atof( r->const_node.cptr ) );
1042771Speter #			endif PC
1043771Speter 			return (nl+TDOUBLE);
1044771Speter 
1045771Speter 		/*
1046771Speter 		 * Constant strings.  Note that constant characters
1047771Speter 		 * are constant strings of length one; there is
1048771Speter 		 * no constant string of length one.
1049771Speter 		 */
1050771Speter 		case T_STRNG:
105115931Smckusick 			cp = r->const_node.cptr;
1052771Speter 			if (cp[1] == 0) {
1053771Speter #				ifdef OBJ
105415931Smckusick 				    (void) put(2, O_CONC, cp[0]);
1055771Speter #				endif OBJ
1056771Speter #				ifdef PC
105718468Sralph 				    putleaf( PCC_ICON , cp[0] , 0 , PCCT_CHAR ,
105815931Smckusick 						(char *) 0 );
1059771Speter #				endif PC
1060771Speter 				return (nl+T1CHAR);
1061771Speter 			}
1062771Speter 			goto cstrng;
1063771Speter 		}
1064771Speter 
1065771Speter 	}
1066771Speter }
1067771Speter 
1068771Speter /*
1069771Speter  * Can a class appear
1070771Speter  * in a comparison ?
1071771Speter  */
1072771Speter nocomp(c)
1073771Speter 	int c;
1074771Speter {
1075771Speter 
1076771Speter 	switch (c) {
1077771Speter 		case TREC:
10781627Speter 			if ( line != reccompline ) {
10791627Speter 			    reccompline = line;
10801627Speter 			    warning();
10811627Speter 			    if ( opt( 's' ) ) {
10821627Speter 				standard();
10831627Speter 			    }
1084771Speter 			    error("record comparison is non-standard");
1085771Speter 			}
1086771Speter 			break;
1087771Speter 		case TFILE:
1088771Speter 		case TARY:
1089771Speter 			error("%ss may not participate in comparisons", clnames[c]);
1090771Speter 			return (1);
1091771Speter 	}
1092771Speter 	return (NIL);
1093771Speter }
1094771Speter 
1095771Speter     /*
1096771Speter      *	this is sort of like gconst, except it works on expression trees
1097771Speter      *	rather than declaration trees, and doesn't give error messages for
1098771Speter      *	non-constant things.
1099771Speter      *	as a side effect this fills in the con structure that gconst uses.
1100771Speter      *	this returns TRUE or FALSE.
1101771Speter      */
110215931Smckusick 
110315931Smckusick bool
1104771Speter constval(r)
110515931Smckusick 	register struct tnode *r;
1106771Speter {
1107771Speter 	register struct nl *np;
110815931Smckusick 	register struct tnode *cn;
1109771Speter 	char *cp;
1110771Speter 	int negd, sgnd;
1111771Speter 	long ci;
1112771Speter 
1113771Speter 	con.ctype = NIL;
1114771Speter 	cn = r;
1115771Speter 	negd = sgnd = 0;
1116771Speter loop:
1117771Speter 	    /*
1118771Speter 	     *	cn[2] is nil if error recovery generated a T_STRNG
1119771Speter 	     */
112015931Smckusick 	if (cn == TR_NIL || cn->expr_node.lhs == TR_NIL)
1121771Speter 		return FALSE;
112215931Smckusick 	switch (cn->tag) {
1123771Speter 		default:
1124771Speter 			return FALSE;
1125771Speter 		case T_MINUS:
1126771Speter 			negd = 1 - negd;
1127771Speter 			/* and fall through */
1128771Speter 		case T_PLUS:
1129771Speter 			sgnd++;
113015931Smckusick 			cn = cn->un_expr.expr;
1131771Speter 			goto loop;
1132771Speter 		case T_NIL:
1133771Speter 			con.cpval = NIL;
1134771Speter 			con.cival = 0;
1135771Speter 			con.crval = con.cival;
1136771Speter 			con.ctype = nl + TNIL;
1137771Speter 			break;
1138771Speter 		case T_VAR:
113915931Smckusick 			np = lookup(cn->var_node.cptr);
114015931Smckusick 			if (np == NLNIL || np->class != CONST) {
1141771Speter 				return FALSE;
1142771Speter 			}
114315931Smckusick 			if ( cn->var_node.qual != TR_NIL ) {
1144771Speter 				return FALSE;
1145771Speter 			}
1146771Speter 			con.ctype = np->type;
1147771Speter 			switch (classify(np->type)) {
1148771Speter 				case TINT:
1149771Speter 					con.crval = np->range[0];
1150771Speter 					break;
1151771Speter 				case TDOUBLE:
1152771Speter 					con.crval = np->real;
1153771Speter 					break;
1154771Speter 				case TBOOL:
1155771Speter 				case TCHAR:
1156771Speter 				case TSCAL:
1157771Speter 					con.cival = np->value[0];
1158771Speter 					con.crval = con.cival;
1159771Speter 					break;
1160771Speter 				case TSTR:
116115931Smckusick 					con.cpval = (char *) np->ptr[0];
1162771Speter 					break;
1163771Speter 				default:
1164771Speter 					con.ctype = NIL;
1165771Speter 					return FALSE;
1166771Speter 			}
1167771Speter 			break;
1168771Speter 		case T_BINT:
116915931Smckusick 			con.crval = a8tol(cn->const_node.cptr);
1170771Speter 			goto restcon;
1171771Speter 		case T_INT:
117215931Smckusick 			con.crval = atof(cn->const_node.cptr);
1173771Speter 			if (con.crval > MAXINT || con.crval < MININT) {
1174771Speter 				derror("Constant too large for this implementation");
1175771Speter 				con.crval = 0;
1176771Speter 			}
1177771Speter restcon:
1178771Speter 			ci = con.crval;
1179771Speter #ifndef PI0
1180771Speter 			if (bytes(ci, ci) <= 2)
1181771Speter 				con.ctype = nl+T2INT;
1182771Speter 			else
1183771Speter #endif
1184771Speter 				con.ctype = nl+T4INT;
1185771Speter 			break;
1186771Speter 		case T_FINT:
1187771Speter 			con.ctype = nl+TDOUBLE;
118815931Smckusick 			con.crval = atof(cn->const_node.cptr);
1189771Speter 			break;
1190771Speter 		case T_STRNG:
119115931Smckusick 			cp = cn->const_node.cptr;
1192771Speter 			if (cp[1] == 0) {
1193771Speter 				con.ctype = nl+T1CHAR;
1194771Speter 				con.cival = cp[0];
1195771Speter 				con.crval = con.cival;
1196771Speter 				break;
1197771Speter 			}
1198771Speter 			con.ctype = nl+TSTR;
1199771Speter 			con.cpval = cp;
1200771Speter 			break;
1201771Speter 	}
1202771Speter 	if (sgnd) {
1203771Speter 		if (isnta(con.ctype, "id")) {
1204771Speter 			derror("%s constants cannot be signed", nameof(con.ctype));
1205771Speter 			return FALSE;
1206771Speter 		} else if (negd)
1207771Speter 			con.crval = -con.crval;
1208771Speter 	}
1209771Speter 	return TRUE;
1210771Speter }
1211