xref: /csrg-svn/usr.bin/pascal/src/rval.c (revision 18468)
1771Speter /* Copyright (c) 1979 Regents of the University of California */
2771Speter 
315945Speter #ifndef lint
4*18468Sralph static char sccsid[] = "@(#)rval.c 2.3 03/20/85";
515931Smckusick #endif
6771Speter 
7771Speter #include "whoami.h"
8771Speter #include "0.h"
9771Speter #include "tree.h"
10771Speter #include "opcode.h"
11771Speter #include "objfmt.h"
12771Speter #ifdef PC
13771Speter #   include	"pc.h"
14*18468Sralph #   include <pcc.h>
15771Speter #endif PC
1611328Speter #include "tmps.h"
1715931Smckusick #include "tree_ty.h"
18771Speter 
19771Speter extern	char *opnames[];
20771Speter 
211627Speter     /* line number of the last record comparison warning */
221627Speter short reccompline = 0;
233397Speter     /* line number of the last non-standard set comparison */
243397Speter short nssetline = 0;
251627Speter 
26771Speter #ifdef PC
27771Speter     char	*relts[] =  {
28771Speter 				"_RELEQ" , "_RELNE" ,
29771Speter 				"_RELTLT" , "_RELTGT" ,
30771Speter 				"_RELTLE" , "_RELTGE"
31771Speter 			    };
32771Speter     char	*relss[] =  {
33771Speter 				"_RELEQ" , "_RELNE" ,
34771Speter 				"_RELSLT" , "_RELSGT" ,
35771Speter 				"_RELSLE" , "_RELSGE"
36771Speter 			    };
37771Speter     long	relops[] =  {
38*18468Sralph 				PCC_EQ , PCC_NE ,
39*18468Sralph 				PCC_LT , PCC_GT ,
40*18468Sralph 				PCC_LE , PCC_GE
41771Speter 			    };
42*18468Sralph     long	mathop[] =  {	PCC_MUL , PCC_PLUS , PCC_MINUS };
43771Speter     char	*setop[] =  {	"_MULT" , "_ADDT" , "_SUBT" };
44771Speter #endif PC
45771Speter /*
46771Speter  * Rvalue - an expression.
47771Speter  *
48771Speter  * Contype is the type that the caller would prefer, nand is important
4916273Speter  * if constant strings are involved, because of string padding.
50771Speter  * required is a flag whether an lvalue or an rvalue is required.
51771Speter  * only VARs and structured things can have gt their lvalue this way.
52771Speter  */
5315931Smckusick /*ARGSUSED*/
54771Speter struct nl *
55771Speter rvalue(r, contype , required )
5615931Smckusick 	struct tnode *r;
57771Speter 	struct nl *contype;
58771Speter 	int	required;
59771Speter {
60771Speter 	register struct nl *p, *p1;
61771Speter 	register struct nl *q;
6215931Smckusick 	int c, c1, w;
6315931Smckusick #ifdef OBJ
6415931Smckusick 	int g;
6515931Smckusick #endif
6615931Smckusick 	struct tnode *rt;
67771Speter 	char *cp, *cp1, *opname;
68771Speter 	long l;
6915931Smckusick 	union
7015931Smckusick 	{
7115931Smckusick 	    long plong[2];
7215931Smckusick 	    double pdouble;
7315931Smckusick 	}f;
74771Speter 	extern int	flagwas;
75771Speter 	struct csetstr	csetd;
76771Speter #	ifdef PC
77771Speter 	    struct nl	*rettype;
78771Speter 	    long	ctype;
793834Speter 	    struct nl	*tempnlp;
80771Speter #	endif PC
81771Speter 
8215931Smckusick 	if (r == TR_NIL)
8315931Smckusick 		return (NLNIL);
84771Speter 	if (nowexp(r))
8515931Smckusick 		return (NLNIL);
86771Speter 	/*
87771Speter 	 * Pick up the name of the operation
88771Speter 	 * for future error messages.
89771Speter 	 */
9015931Smckusick 	if (r->tag <= T_IN)
9115931Smckusick 		opname = opnames[r->tag];
92771Speter 
93771Speter 	/*
94771Speter 	 * The root of the tree tells us what sort of expression we have.
95771Speter 	 */
9615931Smckusick 	switch (r->tag) {
97771Speter 
98771Speter 	/*
99771Speter 	 * The constant nil
100771Speter 	 */
101771Speter 	case T_NIL:
102771Speter #		ifdef OBJ
10315931Smckusick 		    (void) put(2, O_CON2, 0);
104771Speter #		endif OBJ
105771Speter #		ifdef PC
106*18468Sralph 		    putleaf( PCC_ICON , 0 , 0 , PCCTM_PTR|PCCT_UNDEF , (char *) 0 );
107771Speter #		endif PC
108771Speter 		return (nl+TNIL);
109771Speter 
110771Speter 	/*
111771Speter 	 * Function call with arguments.
112771Speter 	 */
113771Speter 	case T_FCALL:
114771Speter #	    ifdef OBJ
115771Speter 		return (funccod(r));
116771Speter #	    endif OBJ
117771Speter #	    ifdef PC
118771Speter 		return (pcfunccod( r ));
119771Speter #	    endif PC
120771Speter 
121771Speter 	case T_VAR:
12215931Smckusick 		p = lookup(r->var_node.cptr);
12315931Smckusick 		if (p == NLNIL || p->class == BADUSE)
12415931Smckusick 			return (NLNIL);
125771Speter 		switch (p->class) {
126771Speter 		    case VAR:
127771Speter 			    /*
128771Speter 			     * If a variable is
129771Speter 			     * qualified then get
130771Speter 			     * the rvalue by a
131771Speter 			     * lvalue and an ind.
132771Speter 			     */
13315931Smckusick 			    if (r->var_node.qual != TR_NIL)
134771Speter 				    goto ind;
135771Speter 			    q = p->type;
136771Speter 			    if (q == NIL)
13715931Smckusick 				    return (NLNIL);
138771Speter #			    ifdef OBJ
139771Speter 				w = width(q);
140771Speter 				switch (w) {
141771Speter 				    case 8:
14215931Smckusick 					(void) put(2, O_RV8 | bn << 8+INDX,
1433078Smckusic 						(int)p->value[0]);
144771Speter 					break;
145771Speter 				    case 4:
14615931Smckusick 					(void) put(2, O_RV4 | bn << 8+INDX,
1473078Smckusic 						(int)p->value[0]);
148771Speter 					break;
149771Speter 				    case 2:
15015931Smckusick 					(void) put(2, O_RV2 | bn << 8+INDX,
1513078Smckusic 						(int)p->value[0]);
152771Speter 					break;
153771Speter 				    case 1:
15415931Smckusick 					(void) put(2, O_RV1 | bn << 8+INDX,
1553078Smckusic 						(int)p->value[0]);
156771Speter 					break;
157771Speter 				    default:
15815931Smckusick 					(void) put(3, O_RV | bn << 8+INDX,
1593078Smckusic 						(int)p->value[0], w);
160771Speter 				}
161771Speter #			   endif OBJ
162771Speter #			   ifdef PC
163771Speter 				if ( required == RREQ ) {
1643834Speter 				    putRV( p -> symbol , bn , p -> value[0] ,
1653834Speter 					    p -> extra_flags , p2type( q ) );
166771Speter 				} else {
1673834Speter 				    putLV( p -> symbol , bn , p -> value[0] ,
1683834Speter 					    p -> extra_flags , p2type( q ) );
169771Speter 				}
170771Speter #			   endif PC
171771Speter 			   return (q);
172771Speter 
173771Speter 		    case WITHPTR:
174771Speter 		    case REF:
175771Speter 			    /*
176771Speter 			     * A lvalue for these
177771Speter 			     * is actually what one
178771Speter 			     * might consider a rvalue.
179771Speter 			     */
180771Speter ind:
181771Speter 			    q = lvalue(r, NOFLAGS , LREQ );
182771Speter 			    if (q == NIL)
18315931Smckusick 				    return (NLNIL);
184771Speter #			    ifdef OBJ
185771Speter 				w = width(q);
186771Speter 				switch (w) {
187771Speter 				    case 8:
18815931Smckusick 					    (void) put(1, O_IND8);
189771Speter 					    break;
190771Speter 				    case 4:
19115931Smckusick 					    (void) put(1, O_IND4);
192771Speter 					    break;
193771Speter 				    case 2:
19415931Smckusick 					    (void) put(1, O_IND2);
195771Speter 					    break;
196771Speter 				    case 1:
19715931Smckusick 					    (void) put(1, O_IND1);
198771Speter 					    break;
199771Speter 				    default:
20015931Smckusick 					    (void) put(2, O_IND, w);
201771Speter 				}
202771Speter #			    endif OBJ
203771Speter #			    ifdef PC
204771Speter 				if ( required == RREQ ) {
205*18468Sralph 				    putop( PCCOM_UNARY PCC_MUL , p2type( q ) );
206771Speter 				}
207771Speter #			    endif PC
208771Speter 			    return (q);
209771Speter 
210771Speter 		    case CONST:
21115931Smckusick 			    if (r->var_node.qual != TR_NIL) {
21215931Smckusick 				error("%s is a constant and cannot be qualified", r->var_node.cptr);
21315931Smckusick 				return (NLNIL);
214771Speter 			    }
215771Speter 			    q = p->type;
21615931Smckusick 			    if (q == NLNIL)
21715931Smckusick 				    return (NLNIL);
218771Speter 			    if (q == nl+TSTR) {
219771Speter 				    /*
220771Speter 				     * Find the size of the string
221771Speter 				     * constant if needed.
222771Speter 				     */
22315931Smckusick 				    cp = (char *) p->ptr[0];
224771Speter cstrng:
225771Speter 				    cp1 = cp;
226771Speter 				    for (c = 0; *cp++; c++)
227771Speter 					    continue;
2283078Smckusic 				    w = c;
229771Speter 				    if (contype != NIL && !opt('s')) {
230771Speter 					    if (width(contype) < c && classify(contype) == TSTR) {
231771Speter 						    error("Constant string too long");
23215931Smckusick 						    return (NLNIL);
233771Speter 					    }
2343078Smckusic 					    w = width(contype);
235771Speter 				    }
236771Speter #				    ifdef OBJ
23715931Smckusick 					(void) put(2, O_CONG, w);
2383078Smckusic 					putstr(cp1, w - c);
239771Speter #				    endif OBJ
240771Speter #				    ifdef PC
2413155Smckusic 					putCONG( cp1 , w , required );
242771Speter #				    endif PC
243771Speter 				    /*
244771Speter 				     * Define the string temporarily
245771Speter 				     * so later people can know its
246771Speter 				     * width.
247771Speter 				     * cleaned out by stat.
248771Speter 				     */
24915931Smckusick 				    q = defnl((char *) 0, STR, NLNIL, w);
250771Speter 				    q->type = q;
251771Speter 				    return (q);
252771Speter 			    }
253771Speter 			    if (q == nl+T1CHAR) {
254771Speter #				    ifdef OBJ
25515931Smckusick 					(void) put(2, O_CONC, (int)p->value[0]);
256771Speter #				    endif OBJ
257771Speter #				    ifdef PC
258*18468Sralph 					putleaf( PCC_ICON , p -> value[0] , 0
259*18468Sralph 						, PCCT_CHAR , (char *) 0 );
260771Speter #				    endif PC
261771Speter 				    return (q);
262771Speter 			    }
263771Speter 			    /*
264771Speter 			     * Every other kind of constant here
265771Speter 			     */
266771Speter 			    switch (width(q)) {
267771Speter 			    case 8:
268771Speter #ifndef DEBUG
269771Speter #				    ifdef OBJ
27015931Smckusick 					(void) put(2, O_CON8, p->real);
271771Speter #				    endif OBJ
272771Speter #				    ifdef PC
273771Speter 					putCON8( p -> real );
274771Speter #				    endif PC
275771Speter #else
276771Speter 				    if (hp21mx) {
27715931Smckusick 					    f.pdouble = p->real;
27815931Smckusick 					    conv((int *) (&f.pdouble));
27915931Smckusick 					    l = f.plong[1];
28015931Smckusick 					    (void) put(2, O_CON4, l);
281771Speter 				    } else
282771Speter #					    ifdef OBJ
28315931Smckusick 						(void) put(2, O_CON8, p->real);
284771Speter #					    endif OBJ
285771Speter #					    ifdef PC
286771Speter 						putCON8( p -> real );
287771Speter #					    endif PC
288771Speter #endif
289771Speter 				    break;
290771Speter 			    case 4:
291771Speter #				    ifdef OBJ
29215931Smckusick 					(void) put(2, O_CON4, p->range[0]);
293771Speter #				    endif OBJ
294771Speter #				    ifdef PC
295*18468Sralph 					putleaf( PCC_ICON , (int) p->range[0] , 0
296*18468Sralph 						, PCCT_INT , (char *) 0 );
297771Speter #				    endif PC
298771Speter 				    break;
299771Speter 			    case 2:
300771Speter #				    ifdef OBJ
30115931Smckusick 					(void) put(2, O_CON2, (short)p->range[0]);
302771Speter #				    endif OBJ
303771Speter #				    ifdef PC
304*18468Sralph 					putleaf( PCC_ICON , (short) p -> range[0]
305*18468Sralph 						, 0 , PCCT_SHORT , (char *) 0 );
306771Speter #				    endif PC
307771Speter 				    break;
308771Speter 			    case 1:
309771Speter #				    ifdef OBJ
31015931Smckusick 					(void) put(2, O_CON1, p->value[0]);
311771Speter #				    endif OBJ
312771Speter #				    ifdef PC
313*18468Sralph 					putleaf( PCC_ICON , p -> value[0] , 0
314*18468Sralph 						, PCCT_CHAR , (char *) 0 );
315771Speter #				    endif PC
316771Speter 				    break;
317771Speter 			    default:
318771Speter 				    panic("rval");
319771Speter 			    }
320771Speter 			    return (q);
321771Speter 
322771Speter 		    case FUNC:
3231200Speter 		    case FFUNC:
324771Speter 			    /*
325771Speter 			     * Function call with no arguments.
326771Speter 			     */
32715931Smckusick 			    if (r->var_node.qual != TR_NIL) {
328771Speter 				    error("Can't qualify a function result value");
32915931Smckusick 				    return (NLNIL);
330771Speter 			    }
331771Speter #			    ifdef OBJ
33215931Smckusick 				return (funccod(r));
333771Speter #			    endif OBJ
334771Speter #			    ifdef PC
335771Speter 				return (pcfunccod( r ));
336771Speter #			    endif PC
337771Speter 
338771Speter 		    case TYPE:
339771Speter 			    error("Type names (e.g. %s) allowed only in declarations", p->symbol);
34015931Smckusick 			    return (NLNIL);
341771Speter 
342771Speter 		    case PROC:
3431200Speter 		    case FPROC:
344771Speter 			    error("Procedure %s found where expression required", p->symbol);
34515931Smckusick 			    return (NLNIL);
346771Speter 		    default:
347771Speter 			    panic("rvid");
348771Speter 		}
349771Speter 	/*
350771Speter 	 * Constant sets
351771Speter 	 */
352771Speter 	case T_CSET:
353771Speter #		ifdef OBJ
354771Speter 		    if ( precset( r , contype , &csetd ) ) {
355771Speter 			if ( csetd.csettype == NIL ) {
35615931Smckusick 			    return (NLNIL);
357771Speter 			}
358771Speter 			postcset( r , &csetd );
359771Speter 		    } else {
36015931Smckusick 			(void) put( 2, O_PUSH, -lwidth(csetd.csettype));
361771Speter 			postcset( r , &csetd );
362771Speter 			setran( ( csetd.csettype ) -> type );
36315931Smckusick 			(void) put( 2, O_CON24, set.uprbp);
36415931Smckusick 			(void) put( 2, O_CON24, set.lwrb);
36515931Smckusick 			(void) put( 2, O_CTTOT,
3663078Smckusic 				(int)(4 + csetd.singcnt + 2 * csetd.paircnt));
367771Speter 		    }
368771Speter 		    return csetd.csettype;
369771Speter #		endif OBJ
370771Speter #		ifdef PC
371771Speter 		    if ( precset( r , contype , &csetd ) ) {
372771Speter 			if ( csetd.csettype == NIL ) {
37315931Smckusick 			    return (NLNIL);
374771Speter 			}
375771Speter 			postcset( r , &csetd );
376771Speter 		    } else {
377*18468Sralph 			putleaf( PCC_ICON , 0 , 0
378*18468Sralph 				, PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR )
379771Speter 				, "_CTTOT" );
380771Speter 			/*
381771Speter 			 *	allocate a temporary and use it
382771Speter 			 */
3833834Speter 			tempnlp = tmpalloc(lwidth(csetd.csettype),
3843227Smckusic 				csetd.csettype, NOREG);
38515931Smckusick 			putLV( (char *) 0 , cbn , tempnlp -> value[ NL_OFFS ] ,
386*18468Sralph 				tempnlp -> extra_flags , PCCTM_PTR|PCCT_STRTY );
387771Speter 			setran( ( csetd.csettype ) -> type );
388*18468Sralph 			putleaf( PCC_ICON , set.lwrb , 0 , PCCT_INT , (char *) 0 );
389*18468Sralph 			putop( PCC_CM , PCCT_INT );
390*18468Sralph 			putleaf( PCC_ICON , set.uprbp , 0 , PCCT_INT , (char *) 0 );
391*18468Sralph 			putop( PCC_CM , PCCT_INT );
392771Speter 			postcset( r , &csetd );
393*18468Sralph 			putop( PCC_CALL , PCCT_INT );
394771Speter 		    }
395771Speter 		    return csetd.csettype;
396771Speter #		endif PC
397771Speter 
398771Speter 	/*
399771Speter 	 * Unary plus and minus
400771Speter 	 */
401771Speter 	case T_PLUS:
402771Speter 	case T_MINUS:
40315931Smckusick 		q = rvalue(r->un_expr.expr, NLNIL , RREQ );
40415931Smckusick 		if (q == NLNIL)
40515931Smckusick 			return (NLNIL);
406771Speter 		if (isnta(q, "id")) {
407771Speter 			error("Operand of %s must be integer or real, not %s", opname, nameof(q));
40815931Smckusick 			return (NLNIL);
409771Speter 		}
41015931Smckusick 		if (r->tag == T_MINUS) {
411771Speter #		    ifdef OBJ
41215931Smckusick 			(void) put(1, O_NEG2 + (width(q) >> 2));
41310670Speter 			return (isa(q, "d") ? q : nl+T4INT);
414771Speter #		    endif OBJ
415771Speter #		    ifdef PC
41610670Speter 			if (isa(q, "i")) {
417*18468Sralph 			    sconv(p2type(q), PCCT_INT);
418*18468Sralph 			    putop( PCCOM_UNARY PCC_MINUS, PCCT_INT);
41910670Speter 			    return nl+T4INT;
42010670Speter 			}
421*18468Sralph 			putop( PCCOM_UNARY PCC_MINUS, PCCT_DOUBLE);
42210670Speter 			return nl+TDOUBLE;
423771Speter #		    endif PC
424771Speter 		}
425771Speter 		return (q);
426771Speter 
427771Speter 	case T_NOT:
42815931Smckusick 		q = rvalue(r->un_expr.expr, NLNIL , RREQ );
42915931Smckusick 		if (q == NLNIL)
43015931Smckusick 			return (NLNIL);
431771Speter 		if (isnta(q, "b")) {
432771Speter 			error("not must operate on a Boolean, not %s", nameof(q));
43315931Smckusick 			return (NLNIL);
434771Speter 		}
435771Speter #		ifdef OBJ
43615931Smckusick 		    (void) put(1, O_NOT);
437771Speter #		endif OBJ
438771Speter #		ifdef PC
439*18468Sralph 		    sconv(p2type(q), PCCT_INT);
440*18468Sralph 		    putop( PCC_NOT , PCCT_INT);
441*18468Sralph 		    sconv(PCCT_INT, p2type(q));
442771Speter #		endif PC
443771Speter 		return (nl+T1BOOL);
444771Speter 
445771Speter 	case T_AND:
446771Speter 	case T_OR:
44715931Smckusick 		p = rvalue(r->expr_node.lhs, NLNIL , RREQ );
44810364Smckusick #		ifdef PC
449*18468Sralph 		    sconv(p2type(p),PCCT_INT);
45010364Smckusick #		endif PC
45115931Smckusick 		p1 = rvalue(r->expr_node.rhs, NLNIL , RREQ );
45210364Smckusick #		ifdef PC
453*18468Sralph 		    sconv(p2type(p1),PCCT_INT);
45410364Smckusick #		endif PC
45515931Smckusick 		if (p == NLNIL || p1 == NLNIL)
45615931Smckusick 			return (NLNIL);
457771Speter 		if (isnta(p, "b")) {
458771Speter 			error("Left operand of %s must be Boolean, not %s", opname, nameof(p));
45915931Smckusick 			return (NLNIL);
460771Speter 		}
461771Speter 		if (isnta(p1, "b")) {
462771Speter 			error("Right operand of %s must be Boolean, not %s", opname, nameof(p1));
46315931Smckusick 			return (NLNIL);
464771Speter 		}
465771Speter #		ifdef OBJ
46615931Smckusick 		    (void) put(1, r->tag == T_AND ? O_AND : O_OR);
467771Speter #		endif OBJ
468771Speter #		ifdef PC
469771Speter 			/*
470771Speter 			 * note the use of & and | rather than && and ||
471771Speter 			 * to force evaluation of all the expressions.
472771Speter 			 */
473*18468Sralph 		    putop( r->tag == T_AND ? PCC_AND : PCC_OR , PCCT_INT );
474*18468Sralph 		    sconv(PCCT_INT, p2type(p));
475771Speter #		endif PC
476771Speter 		return (nl+T1BOOL);
477771Speter 
478771Speter 	case T_DIVD:
479771Speter #		ifdef OBJ
48015931Smckusick 		    p = rvalue(r->expr_node.lhs, NLNIL , RREQ );
48115931Smckusick 		    p1 = rvalue(r->expr_node.rhs, NLNIL , RREQ );
482771Speter #		endif OBJ
483771Speter #		ifdef PC
484771Speter 			/*
485771Speter 			 *	force these to be doubles for the divide
486771Speter 			 */
48715931Smckusick 		    p = rvalue( r->expr_node.lhs , NLNIL , RREQ );
488*18468Sralph 		    sconv(p2type(p), PCCT_DOUBLE);
48915931Smckusick 		    p1 = rvalue( r->expr_node.rhs , NLNIL , RREQ );
490*18468Sralph 		    sconv(p2type(p1), PCCT_DOUBLE);
491771Speter #		endif PC
49215931Smckusick 		if (p == NLNIL || p1 == NLNIL)
49315931Smckusick 			return (NLNIL);
494771Speter 		if (isnta(p, "id")) {
495771Speter 			error("Left operand of / must be integer or real, not %s", nameof(p));
49615931Smckusick 			return (NLNIL);
497771Speter 		}
498771Speter 		if (isnta(p1, "id")) {
499771Speter 			error("Right operand of / must be integer or real, not %s", nameof(p1));
50015931Smckusick 			return (NLNIL);
501771Speter 		}
502771Speter #		ifdef OBJ
50315931Smckusick 		    return gen(NIL, r->tag, width(p), width(p1));
504771Speter #		endif OBJ
505771Speter #		ifdef PC
506*18468Sralph 		    putop( PCC_DIV , PCCT_DOUBLE );
507771Speter 		    return nl + TDOUBLE;
508771Speter #		endif PC
509771Speter 
510771Speter 	case T_MULT:
511771Speter 	case T_ADD:
512771Speter 	case T_SUB:
513771Speter #		ifdef OBJ
514771Speter 		    /*
51516273Speter 		     * get the type of the right hand side.
51616273Speter 		     * if it turns out to be a set,
51716273Speter 		     * use that type when getting
51816273Speter 		     * the type of the left hand side.
51916273Speter 		     * and then use the type of the left hand side
52016273Speter 		     * when generating code.
52116273Speter 		     * this will correctly decide the type of any
52216273Speter 		     * empty sets in the tree, since if the empty set
52316273Speter 		     * is on the left hand side it will inherit
52416273Speter 		     * the type of the right hand side,
52516273Speter 		     * and if it's on the right hand side, its type (intset)
52616273Speter 		     * will be overridden by the type of the left hand side.
52716273Speter 		     * this is an awful lot of tree traversing,
52816273Speter 		     * but it works.
529771Speter 		     */
53016273Speter 		    codeoff();
53116273Speter 		    p1 = rvalue( r->expr_node.rhs , NLNIL , RREQ );
53216273Speter 		    codeon();
53316273Speter 		    if ( p1 == NLNIL ) {
53415931Smckusick 			return NLNIL;
5351555Speter 		    }
53616273Speter 		    if (isa(p1, "t")) {
53716273Speter 			codeoff();
53816273Speter 			contype = rvalue(r->expr_node.lhs, p1, RREQ);
53916273Speter 			codeon();
54016273Speter 			if (contype == NLNIL) {
54116273Speter 			    return NLNIL;
54216273Speter 			}
54316273Speter 		    }
54415931Smckusick 		    p = rvalue( r->expr_node.lhs , contype , RREQ );
54515931Smckusick 		    p1 = rvalue( r->expr_node.rhs , p , RREQ );
54615937Smckusick 		    if ( p == NLNIL || p1 == NLNIL )
54715931Smckusick 			    return NLNIL;
548771Speter 		    if (isa(p, "id") && isa(p1, "id"))
54915931Smckusick 			return (gen(NIL, r->tag, width(p), width(p1)));
550771Speter 		    if (isa(p, "t") && isa(p1, "t")) {
551771Speter 			    if (p != p1) {
552771Speter 				    error("Set types of operands of %s must be identical", opname);
55315931Smckusick 				    return (NLNIL);
554771Speter 			    }
55515931Smckusick 			    (void) gen(TSET, r->tag, width(p), 0);
556771Speter 			    return (p);
557771Speter 		    }
558771Speter #		endif OBJ
559771Speter #		ifdef PC
560771Speter 			/*
561771Speter 			 * the second pass can't do
562771Speter 			 *	long op double  or  double op long
56316273Speter 			 * so we have to know the type of both operands.
56416273Speter 			 * also, see the note for obj above on determining
56516273Speter 			 * the type of empty sets.
566771Speter 			 */
567771Speter 		    codeoff();
56816273Speter 		    p1 = rvalue(r->expr_node.rhs, NLNIL, RREQ);
569771Speter 		    codeon();
570771Speter 		    if ( isa( p1 , "id" ) ) {
57115931Smckusick 			p = rvalue( r->expr_node.lhs , contype , RREQ );
57215937Smckusick 			if ( ( p == NLNIL ) || ( p1 == NLNIL ) ) {
57315931Smckusick 			    return NLNIL;
574771Speter 			}
57515931Smckusick 			tuac(p, p1, &rettype, (int *) (&ctype));
57615931Smckusick 			p1 = rvalue( r->expr_node.rhs , contype , RREQ );
57715931Smckusick 			tuac(p1, p, &rettype, (int *) (&ctype));
578771Speter 			if ( isa( p , "id" ) ) {
57915931Smckusick 			    putop( (int) mathop[r->tag - T_MULT], (int) ctype);
580771Speter 			    return rettype;
581771Speter 			}
582771Speter 		    }
583771Speter 		    if ( isa( p1 , "t" ) ) {
584*18468Sralph 			putleaf( PCC_ICON , 0 , 0
585*18468Sralph 			    , PCCM_ADDTYPE( PCCM_ADDTYPE( PCCTM_PTR | PCCT_STRTY , PCCTM_FTN )
586*18468Sralph 					, PCCTM_PTR )
58715931Smckusick 			    , setop[ r->tag - T_MULT ] );
58816273Speter 			codeoff();
58916273Speter 			contype = rvalue( r->expr_node.lhs, p1 , LREQ );
59016273Speter 			codeon();
59115937Smckusick 			if ( contype == NLNIL ) {
59215931Smckusick 			    return NLNIL;
5931555Speter 			}
5941555Speter 			    /*
5951555Speter 			     *	allocate a temporary and use it
5961555Speter 			     */
5973834Speter 			tempnlp = tmpalloc(lwidth(contype), contype, NOREG);
59815931Smckusick 			putLV((char *) 0 , cbn , tempnlp -> value[ NL_OFFS ] ,
599*18468Sralph 				tempnlp -> extra_flags , PCCTM_PTR|PCCT_STRTY );
60015931Smckusick 			p = rvalue( r->expr_node.lhs , contype , LREQ );
601771Speter 			if ( isa( p , "t" ) ) {
602*18468Sralph 			    putop( PCC_CM , PCCT_INT );
60315937Smckusick 			    if ( p == NLNIL || p1 == NLNIL ) {
60415931Smckusick 				return NLNIL;
605771Speter 			    }
60615931Smckusick 			    p1 = rvalue( r->expr_node.rhs , p , LREQ );
607771Speter 			    if ( p != p1 ) {
608771Speter 				error("Set types of operands of %s must be identical", opname);
60915931Smckusick 				return NLNIL;
610771Speter 			    }
611*18468Sralph 			    putop( PCC_CM , PCCT_INT );
612*18468Sralph 			    putleaf( PCC_ICON , (int) (lwidth(p1)) / sizeof( long ) , 0
613*18468Sralph 				    , PCCT_INT , (char *) 0 );
614*18468Sralph 			    putop( PCC_CM , PCCT_INT );
615*18468Sralph 			    putop( PCC_CALL , PCCTM_PTR | PCCT_STRTY );
616771Speter 			    return p;
617771Speter 			}
618771Speter 		    }
619771Speter 		    if ( isnta( p1 , "idt" ) ) {
620771Speter 			    /*
621771Speter 			     *	find type of left operand for error message.
622771Speter 			     */
62315931Smckusick 			p = rvalue( r->expr_node.lhs , contype , RREQ );
624771Speter 		    }
625771Speter 			/*
626771Speter 			 *	don't give spurious error messages.
627771Speter 			 */
62815937Smckusick 		    if ( p == NLNIL || p1 == NLNIL ) {
62915931Smckusick 			return NLNIL;
630771Speter 		    }
631771Speter #		endif PC
632771Speter 		if (isnta(p, "idt")) {
633771Speter 			error("Left operand of %s must be integer, real or set, not %s", opname, nameof(p));
63415931Smckusick 			return (NLNIL);
635771Speter 		}
636771Speter 		if (isnta(p1, "idt")) {
637771Speter 			error("Right operand of %s must be integer, real or set, not %s", opname, nameof(p1));
63815931Smckusick 			return (NLNIL);
639771Speter 		}
640771Speter 		error("Cannot mix sets with integers and reals as operands of %s", opname);
64115931Smckusick 		return (NLNIL);
642771Speter 
643771Speter 	case T_MOD:
644771Speter 	case T_DIV:
64515931Smckusick 		p = rvalue(r->expr_node.lhs, NLNIL , RREQ );
64610364Smckusick #		ifdef PC
647*18468Sralph 		    sconv(p2type(p), PCCT_INT);
64810364Smckusick #		endif PC
64915931Smckusick 		p1 = rvalue(r->expr_node.rhs, NLNIL , RREQ );
65010364Smckusick #		ifdef PC
651*18468Sralph 		    sconv(p2type(p1), PCCT_INT);
65210364Smckusick #		endif PC
65315937Smckusick 		if (p == NLNIL || p1 == NLNIL)
65415931Smckusick 			return (NLNIL);
655771Speter 		if (isnta(p, "i")) {
656771Speter 			error("Left operand of %s must be integer, not %s", opname, nameof(p));
65715931Smckusick 			return (NLNIL);
658771Speter 		}
659771Speter 		if (isnta(p1, "i")) {
660771Speter 			error("Right operand of %s must be integer, not %s", opname, nameof(p1));
66115931Smckusick 			return (NLNIL);
662771Speter 		}
663771Speter #		ifdef OBJ
66415931Smckusick 		    return (gen(NIL, r->tag, width(p), width(p1)));
665771Speter #		endif OBJ
666771Speter #		ifdef PC
667*18468Sralph 		    putop( r->tag == T_DIV ? PCC_DIV : PCC_MOD , PCCT_INT );
668771Speter 		    return ( nl + T4INT );
669771Speter #		endif PC
670771Speter 
671771Speter 	case T_EQ:
672771Speter 	case T_NE:
673771Speter 	case T_LT:
674771Speter 	case T_GT:
675771Speter 	case T_LE:
676771Speter 	case T_GE:
677771Speter 		/*
678771Speter 		 * Since there can be no, a priori, knowledge
679771Speter 		 * of the context type should a constant string
680771Speter 		 * or set arise, we must poke around to find such
681771Speter 		 * a type if possible.  Since constant strings can
682771Speter 		 * always masquerade as identifiers, this is always
683771Speter 		 * necessary.
68416273Speter 		 * see the note in the obj section of case T_MULT above
68516273Speter 		 * for the determination of the base type of empty sets.
686771Speter 		 */
687771Speter 		codeoff();
68815931Smckusick 		p1 = rvalue(r->expr_node.rhs, NLNIL , RREQ );
689771Speter 		codeon();
69015931Smckusick 		if (p1 == NLNIL)
69115931Smckusick 			return (NLNIL);
692771Speter 		contype = p1;
693771Speter #		ifdef OBJ
6941555Speter 		    if (p1->class == STR) {
695771Speter 			    /*
696771Speter 			     * For constant strings we want
697771Speter 			     * the longest type so as to be
698771Speter 			     * able to do padding (more importantly
699771Speter 			     * avoiding truncation). For clarity,
700771Speter 			     * we get this length here.
701771Speter 			     */
702771Speter 			    codeoff();
70315931Smckusick 			    p = rvalue(r->expr_node.lhs, NLNIL , RREQ );
704771Speter 			    codeon();
70515931Smckusick 			    if (p == NLNIL)
70615931Smckusick 				    return (NLNIL);
7071555Speter 			    if (width(p) > width(p1))
708771Speter 				    contype = p;
709771Speter 		    }
71016273Speter 		    if (isa(p1, "t")) {
71116273Speter 			codeoff();
71216273Speter 			contype = rvalue(r->expr_node.lhs, p1, RREQ);
71316273Speter 			codeon();
71416273Speter 			if (contype == NLNIL) {
71516273Speter 			    return NLNIL;
71616273Speter 			}
71716273Speter 		    }
718771Speter 		    /*
719771Speter 		     * Now we generate code for
720771Speter 		     * the operands of the relational
721771Speter 		     * operation.
722771Speter 		     */
72315931Smckusick 		    p = rvalue(r->expr_node.lhs, contype , RREQ );
72415931Smckusick 		    if (p == NLNIL)
72515931Smckusick 			    return (NLNIL);
72615931Smckusick 		    p1 = rvalue(r->expr_node.rhs, p , RREQ );
72715931Smckusick 		    if (p1 == NLNIL)
72815931Smckusick 			    return (NLNIL);
729771Speter #		endif OBJ
730771Speter #		ifdef PC
731771Speter 		    c1 = classify( p1 );
732771Speter 		    if ( c1 == TSET || c1 == TSTR || c1 == TREC ) {
733*18468Sralph 			putleaf( PCC_ICON , 0 , 0
734*18468Sralph 				, PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR )
73515931Smckusick 				, c1 == TSET  ? relts[ r->tag - T_EQ ]
73615931Smckusick 					      : relss[ r->tag - T_EQ ] );
737771Speter 			    /*
738771Speter 			     *	for [] and strings, comparisons are done on
739771Speter 			     *	the maximum width of the two sides.
740771Speter 			     *	for other sets, we have to ask the left side
741771Speter 			     *	what type it is based on the type of the right.
742771Speter 			     *	(this matters for intsets).
743771Speter 			     */
7441555Speter 			if ( c1 == TSTR ) {
745771Speter 			    codeoff();
74615931Smckusick 			    p = rvalue( r->expr_node.lhs , NLNIL , LREQ );
747771Speter 			    codeon();
74815931Smckusick 			    if ( p == NLNIL ) {
74915931Smckusick 				return NLNIL;
7501555Speter 			    }
7511555Speter 			    if ( lwidth( p ) > lwidth( p1 ) ) {
752771Speter 				contype = p;
753771Speter 			    }
7541555Speter 			} else if ( c1 == TSET ) {
75515937Smckusick 			    codeoff();
75616273Speter 			    contype = rvalue(r->expr_node.lhs, p1, LREQ);
75715937Smckusick 			    codeon();
75816273Speter 			    if (contype == NLNIL) {
75915937Smckusick 				return NLNIL;
7601555Speter 			    }
7611627Speter 			}
762771Speter 			    /*
763771Speter 			     *	put out the width of the comparison.
764771Speter 			     */
765*18468Sralph 			putleaf(PCC_ICON, (int) lwidth(contype), 0, PCCT_INT, (char *) 0);
766771Speter 			    /*
767771Speter 			     *	and the left hand side,
768771Speter 			     *	for sets, strings, records
769771Speter 			     */
77015931Smckusick 			p = rvalue( r->expr_node.lhs , contype , LREQ );
77115931Smckusick 			if ( p == NLNIL ) {
77215931Smckusick 			    return NLNIL;
7735413Speter 			}
774*18468Sralph 			putop( PCC_CM , PCCT_INT );
77515931Smckusick 			p1 = rvalue( r->expr_node.rhs , p , LREQ );
77615931Smckusick 			if ( p1 == NLNIL ) {
77715931Smckusick 			    return NLNIL;
7785413Speter 			}
779*18468Sralph 			putop( PCC_CM , PCCT_INT );
780*18468Sralph 			putop( PCC_CALL , PCCT_INT );
781771Speter 		    } else {
782771Speter 			    /*
783771Speter 			     *	the easy (scalar or error) case
784771Speter 			     */
78515931Smckusick 			p = rvalue( r->expr_node.lhs , contype , RREQ );
78615931Smckusick 			if ( p == NLNIL ) {
78715931Smckusick 			    return NLNIL;
7882056Speter 			}
789771Speter 			    /*
790771Speter 			     * since the second pass can't do
791771Speter 			     *	long op double  or  double op long
792771Speter 			     * we may have to do some coercing.
793771Speter 			     */
79415931Smckusick 			tuac(p, p1, &rettype, (int *) (&ctype));
79515931Smckusick 			p1 = rvalue( r->expr_node.rhs , p , RREQ );
79615931Smckusick 			if ( p1 == NLNIL ) {
79715931Smckusick 			    return NLNIL;
7985413Speter 			}
79915931Smckusick 			tuac(p1, p, &rettype, (int *) (&ctype));
800*18468Sralph 			putop((int) relops[ r->tag - T_EQ ] , PCCT_INT );
801*18468Sralph 			sconv(PCCT_INT, PCCT_CHAR);
802771Speter 		    }
803771Speter #		endif PC
804771Speter 		c = classify(p);
805771Speter 		c1 = classify(p1);
806771Speter 		if (nocomp(c) || nocomp(c1))
80715931Smckusick 			return (NLNIL);
80815931Smckusick #		ifdef OBJ
80915931Smckusick 		    g = NIL;
81015931Smckusick #		endif
811771Speter 		switch (c) {
812771Speter 			case TBOOL:
813771Speter 			case TCHAR:
814771Speter 				if (c != c1)
815771Speter 					goto clash;
816771Speter 				break;
817771Speter 			case TINT:
818771Speter 			case TDOUBLE:
819771Speter 				if (c1 != TINT && c1 != TDOUBLE)
820771Speter 					goto clash;
821771Speter 				break;
822771Speter 			case TSCAL:
823771Speter 				if (c1 != TSCAL)
824771Speter 					goto clash;
825771Speter 				if (scalar(p) != scalar(p1))
826771Speter 					goto nonident;
827771Speter 				break;
828771Speter 			case TSET:
829771Speter 				if (c1 != TSET)
830771Speter 					goto clash;
8313397Speter 				if ( opt( 's' ) &&
83215931Smckusick 				    ( ( r->tag == T_LT) || (r->tag == T_GT) ) &&
8333397Speter 				    ( line != nssetline ) ) {
8343397Speter 				    nssetline = line;
8353397Speter 				    standard();
8363397Speter 				    error("%s comparison on sets is non-standard" , opname );
8373397Speter 				}
838771Speter 				if (p != p1)
839771Speter 					goto nonident;
84015931Smckusick #				ifdef OBJ
84115931Smckusick 				    g = TSET;
84215931Smckusick #				endif
843771Speter 				break;
844771Speter 			case TREC:
845771Speter 				if ( c1 != TREC ) {
846771Speter 				    goto clash;
847771Speter 				}
848771Speter 				if ( p != p1 ) {
849771Speter 				    goto nonident;
850771Speter 				}
85115931Smckusick 				if (r->tag != T_EQ && r->tag != T_NE) {
852771Speter 					error("%s not allowed on records - only allow = and <>" , opname );
85315931Smckusick 					return (NLNIL);
854771Speter 				}
85515931Smckusick #				ifdef OBJ
85615931Smckusick 				    g = TREC;
85715931Smckusick #				endif
858771Speter 				break;
859771Speter 			case TPTR:
860771Speter 			case TNIL:
861771Speter 				if (c1 != TPTR && c1 != TNIL)
862771Speter 					goto clash;
86315931Smckusick 				if (r->tag != T_EQ && r->tag != T_NE) {
864771Speter 					error("%s not allowed on pointers - only allow = and <>" , opname );
86515931Smckusick 					return (NLNIL);
866771Speter 				}
86715937Smckusick 				if (p != nl+TNIL && p1 != nl+TNIL && p != p1)
86815937Smckusick 					goto nonident;
869771Speter 				break;
870771Speter 			case TSTR:
871771Speter 				if (c1 != TSTR)
872771Speter 					goto clash;
873771Speter 				if (width(p) != width(p1)) {
874771Speter 					error("Strings not same length in %s comparison", opname);
87515931Smckusick 					return (NLNIL);
876771Speter 				}
87715931Smckusick #				ifdef OBJ
87815931Smckusick 				    g = TSTR;
87915931Smckusick #				endif OBJ
880771Speter 				break;
881771Speter 			default:
882771Speter 				panic("rval2");
883771Speter 		}
884771Speter #		ifdef OBJ
88515931Smckusick 		    return (gen(g, r->tag, width(p), width(p1)));
886771Speter #		endif OBJ
887771Speter #		ifdef PC
888771Speter 		    return nl + TBOOL;
889771Speter #		endif PC
890771Speter clash:
891771Speter 		error("%ss and %ss cannot be compared - operator was %s", clnames[c], clnames[c1], opname);
89215931Smckusick 		return (NLNIL);
893771Speter nonident:
894771Speter 		error("%s types must be identical in comparisons - operator was %s", clnames[c1], opname);
89515931Smckusick 		return (NLNIL);
896771Speter 
897771Speter 	case T_IN:
89815931Smckusick 	    rt = r->expr_node.rhs;
899771Speter #	    ifdef OBJ
90015931Smckusick 		if (rt != TR_NIL && rt->tag == T_CSET) {
90115931Smckusick 			(void) precset( rt , NLNIL , &csetd );
902771Speter 			p1 = csetd.csettype;
90315931Smckusick 			if (p1 == NLNIL)
90415931Smckusick 			    return NLNIL;
905771Speter 			postcset( rt, &csetd);
906771Speter 		    } else {
90715931Smckusick 			p1 = stkrval(r->expr_node.rhs, NLNIL , (long) RREQ );
90815931Smckusick 			rt = TR_NIL;
909771Speter 		    }
910771Speter #		endif OBJ
911771Speter #		ifdef PC
91215931Smckusick 		    if (rt != TR_NIL && rt->tag == T_CSET) {
91315931Smckusick 			if ( precset( rt , NLNIL , &csetd ) ) {
914*18468Sralph 			    putleaf( PCC_ICON , 0 , 0
915*18468Sralph 				    , PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR )
9161555Speter 				    , "_IN" );
917771Speter 			} else {
918*18468Sralph 			    putleaf( PCC_ICON , 0 , 0
919*18468Sralph 				    , PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR )
920771Speter 				    , "_INCT" );
921771Speter 			}
922771Speter 			p1 = csetd.csettype;
923771Speter 			if (p1 == NIL)
92415931Smckusick 			    return NLNIL;
925771Speter 		    } else {
926*18468Sralph 			putleaf( PCC_ICON , 0 , 0
927*18468Sralph 				, PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR )
928771Speter 				, "_IN" );
929771Speter 			codeoff();
93015931Smckusick 			p1 = rvalue(r->expr_node.rhs, NLNIL , LREQ );
931771Speter 			codeon();
932771Speter 		    }
933771Speter #		endif PC
93415931Smckusick 		p = stkrval(r->expr_node.lhs, NLNIL , (long) RREQ );
935771Speter 		if (p == NIL || p1 == NIL)
93615931Smckusick 			return (NLNIL);
93715931Smckusick 		if (p1->class != (char) SET) {
938771Speter 			error("Right operand of 'in' must be a set, not %s", nameof(p1));
93915931Smckusick 			return (NLNIL);
940771Speter 		}
94115931Smckusick 		if (incompat(p, p1->type, r->expr_node.lhs)) {
942771Speter 			cerror("Index type clashed with set component type for 'in'");
94315931Smckusick 			return (NLNIL);
944771Speter 		}
945771Speter 		setran(p1->type);
946771Speter #		ifdef OBJ
94715931Smckusick 		    if (rt == TR_NIL || csetd.comptime)
94815931Smckusick 			    (void) put(4, O_IN, width(p1), set.lwrb, set.uprbp);
949771Speter 		    else
95015931Smckusick 			    (void) put(2, O_INCT,
9513078Smckusic 				(int)(3 + csetd.singcnt + 2*csetd.paircnt));
952771Speter #		endif OBJ
953771Speter #		ifdef PC
95415931Smckusick 		    if ( rt == TR_NIL || rt->tag != T_CSET ) {
955*18468Sralph 			putleaf( PCC_ICON , set.lwrb , 0 , PCCT_INT , (char *) 0 );
956*18468Sralph 			putop( PCC_CM , PCCT_INT );
957*18468Sralph 			putleaf( PCC_ICON , set.uprbp , 0 , PCCT_INT , (char *) 0 );
958*18468Sralph 			putop( PCC_CM , PCCT_INT );
95915931Smckusick 			p1 = rvalue( r->expr_node.rhs , NLNIL , LREQ );
96015931Smckusick 			if ( p1 == NLNIL ) {
96115931Smckusick 			    return NLNIL;
9625413Speter 			}
963*18468Sralph 			putop( PCC_CM , PCCT_INT );
964771Speter 		    } else if ( csetd.comptime ) {
965*18468Sralph 			putleaf( PCC_ICON , set.lwrb , 0 , PCCT_INT , (char *) 0 );
966*18468Sralph 			putop( PCC_CM , PCCT_INT );
967*18468Sralph 			putleaf( PCC_ICON , set.uprbp , 0 , PCCT_INT , (char *) 0 );
968*18468Sralph 			putop( PCC_CM , PCCT_INT );
96915931Smckusick 			postcset( r->expr_node.rhs , &csetd );
970*18468Sralph 			putop( PCC_CM , PCCT_INT );
971771Speter 		    } else {
97215931Smckusick 			postcset( r->expr_node.rhs , &csetd );
973771Speter 		    }
974*18468Sralph 		    putop( PCC_CALL , PCCT_INT );
975*18468Sralph 		    sconv(PCCT_INT, PCCT_CHAR);
976771Speter #		endif PC
977771Speter 		return (nl+T1BOOL);
978771Speter 	default:
97915931Smckusick 		if (r->expr_node.lhs == TR_NIL)
98015931Smckusick 			return (NLNIL);
98115931Smckusick 		switch (r->tag) {
982771Speter 		default:
983771Speter 			panic("rval3");
984771Speter 
985771Speter 
986771Speter 		/*
987771Speter 		 * An octal number
988771Speter 		 */
989771Speter 		case T_BINT:
99015931Smckusick 			f.pdouble = a8tol(r->const_node.cptr);
991771Speter 			goto conint;
992771Speter 
993771Speter 		/*
994771Speter 		 * A decimal number
995771Speter 		 */
996771Speter 		case T_INT:
99715931Smckusick 			f.pdouble = atof(r->const_node.cptr);
998771Speter conint:
99915931Smckusick 			if (f.pdouble > MAXINT || f.pdouble < MININT) {
1000771Speter 				error("Constant too large for this implementation");
100115931Smckusick 				return (NLNIL);
1002771Speter 			}
100315931Smckusick 			l = f.pdouble;
100410364Smckusick #			ifdef OBJ
100510364Smckusick 			    if (bytes(l, l) <= 2) {
100615931Smckusick 				    (void) put(2, O_CON2, ( short ) l);
100710364Smckusick 				    return (nl+T2INT);
100810364Smckusick 			    }
100915931Smckusick 			    (void) put(2, O_CON4, l);
101010364Smckusick 			    return (nl+T4INT);
1011771Speter #			endif OBJ
1012771Speter #			ifdef PC
101310364Smckusick 			    switch (bytes(l, l)) {
101410364Smckusick 				case 1:
1015*18468Sralph 				    putleaf(PCC_ICON, (int) l, 0, PCCT_CHAR,
101615931Smckusick 						(char *) 0);
101710364Smckusick 				    return nl+T1INT;
101810364Smckusick 				case 2:
1019*18468Sralph 				    putleaf(PCC_ICON, (int) l, 0, PCCT_SHORT,
102015931Smckusick 						(char *) 0);
102110364Smckusick 				    return nl+T2INT;
102210364Smckusick 				case 4:
1023*18468Sralph 				    putleaf(PCC_ICON, (int) l, 0, PCCT_INT,
102415931Smckusick 						(char *) 0);
102510364Smckusick 				    return nl+T4INT;
102610364Smckusick 			    }
1027771Speter #			endif PC
1028771Speter 
1029771Speter 		/*
1030771Speter 		 * A floating point number
1031771Speter 		 */
1032771Speter 		case T_FINT:
1033771Speter #			ifdef OBJ
103415931Smckusick 			    (void) put(2, O_CON8, atof(r->const_node.cptr));
1035771Speter #			endif OBJ
1036771Speter #			ifdef PC
103715931Smckusick 			    putCON8( atof( r->const_node.cptr ) );
1038771Speter #			endif PC
1039771Speter 			return (nl+TDOUBLE);
1040771Speter 
1041771Speter 		/*
1042771Speter 		 * Constant strings.  Note that constant characters
1043771Speter 		 * are constant strings of length one; there is
1044771Speter 		 * no constant string of length one.
1045771Speter 		 */
1046771Speter 		case T_STRNG:
104715931Smckusick 			cp = r->const_node.cptr;
1048771Speter 			if (cp[1] == 0) {
1049771Speter #				ifdef OBJ
105015931Smckusick 				    (void) put(2, O_CONC, cp[0]);
1051771Speter #				endif OBJ
1052771Speter #				ifdef PC
1053*18468Sralph 				    putleaf( PCC_ICON , cp[0] , 0 , PCCT_CHAR ,
105415931Smckusick 						(char *) 0 );
1055771Speter #				endif PC
1056771Speter 				return (nl+T1CHAR);
1057771Speter 			}
1058771Speter 			goto cstrng;
1059771Speter 		}
1060771Speter 
1061771Speter 	}
1062771Speter }
1063771Speter 
1064771Speter /*
1065771Speter  * Can a class appear
1066771Speter  * in a comparison ?
1067771Speter  */
1068771Speter nocomp(c)
1069771Speter 	int c;
1070771Speter {
1071771Speter 
1072771Speter 	switch (c) {
1073771Speter 		case TREC:
10741627Speter 			if ( line != reccompline ) {
10751627Speter 			    reccompline = line;
10761627Speter 			    warning();
10771627Speter 			    if ( opt( 's' ) ) {
10781627Speter 				standard();
10791627Speter 			    }
1080771Speter 			    error("record comparison is non-standard");
1081771Speter 			}
1082771Speter 			break;
1083771Speter 		case TFILE:
1084771Speter 		case TARY:
1085771Speter 			error("%ss may not participate in comparisons", clnames[c]);
1086771Speter 			return (1);
1087771Speter 	}
1088771Speter 	return (NIL);
1089771Speter }
1090771Speter 
1091771Speter     /*
1092771Speter      *	this is sort of like gconst, except it works on expression trees
1093771Speter      *	rather than declaration trees, and doesn't give error messages for
1094771Speter      *	non-constant things.
1095771Speter      *	as a side effect this fills in the con structure that gconst uses.
1096771Speter      *	this returns TRUE or FALSE.
1097771Speter      */
109815931Smckusick 
109915931Smckusick bool
1100771Speter constval(r)
110115931Smckusick 	register struct tnode *r;
1102771Speter {
1103771Speter 	register struct nl *np;
110415931Smckusick 	register struct tnode *cn;
1105771Speter 	char *cp;
1106771Speter 	int negd, sgnd;
1107771Speter 	long ci;
1108771Speter 
1109771Speter 	con.ctype = NIL;
1110771Speter 	cn = r;
1111771Speter 	negd = sgnd = 0;
1112771Speter loop:
1113771Speter 	    /*
1114771Speter 	     *	cn[2] is nil if error recovery generated a T_STRNG
1115771Speter 	     */
111615931Smckusick 	if (cn == TR_NIL || cn->expr_node.lhs == TR_NIL)
1117771Speter 		return FALSE;
111815931Smckusick 	switch (cn->tag) {
1119771Speter 		default:
1120771Speter 			return FALSE;
1121771Speter 		case T_MINUS:
1122771Speter 			negd = 1 - negd;
1123771Speter 			/* and fall through */
1124771Speter 		case T_PLUS:
1125771Speter 			sgnd++;
112615931Smckusick 			cn = cn->un_expr.expr;
1127771Speter 			goto loop;
1128771Speter 		case T_NIL:
1129771Speter 			con.cpval = NIL;
1130771Speter 			con.cival = 0;
1131771Speter 			con.crval = con.cival;
1132771Speter 			con.ctype = nl + TNIL;
1133771Speter 			break;
1134771Speter 		case T_VAR:
113515931Smckusick 			np = lookup(cn->var_node.cptr);
113615931Smckusick 			if (np == NLNIL || np->class != CONST) {
1137771Speter 				return FALSE;
1138771Speter 			}
113915931Smckusick 			if ( cn->var_node.qual != TR_NIL ) {
1140771Speter 				return FALSE;
1141771Speter 			}
1142771Speter 			con.ctype = np->type;
1143771Speter 			switch (classify(np->type)) {
1144771Speter 				case TINT:
1145771Speter 					con.crval = np->range[0];
1146771Speter 					break;
1147771Speter 				case TDOUBLE:
1148771Speter 					con.crval = np->real;
1149771Speter 					break;
1150771Speter 				case TBOOL:
1151771Speter 				case TCHAR:
1152771Speter 				case TSCAL:
1153771Speter 					con.cival = np->value[0];
1154771Speter 					con.crval = con.cival;
1155771Speter 					break;
1156771Speter 				case TSTR:
115715931Smckusick 					con.cpval = (char *) np->ptr[0];
1158771Speter 					break;
1159771Speter 				default:
1160771Speter 					con.ctype = NIL;
1161771Speter 					return FALSE;
1162771Speter 			}
1163771Speter 			break;
1164771Speter 		case T_BINT:
116515931Smckusick 			con.crval = a8tol(cn->const_node.cptr);
1166771Speter 			goto restcon;
1167771Speter 		case T_INT:
116815931Smckusick 			con.crval = atof(cn->const_node.cptr);
1169771Speter 			if (con.crval > MAXINT || con.crval < MININT) {
1170771Speter 				derror("Constant too large for this implementation");
1171771Speter 				con.crval = 0;
1172771Speter 			}
1173771Speter restcon:
1174771Speter 			ci = con.crval;
1175771Speter #ifndef PI0
1176771Speter 			if (bytes(ci, ci) <= 2)
1177771Speter 				con.ctype = nl+T2INT;
1178771Speter 			else
1179771Speter #endif
1180771Speter 				con.ctype = nl+T4INT;
1181771Speter 			break;
1182771Speter 		case T_FINT:
1183771Speter 			con.ctype = nl+TDOUBLE;
118415931Smckusick 			con.crval = atof(cn->const_node.cptr);
1185771Speter 			break;
1186771Speter 		case T_STRNG:
118715931Smckusick 			cp = cn->const_node.cptr;
1188771Speter 			if (cp[1] == 0) {
1189771Speter 				con.ctype = nl+T1CHAR;
1190771Speter 				con.cival = cp[0];
1191771Speter 				con.crval = con.cival;
1192771Speter 				break;
1193771Speter 			}
1194771Speter 			con.ctype = nl+TSTR;
1195771Speter 			con.cpval = cp;
1196771Speter 			break;
1197771Speter 	}
1198771Speter 	if (sgnd) {
1199771Speter 		if (isnta(con.ctype, "id")) {
1200771Speter 			derror("%s constants cannot be signed", nameof(con.ctype));
1201771Speter 			return FALSE;
1202771Speter 		} else if (negd)
1203771Speter 			con.crval = -con.crval;
1204771Speter 	}
1205771Speter 	return TRUE;
1206771Speter }
1207