xref: /csrg-svn/usr.bin/pascal/src/rval.c (revision 16000)
1 /* Copyright (c) 1979 Regents of the University of California */
2 
3 #ifndef lint
4 static char sccsid[] = "@(#)rval.c 2.1 02/08/84";
5 #endif
6 
7 #include "whoami.h"
8 #include "0.h"
9 #include "tree.h"
10 #include "opcode.h"
11 #include "objfmt.h"
12 #ifdef PC
13 #   include	"pc.h"
14 #   include "pcops.h"
15 #endif PC
16 #include "tmps.h"
17 #include "tree_ty.h"
18 
19 extern	char *opnames[];
20 
21     /* line number of the last record comparison warning */
22 short reccompline = 0;
23     /* line number of the last non-standard set comparison */
24 short nssetline = 0;
25 
26 #ifdef PC
27     char	*relts[] =  {
28 				"_RELEQ" , "_RELNE" ,
29 				"_RELTLT" , "_RELTGT" ,
30 				"_RELTLE" , "_RELTGE"
31 			    };
32     char	*relss[] =  {
33 				"_RELEQ" , "_RELNE" ,
34 				"_RELSLT" , "_RELSGT" ,
35 				"_RELSLE" , "_RELSGE"
36 			    };
37     long	relops[] =  {
38 				P2EQ , P2NE ,
39 				P2LT , P2GT ,
40 				P2LE , P2GE
41 			    };
42     long	mathop[] =  {	P2MUL , P2PLUS , P2MINUS };
43     char	*setop[] =  {	"_MULT" , "_ADDT" , "_SUBT" };
44 #endif PC
45 /*
46  * Rvalue - an expression.
47  *
48  * Contype is the type that the caller would prefer, nand is important
49  * if constant sets or constant strings are involved, the latter
50  * because of string padding.
51  * required is a flag whether an lvalue or an rvalue is required.
52  * only VARs and structured things can have gt their lvalue this way.
53  */
54 /*ARGSUSED*/
55 struct nl *
56 rvalue(r, contype , required )
57 	struct tnode *r;
58 	struct nl *contype;
59 	int	required;
60 {
61 	register struct nl *p, *p1;
62 	register struct nl *q;
63 	int c, c1, w;
64 #ifdef OBJ
65 	int g;
66 #endif
67 	struct tnode *rt;
68 	char *cp, *cp1, *opname;
69 	long l;
70 	union
71 	{
72 	    long plong[2];
73 	    double pdouble;
74 	}f;
75 	extern int	flagwas;
76 	struct csetstr	csetd;
77 #	ifdef PC
78 	    struct nl	*rettype;
79 	    long	ctype;
80 	    struct nl	*tempnlp;
81 #	endif PC
82 
83 	if (r == TR_NIL)
84 		return (NLNIL);
85 	if (nowexp(r))
86 		return (NLNIL);
87 	/*
88 	 * Pick up the name of the operation
89 	 * for future error messages.
90 	 */
91 	if (r->tag <= T_IN)
92 		opname = opnames[r->tag];
93 
94 	/*
95 	 * The root of the tree tells us what sort of expression we have.
96 	 */
97 	switch (r->tag) {
98 
99 	/*
100 	 * The constant nil
101 	 */
102 	case T_NIL:
103 #		ifdef OBJ
104 		    (void) put(2, O_CON2, 0);
105 #		endif OBJ
106 #		ifdef PC
107 		    putleaf( P2ICON , 0 , 0 , P2PTR|P2UNDEF , (char *) 0 );
108 #		endif PC
109 		return (nl+TNIL);
110 
111 	/*
112 	 * Function call with arguments.
113 	 */
114 	case T_FCALL:
115 #	    ifdef OBJ
116 		return (funccod(r));
117 #	    endif OBJ
118 #	    ifdef PC
119 		return (pcfunccod( r ));
120 #	    endif PC
121 
122 	case T_VAR:
123 		p = lookup(r->var_node.cptr);
124 		if (p == NLNIL || p->class == BADUSE)
125 			return (NLNIL);
126 		switch (p->class) {
127 		    case VAR:
128 			    /*
129 			     * If a variable is
130 			     * qualified then get
131 			     * the rvalue by a
132 			     * lvalue and an ind.
133 			     */
134 			    if (r->var_node.qual != TR_NIL)
135 				    goto ind;
136 			    q = p->type;
137 			    if (q == NIL)
138 				    return (NLNIL);
139 #			    ifdef OBJ
140 				w = width(q);
141 				switch (w) {
142 				    case 8:
143 					(void) put(2, O_RV8 | bn << 8+INDX,
144 						(int)p->value[0]);
145 					break;
146 				    case 4:
147 					(void) put(2, O_RV4 | bn << 8+INDX,
148 						(int)p->value[0]);
149 					break;
150 				    case 2:
151 					(void) put(2, O_RV2 | bn << 8+INDX,
152 						(int)p->value[0]);
153 					break;
154 				    case 1:
155 					(void) put(2, O_RV1 | bn << 8+INDX,
156 						(int)p->value[0]);
157 					break;
158 				    default:
159 					(void) put(3, O_RV | bn << 8+INDX,
160 						(int)p->value[0], w);
161 				}
162 #			   endif OBJ
163 #			   ifdef PC
164 				if ( required == RREQ ) {
165 				    putRV( p -> symbol , bn , p -> value[0] ,
166 					    p -> extra_flags , p2type( q ) );
167 				} else {
168 				    putLV( p -> symbol , bn , p -> value[0] ,
169 					    p -> extra_flags , p2type( q ) );
170 				}
171 #			   endif PC
172 			   return (q);
173 
174 		    case WITHPTR:
175 		    case REF:
176 			    /*
177 			     * A lvalue for these
178 			     * is actually what one
179 			     * might consider a rvalue.
180 			     */
181 ind:
182 			    q = lvalue(r, NOFLAGS , LREQ );
183 			    if (q == NIL)
184 				    return (NLNIL);
185 #			    ifdef OBJ
186 				w = width(q);
187 				switch (w) {
188 				    case 8:
189 					    (void) put(1, O_IND8);
190 					    break;
191 				    case 4:
192 					    (void) put(1, O_IND4);
193 					    break;
194 				    case 2:
195 					    (void) put(1, O_IND2);
196 					    break;
197 				    case 1:
198 					    (void) put(1, O_IND1);
199 					    break;
200 				    default:
201 					    (void) put(2, O_IND, w);
202 				}
203 #			    endif OBJ
204 #			    ifdef PC
205 				if ( required == RREQ ) {
206 				    putop( P2UNARY P2MUL , p2type( q ) );
207 				}
208 #			    endif PC
209 			    return (q);
210 
211 		    case CONST:
212 			    if (r->var_node.qual != TR_NIL) {
213 				error("%s is a constant and cannot be qualified", r->var_node.cptr);
214 				return (NLNIL);
215 			    }
216 			    q = p->type;
217 			    if (q == NLNIL)
218 				    return (NLNIL);
219 			    if (q == nl+TSTR) {
220 				    /*
221 				     * Find the size of the string
222 				     * constant if needed.
223 				     */
224 				    cp = (char *) p->ptr[0];
225 cstrng:
226 				    cp1 = cp;
227 				    for (c = 0; *cp++; c++)
228 					    continue;
229 				    w = c;
230 				    if (contype != NIL && !opt('s')) {
231 					    if (width(contype) < c && classify(contype) == TSTR) {
232 						    error("Constant string too long");
233 						    return (NLNIL);
234 					    }
235 					    w = width(contype);
236 				    }
237 #				    ifdef OBJ
238 					(void) put(2, O_CONG, w);
239 					putstr(cp1, w - c);
240 #				    endif OBJ
241 #				    ifdef PC
242 					putCONG( cp1 , w , required );
243 #				    endif PC
244 				    /*
245 				     * Define the string temporarily
246 				     * so later people can know its
247 				     * width.
248 				     * cleaned out by stat.
249 				     */
250 				    q = defnl((char *) 0, STR, NLNIL, w);
251 				    q->type = q;
252 				    return (q);
253 			    }
254 			    if (q == nl+T1CHAR) {
255 #				    ifdef OBJ
256 					(void) put(2, O_CONC, (int)p->value[0]);
257 #				    endif OBJ
258 #				    ifdef PC
259 					putleaf( P2ICON , p -> value[0] , 0
260 						, P2CHAR , (char *) 0 );
261 #				    endif PC
262 				    return (q);
263 			    }
264 			    /*
265 			     * Every other kind of constant here
266 			     */
267 			    switch (width(q)) {
268 			    case 8:
269 #ifndef DEBUG
270 #				    ifdef OBJ
271 					(void) put(2, O_CON8, p->real);
272 #				    endif OBJ
273 #				    ifdef PC
274 					putCON8( p -> real );
275 #				    endif PC
276 #else
277 				    if (hp21mx) {
278 					    f.pdouble = p->real;
279 					    conv((int *) (&f.pdouble));
280 					    l = f.plong[1];
281 					    (void) put(2, O_CON4, l);
282 				    } else
283 #					    ifdef OBJ
284 						(void) put(2, O_CON8, p->real);
285 #					    endif OBJ
286 #					    ifdef PC
287 						putCON8( p -> real );
288 #					    endif PC
289 #endif
290 				    break;
291 			    case 4:
292 #				    ifdef OBJ
293 					(void) put(2, O_CON4, p->range[0]);
294 #				    endif OBJ
295 #				    ifdef PC
296 					putleaf( P2ICON , (int) p->range[0] , 0
297 						, P2INT , (char *) 0 );
298 #				    endif PC
299 				    break;
300 			    case 2:
301 #				    ifdef OBJ
302 					(void) put(2, O_CON2, (short)p->range[0]);
303 #				    endif OBJ
304 #				    ifdef PC
305 					putleaf( P2ICON , (short) p -> range[0]
306 						, 0 , P2SHORT , (char *) 0 );
307 #				    endif PC
308 				    break;
309 			    case 1:
310 #				    ifdef OBJ
311 					(void) put(2, O_CON1, p->value[0]);
312 #				    endif OBJ
313 #				    ifdef PC
314 					putleaf( P2ICON , p -> value[0] , 0
315 						, P2CHAR , (char *) 0 );
316 #				    endif PC
317 				    break;
318 			    default:
319 				    panic("rval");
320 			    }
321 			    return (q);
322 
323 		    case FUNC:
324 		    case FFUNC:
325 			    /*
326 			     * Function call with no arguments.
327 			     */
328 			    if (r->var_node.qual != TR_NIL) {
329 				    error("Can't qualify a function result value");
330 				    return (NLNIL);
331 			    }
332 #			    ifdef OBJ
333 				return (funccod(r));
334 #			    endif OBJ
335 #			    ifdef PC
336 				return (pcfunccod( r ));
337 #			    endif PC
338 
339 		    case TYPE:
340 			    error("Type names (e.g. %s) allowed only in declarations", p->symbol);
341 			    return (NLNIL);
342 
343 		    case PROC:
344 		    case FPROC:
345 			    error("Procedure %s found where expression required", p->symbol);
346 			    return (NLNIL);
347 		    default:
348 			    panic("rvid");
349 		}
350 	/*
351 	 * Constant sets
352 	 */
353 	case T_CSET:
354 #		ifdef OBJ
355 		    if ( precset( r , contype , &csetd ) ) {
356 			if ( csetd.csettype == NIL ) {
357 			    return (NLNIL);
358 			}
359 			postcset( r , &csetd );
360 		    } else {
361 			(void) put( 2, O_PUSH, -lwidth(csetd.csettype));
362 			postcset( r , &csetd );
363 			setran( ( csetd.csettype ) -> type );
364 			(void) put( 2, O_CON24, set.uprbp);
365 			(void) put( 2, O_CON24, set.lwrb);
366 			(void) put( 2, O_CTTOT,
367 				(int)(4 + csetd.singcnt + 2 * csetd.paircnt));
368 		    }
369 		    return csetd.csettype;
370 #		endif OBJ
371 #		ifdef PC
372 		    if ( precset( r , contype , &csetd ) ) {
373 			if ( csetd.csettype == NIL ) {
374 			    return (NLNIL);
375 			}
376 			postcset( r , &csetd );
377 		    } else {
378 			putleaf( P2ICON , 0 , 0
379 				, ADDTYPE( P2FTN | P2INT , P2PTR )
380 				, "_CTTOT" );
381 			/*
382 			 *	allocate a temporary and use it
383 			 */
384 			tempnlp = tmpalloc(lwidth(csetd.csettype),
385 				csetd.csettype, NOREG);
386 			putLV( (char *) 0 , cbn , tempnlp -> value[ NL_OFFS ] ,
387 				tempnlp -> extra_flags , P2PTR|P2STRTY );
388 			setran( ( csetd.csettype ) -> type );
389 			putleaf( P2ICON , set.lwrb , 0 , P2INT , (char *) 0 );
390 			putop( P2LISTOP , P2INT );
391 			putleaf( P2ICON , set.uprbp , 0 , P2INT , (char *) 0 );
392 			putop( P2LISTOP , P2INT );
393 			postcset( r , &csetd );
394 			putop( P2CALL , P2INT );
395 		    }
396 		    return csetd.csettype;
397 #		endif PC
398 
399 	/*
400 	 * Unary plus and minus
401 	 */
402 	case T_PLUS:
403 	case T_MINUS:
404 		q = rvalue(r->un_expr.expr, NLNIL , RREQ );
405 		if (q == NLNIL)
406 			return (NLNIL);
407 		if (isnta(q, "id")) {
408 			error("Operand of %s must be integer or real, not %s", opname, nameof(q));
409 			return (NLNIL);
410 		}
411 		if (r->tag == T_MINUS) {
412 #		    ifdef OBJ
413 			(void) put(1, O_NEG2 + (width(q) >> 2));
414 			return (isa(q, "d") ? q : nl+T4INT);
415 #		    endif OBJ
416 #		    ifdef PC
417 			if (isa(q, "i")) {
418 			    sconv(p2type(q), P2INT);
419 			    putop( P2UNARY P2MINUS, P2INT);
420 			    return nl+T4INT;
421 			}
422 			putop( P2UNARY P2MINUS, P2DOUBLE);
423 			return nl+TDOUBLE;
424 #		    endif PC
425 		}
426 		return (q);
427 
428 	case T_NOT:
429 		q = rvalue(r->un_expr.expr, NLNIL , RREQ );
430 		if (q == NLNIL)
431 			return (NLNIL);
432 		if (isnta(q, "b")) {
433 			error("not must operate on a Boolean, not %s", nameof(q));
434 			return (NLNIL);
435 		}
436 #		ifdef OBJ
437 		    (void) put(1, O_NOT);
438 #		endif OBJ
439 #		ifdef PC
440 		    sconv(p2type(q), P2INT);
441 		    putop( P2NOT , P2INT);
442 		    sconv(P2INT, p2type(q));
443 #		endif PC
444 		return (nl+T1BOOL);
445 
446 	case T_AND:
447 	case T_OR:
448 		p = rvalue(r->expr_node.lhs, NLNIL , RREQ );
449 #		ifdef PC
450 		    sconv(p2type(p),P2INT);
451 #		endif PC
452 		p1 = rvalue(r->expr_node.rhs, NLNIL , RREQ );
453 #		ifdef PC
454 		    sconv(p2type(p1),P2INT);
455 #		endif PC
456 		if (p == NLNIL || p1 == NLNIL)
457 			return (NLNIL);
458 		if (isnta(p, "b")) {
459 			error("Left operand of %s must be Boolean, not %s", opname, nameof(p));
460 			return (NLNIL);
461 		}
462 		if (isnta(p1, "b")) {
463 			error("Right operand of %s must be Boolean, not %s", opname, nameof(p1));
464 			return (NLNIL);
465 		}
466 #		ifdef OBJ
467 		    (void) put(1, r->tag == T_AND ? O_AND : O_OR);
468 #		endif OBJ
469 #		ifdef PC
470 			/*
471 			 * note the use of & and | rather than && and ||
472 			 * to force evaluation of all the expressions.
473 			 */
474 		    putop( r->tag == T_AND ? P2AND : P2OR , P2INT );
475 		    sconv(P2INT, p2type(p));
476 #		endif PC
477 		return (nl+T1BOOL);
478 
479 	case T_DIVD:
480 #		ifdef OBJ
481 		    p = rvalue(r->expr_node.lhs, NLNIL , RREQ );
482 		    p1 = rvalue(r->expr_node.rhs, NLNIL , RREQ );
483 #		endif OBJ
484 #		ifdef PC
485 			/*
486 			 *	force these to be doubles for the divide
487 			 */
488 		    p = rvalue( r->expr_node.lhs , NLNIL , RREQ );
489 		    sconv(p2type(p), P2DOUBLE);
490 		    p1 = rvalue( r->expr_node.rhs , NLNIL , RREQ );
491 		    sconv(p2type(p1), P2DOUBLE);
492 #		endif PC
493 		if (p == NLNIL || p1 == NLNIL)
494 			return (NLNIL);
495 		if (isnta(p, "id")) {
496 			error("Left operand of / must be integer or real, not %s", nameof(p));
497 			return (NLNIL);
498 		}
499 		if (isnta(p1, "id")) {
500 			error("Right operand of / must be integer or real, not %s", nameof(p1));
501 			return (NLNIL);
502 		}
503 #		ifdef OBJ
504 		    return gen(NIL, r->tag, width(p), width(p1));
505 #		endif OBJ
506 #		ifdef PC
507 		    putop( P2DIV , P2DOUBLE );
508 		    return nl + TDOUBLE;
509 #		endif PC
510 
511 	case T_MULT:
512 	case T_ADD:
513 	case T_SUB:
514 #		ifdef OBJ
515 		    /*
516 		     * If the context hasn't told us the type
517 		     * and a constant set is present
518 		     * we need to infer the type
519 		     * before generating code.
520 		     */
521 		    if ( contype == NLNIL ) {
522 			    codeoff();
523 			    contype = rvalue( r->expr_node.rhs , NLNIL , RREQ );
524 			    codeon();
525 		    }
526 		    if ( contype == NLNIL ) {
527 			return NLNIL;
528 		    }
529 		    p = rvalue( r->expr_node.lhs , contype , RREQ );
530 		    p1 = rvalue( r->expr_node.rhs , p , RREQ );
531 		    if ( p == NLNIL || p1 == NLNIL )
532 			    return NLNIL;
533 		    if (isa(p, "id") && isa(p1, "id"))
534 			return (gen(NIL, r->tag, width(p), width(p1)));
535 		    if (isa(p, "t") && isa(p1, "t")) {
536 			    if (p != p1) {
537 				    error("Set types of operands of %s must be identical", opname);
538 				    return (NLNIL);
539 			    }
540 			    (void) gen(TSET, r->tag, width(p), 0);
541 			    return (p);
542 		    }
543 #		endif OBJ
544 #		ifdef PC
545 			/*
546 			 * the second pass can't do
547 			 *	long op double  or  double op long
548 			 * so we have to know the type of both operands
549 			 * also, it gets tricky for sets, which are done
550 			 * by function calls.
551 			 */
552 		    codeoff();
553 		    p1 = rvalue( r->expr_node.rhs , contype , RREQ );
554 		    codeon();
555 		    if ( isa( p1 , "id" ) ) {
556 			p = rvalue( r->expr_node.lhs , contype , RREQ );
557 			if ( ( p == NLNIL ) || ( p1 == NLNIL ) ) {
558 			    return NLNIL;
559 			}
560 			tuac(p, p1, &rettype, (int *) (&ctype));
561 			p1 = rvalue( r->expr_node.rhs , contype , RREQ );
562 			tuac(p1, p, &rettype, (int *) (&ctype));
563 			if ( isa( p , "id" ) ) {
564 			    putop( (int) mathop[r->tag - T_MULT], (int) ctype);
565 			    return rettype;
566 			}
567 		    }
568 		    if ( isa( p1 , "t" ) ) {
569 			putleaf( P2ICON , 0 , 0
570 			    , ADDTYPE( ADDTYPE( P2PTR | P2STRTY , P2FTN )
571 					, P2PTR )
572 			    , setop[ r->tag - T_MULT ] );
573 			if ( contype == NLNIL ) {
574 			    codeoff();
575 			    contype = rvalue( r->expr_node.lhs, p1 , LREQ );
576 			    codeon();
577 			}
578 			if ( contype == NLNIL ) {
579 			    return NLNIL;
580 			}
581 			    /*
582 			     *	allocate a temporary and use it
583 			     */
584 			tempnlp = tmpalloc(lwidth(contype), contype, NOREG);
585 			putLV((char *) 0 , cbn , tempnlp -> value[ NL_OFFS ] ,
586 				tempnlp -> extra_flags , P2PTR|P2STRTY );
587 			p = rvalue( r->expr_node.lhs , contype , LREQ );
588 			if ( isa( p , "t" ) ) {
589 			    putop( P2LISTOP , P2INT );
590 			    if ( p == NLNIL || p1 == NLNIL ) {
591 				return NLNIL;
592 			    }
593 			    p1 = rvalue( r->expr_node.rhs , p , LREQ );
594 			    if ( p != p1 ) {
595 				error("Set types of operands of %s must be identical", opname);
596 				return NLNIL;
597 			    }
598 			    putop( P2LISTOP , P2INT );
599 			    putleaf( P2ICON , (int) (lwidth(p1)) / sizeof( long ) , 0
600 				    , P2INT , (char *) 0 );
601 			    putop( P2LISTOP , P2INT );
602 			    putop( P2CALL , P2PTR | P2STRTY );
603 			    return p;
604 			}
605 		    }
606 		    if ( isnta( p1 , "idt" ) ) {
607 			    /*
608 			     *	find type of left operand for error message.
609 			     */
610 			p = rvalue( r->expr_node.lhs , contype , RREQ );
611 		    }
612 			/*
613 			 *	don't give spurious error messages.
614 			 */
615 		    if ( p == NLNIL || p1 == NLNIL ) {
616 			return NLNIL;
617 		    }
618 #		endif PC
619 		if (isnta(p, "idt")) {
620 			error("Left operand of %s must be integer, real or set, not %s", opname, nameof(p));
621 			return (NLNIL);
622 		}
623 		if (isnta(p1, "idt")) {
624 			error("Right operand of %s must be integer, real or set, not %s", opname, nameof(p1));
625 			return (NLNIL);
626 		}
627 		error("Cannot mix sets with integers and reals as operands of %s", opname);
628 		return (NLNIL);
629 
630 	case T_MOD:
631 	case T_DIV:
632 		p = rvalue(r->expr_node.lhs, NLNIL , RREQ );
633 #		ifdef PC
634 		    sconv(p2type(p), P2INT);
635 #		endif PC
636 		p1 = rvalue(r->expr_node.rhs, NLNIL , RREQ );
637 #		ifdef PC
638 		    sconv(p2type(p1), P2INT);
639 #		endif PC
640 		if (p == NLNIL || p1 == NLNIL)
641 			return (NLNIL);
642 		if (isnta(p, "i")) {
643 			error("Left operand of %s must be integer, not %s", opname, nameof(p));
644 			return (NLNIL);
645 		}
646 		if (isnta(p1, "i")) {
647 			error("Right operand of %s must be integer, not %s", opname, nameof(p1));
648 			return (NLNIL);
649 		}
650 #		ifdef OBJ
651 		    return (gen(NIL, r->tag, width(p), width(p1)));
652 #		endif OBJ
653 #		ifdef PC
654 		    putop( r->tag == T_DIV ? P2DIV : P2MOD , P2INT );
655 		    return ( nl + T4INT );
656 #		endif PC
657 
658 	case T_EQ:
659 	case T_NE:
660 	case T_LT:
661 	case T_GT:
662 	case T_LE:
663 	case T_GE:
664 		/*
665 		 * Since there can be no, a priori, knowledge
666 		 * of the context type should a constant string
667 		 * or set arise, we must poke around to find such
668 		 * a type if possible.  Since constant strings can
669 		 * always masquerade as identifiers, this is always
670 		 * necessary.
671 		 */
672 		codeoff();
673 		p1 = rvalue(r->expr_node.rhs, NLNIL , RREQ );
674 		codeon();
675 		if (p1 == NLNIL)
676 			return (NLNIL);
677 		contype = p1;
678 #		ifdef OBJ
679 		    if (p1->class == STR) {
680 			    /*
681 			     * For constant strings we want
682 			     * the longest type so as to be
683 			     * able to do padding (more importantly
684 			     * avoiding truncation). For clarity,
685 			     * we get this length here.
686 			     */
687 			    codeoff();
688 			    p = rvalue(r->expr_node.lhs, NLNIL , RREQ );
689 			    codeon();
690 			    if (p == NLNIL)
691 				    return (NLNIL);
692 			    if (width(p) > width(p1))
693 				    contype = p;
694 		    }
695 		    /*
696 		     * Now we generate code for
697 		     * the operands of the relational
698 		     * operation.
699 		     */
700 		    p = rvalue(r->expr_node.lhs, contype , RREQ );
701 		    if (p == NLNIL)
702 			    return (NLNIL);
703 		    p1 = rvalue(r->expr_node.rhs, p , RREQ );
704 		    if (p1 == NLNIL)
705 			    return (NLNIL);
706 #		endif OBJ
707 #		ifdef PC
708 		    c1 = classify( p1 );
709 		    if ( c1 == TSET || c1 == TSTR || c1 == TREC ) {
710 			putleaf( P2ICON , 0 , 0
711 				, ADDTYPE( P2FTN | P2INT , P2PTR )
712 				, c1 == TSET  ? relts[ r->tag - T_EQ ]
713 					      : relss[ r->tag - T_EQ ] );
714 			    /*
715 			     *	for [] and strings, comparisons are done on
716 			     *	the maximum width of the two sides.
717 			     *	for other sets, we have to ask the left side
718 			     *	what type it is based on the type of the right.
719 			     *	(this matters for intsets).
720 			     */
721 			if ( c1 == TSTR ) {
722 			    codeoff();
723 			    p = rvalue( r->expr_node.lhs , NLNIL , LREQ );
724 			    codeon();
725 			    if ( p == NLNIL ) {
726 				return NLNIL;
727 			    }
728 			    if ( lwidth( p ) > lwidth( p1 ) ) {
729 				contype = p;
730 			    }
731 			} else if ( c1 == TSET ) {
732 			    codeoff();
733 			    p = rvalue( r->expr_node.lhs , contype , LREQ );
734 			    codeon();
735 			    if ( p == NLNIL ) {
736 				return NLNIL;
737 			    }
738 			    contype = p;
739 			}
740 			    /*
741 			     *	put out the width of the comparison.
742 			     */
743 			putleaf(P2ICON, (int) lwidth(contype), 0, P2INT, (char *) 0);
744 			    /*
745 			     *	and the left hand side,
746 			     *	for sets, strings, records
747 			     */
748 			p = rvalue( r->expr_node.lhs , contype , LREQ );
749 			if ( p == NLNIL ) {
750 			    return NLNIL;
751 			}
752 			putop( P2LISTOP , P2INT );
753 			p1 = rvalue( r->expr_node.rhs , p , LREQ );
754 			if ( p1 == NLNIL ) {
755 			    return NLNIL;
756 			}
757 			putop( P2LISTOP , P2INT );
758 			putop( P2CALL , P2INT );
759 		    } else {
760 			    /*
761 			     *	the easy (scalar or error) case
762 			     */
763 			p = rvalue( r->expr_node.lhs , contype , RREQ );
764 			if ( p == NLNIL ) {
765 			    return NLNIL;
766 			}
767 			    /*
768 			     * since the second pass can't do
769 			     *	long op double  or  double op long
770 			     * we may have to do some coercing.
771 			     */
772 			tuac(p, p1, &rettype, (int *) (&ctype));
773 			p1 = rvalue( r->expr_node.rhs , p , RREQ );
774 			if ( p1 == NLNIL ) {
775 			    return NLNIL;
776 			}
777 			tuac(p1, p, &rettype, (int *) (&ctype));
778 			putop((int) relops[ r->tag - T_EQ ] , P2INT );
779 			sconv(P2INT, P2CHAR);
780 		    }
781 #		endif PC
782 		c = classify(p);
783 		c1 = classify(p1);
784 		if (nocomp(c) || nocomp(c1))
785 			return (NLNIL);
786 #		ifdef OBJ
787 		    g = NIL;
788 #		endif
789 		switch (c) {
790 			case TBOOL:
791 			case TCHAR:
792 				if (c != c1)
793 					goto clash;
794 				break;
795 			case TINT:
796 			case TDOUBLE:
797 				if (c1 != TINT && c1 != TDOUBLE)
798 					goto clash;
799 				break;
800 			case TSCAL:
801 				if (c1 != TSCAL)
802 					goto clash;
803 				if (scalar(p) != scalar(p1))
804 					goto nonident;
805 				break;
806 			case TSET:
807 				if (c1 != TSET)
808 					goto clash;
809 				if ( opt( 's' ) &&
810 				    ( ( r->tag == T_LT) || (r->tag == T_GT) ) &&
811 				    ( line != nssetline ) ) {
812 				    nssetline = line;
813 				    standard();
814 				    error("%s comparison on sets is non-standard" , opname );
815 				}
816 				if (p != p1)
817 					goto nonident;
818 #				ifdef OBJ
819 				    g = TSET;
820 #				endif
821 				break;
822 			case TREC:
823 				if ( c1 != TREC ) {
824 				    goto clash;
825 				}
826 				if ( p != p1 ) {
827 				    goto nonident;
828 				}
829 				if (r->tag != T_EQ && r->tag != T_NE) {
830 					error("%s not allowed on records - only allow = and <>" , opname );
831 					return (NLNIL);
832 				}
833 #				ifdef OBJ
834 				    g = TREC;
835 #				endif
836 				break;
837 			case TPTR:
838 			case TNIL:
839 				if (c1 != TPTR && c1 != TNIL)
840 					goto clash;
841 				if (r->tag != T_EQ && r->tag != T_NE) {
842 					error("%s not allowed on pointers - only allow = and <>" , opname );
843 					return (NLNIL);
844 				}
845 				if (p != nl+TNIL && p1 != nl+TNIL && p != p1)
846 					goto nonident;
847 				break;
848 			case TSTR:
849 				if (c1 != TSTR)
850 					goto clash;
851 				if (width(p) != width(p1)) {
852 					error("Strings not same length in %s comparison", opname);
853 					return (NLNIL);
854 				}
855 #				ifdef OBJ
856 				    g = TSTR;
857 #				endif OBJ
858 				break;
859 			default:
860 				panic("rval2");
861 		}
862 #		ifdef OBJ
863 		    return (gen(g, r->tag, width(p), width(p1)));
864 #		endif OBJ
865 #		ifdef PC
866 		    return nl + TBOOL;
867 #		endif PC
868 clash:
869 		error("%ss and %ss cannot be compared - operator was %s", clnames[c], clnames[c1], opname);
870 		return (NLNIL);
871 nonident:
872 		error("%s types must be identical in comparisons - operator was %s", clnames[c1], opname);
873 		return (NLNIL);
874 
875 	case T_IN:
876 	    rt = r->expr_node.rhs;
877 #	    ifdef OBJ
878 		if (rt != TR_NIL && rt->tag == T_CSET) {
879 			(void) precset( rt , NLNIL , &csetd );
880 			p1 = csetd.csettype;
881 			if (p1 == NLNIL)
882 			    return NLNIL;
883 			postcset( rt, &csetd);
884 		    } else {
885 			p1 = stkrval(r->expr_node.rhs, NLNIL , (long) RREQ );
886 			rt = TR_NIL;
887 		    }
888 #		endif OBJ
889 #		ifdef PC
890 		    if (rt != TR_NIL && rt->tag == T_CSET) {
891 			if ( precset( rt , NLNIL , &csetd ) ) {
892 			    putleaf( P2ICON , 0 , 0
893 				    , ADDTYPE( P2FTN | P2INT , P2PTR )
894 				    , "_IN" );
895 			} else {
896 			    putleaf( P2ICON , 0 , 0
897 				    , ADDTYPE( P2FTN | P2INT , P2PTR )
898 				    , "_INCT" );
899 			}
900 			p1 = csetd.csettype;
901 			if (p1 == NIL)
902 			    return NLNIL;
903 		    } else {
904 			putleaf( P2ICON , 0 , 0
905 				, ADDTYPE( P2FTN | P2INT , P2PTR )
906 				, "_IN" );
907 			codeoff();
908 			p1 = rvalue(r->expr_node.rhs, NLNIL , LREQ );
909 			codeon();
910 		    }
911 #		endif PC
912 		p = stkrval(r->expr_node.lhs, NLNIL , (long) RREQ );
913 		if (p == NIL || p1 == NIL)
914 			return (NLNIL);
915 		if (p1->class != (char) SET) {
916 			error("Right operand of 'in' must be a set, not %s", nameof(p1));
917 			return (NLNIL);
918 		}
919 		if (incompat(p, p1->type, r->expr_node.lhs)) {
920 			cerror("Index type clashed with set component type for 'in'");
921 			return (NLNIL);
922 		}
923 		setran(p1->type);
924 #		ifdef OBJ
925 		    if (rt == TR_NIL || csetd.comptime)
926 			    (void) put(4, O_IN, width(p1), set.lwrb, set.uprbp);
927 		    else
928 			    (void) put(2, O_INCT,
929 				(int)(3 + csetd.singcnt + 2*csetd.paircnt));
930 #		endif OBJ
931 #		ifdef PC
932 		    if ( rt == TR_NIL || rt->tag != T_CSET ) {
933 			putleaf( P2ICON , set.lwrb , 0 , P2INT , (char *) 0 );
934 			putop( P2LISTOP , P2INT );
935 			putleaf( P2ICON , set.uprbp , 0 , P2INT , (char *) 0 );
936 			putop( P2LISTOP , P2INT );
937 			p1 = rvalue( r->expr_node.rhs , NLNIL , LREQ );
938 			if ( p1 == NLNIL ) {
939 			    return NLNIL;
940 			}
941 			putop( P2LISTOP , P2INT );
942 		    } else if ( csetd.comptime ) {
943 			putleaf( P2ICON , set.lwrb , 0 , P2INT , (char *) 0 );
944 			putop( P2LISTOP , P2INT );
945 			putleaf( P2ICON , set.uprbp , 0 , P2INT , (char *) 0 );
946 			putop( P2LISTOP , P2INT );
947 			postcset( r->expr_node.rhs , &csetd );
948 			putop( P2LISTOP , P2INT );
949 		    } else {
950 			postcset( r->expr_node.rhs , &csetd );
951 		    }
952 		    putop( P2CALL , P2INT );
953 		    sconv(P2INT, P2CHAR);
954 #		endif PC
955 		return (nl+T1BOOL);
956 	default:
957 		if (r->expr_node.lhs == TR_NIL)
958 			return (NLNIL);
959 		switch (r->tag) {
960 		default:
961 			panic("rval3");
962 
963 
964 		/*
965 		 * An octal number
966 		 */
967 		case T_BINT:
968 			f.pdouble = a8tol(r->const_node.cptr);
969 			goto conint;
970 
971 		/*
972 		 * A decimal number
973 		 */
974 		case T_INT:
975 			f.pdouble = atof(r->const_node.cptr);
976 conint:
977 			if (f.pdouble > MAXINT || f.pdouble < MININT) {
978 				error("Constant too large for this implementation");
979 				return (NLNIL);
980 			}
981 			l = f.pdouble;
982 #			ifdef OBJ
983 			    if (bytes(l, l) <= 2) {
984 				    (void) put(2, O_CON2, ( short ) l);
985 				    return (nl+T2INT);
986 			    }
987 			    (void) put(2, O_CON4, l);
988 			    return (nl+T4INT);
989 #			endif OBJ
990 #			ifdef PC
991 			    switch (bytes(l, l)) {
992 				case 1:
993 				    putleaf(P2ICON, (int) l, 0, P2CHAR,
994 						(char *) 0);
995 				    return nl+T1INT;
996 				case 2:
997 				    putleaf(P2ICON, (int) l, 0, P2SHORT,
998 						(char *) 0);
999 				    return nl+T2INT;
1000 				case 4:
1001 				    putleaf(P2ICON, (int) l, 0, P2INT,
1002 						(char *) 0);
1003 				    return nl+T4INT;
1004 			    }
1005 #			endif PC
1006 
1007 		/*
1008 		 * A floating point number
1009 		 */
1010 		case T_FINT:
1011 #			ifdef OBJ
1012 			    (void) put(2, O_CON8, atof(r->const_node.cptr));
1013 #			endif OBJ
1014 #			ifdef PC
1015 			    putCON8( atof( r->const_node.cptr ) );
1016 #			endif PC
1017 			return (nl+TDOUBLE);
1018 
1019 		/*
1020 		 * Constant strings.  Note that constant characters
1021 		 * are constant strings of length one; there is
1022 		 * no constant string of length one.
1023 		 */
1024 		case T_STRNG:
1025 			cp = r->const_node.cptr;
1026 			if (cp[1] == 0) {
1027 #				ifdef OBJ
1028 				    (void) put(2, O_CONC, cp[0]);
1029 #				endif OBJ
1030 #				ifdef PC
1031 				    putleaf( P2ICON , cp[0] , 0 , P2CHAR ,
1032 						(char *) 0 );
1033 #				endif PC
1034 				return (nl+T1CHAR);
1035 			}
1036 			goto cstrng;
1037 		}
1038 
1039 	}
1040 }
1041 
1042 /*
1043  * Can a class appear
1044  * in a comparison ?
1045  */
1046 nocomp(c)
1047 	int c;
1048 {
1049 
1050 	switch (c) {
1051 		case TREC:
1052 			if ( line != reccompline ) {
1053 			    reccompline = line;
1054 			    warning();
1055 			    if ( opt( 's' ) ) {
1056 				standard();
1057 			    }
1058 			    error("record comparison is non-standard");
1059 			}
1060 			break;
1061 		case TFILE:
1062 		case TARY:
1063 			error("%ss may not participate in comparisons", clnames[c]);
1064 			return (1);
1065 	}
1066 	return (NIL);
1067 }
1068 
1069     /*
1070      *	this is sort of like gconst, except it works on expression trees
1071      *	rather than declaration trees, and doesn't give error messages for
1072      *	non-constant things.
1073      *	as a side effect this fills in the con structure that gconst uses.
1074      *	this returns TRUE or FALSE.
1075      */
1076 
1077 bool
1078 constval(r)
1079 	register struct tnode *r;
1080 {
1081 	register struct nl *np;
1082 	register struct tnode *cn;
1083 	char *cp;
1084 	int negd, sgnd;
1085 	long ci;
1086 
1087 	con.ctype = NIL;
1088 	cn = r;
1089 	negd = sgnd = 0;
1090 loop:
1091 	    /*
1092 	     *	cn[2] is nil if error recovery generated a T_STRNG
1093 	     */
1094 	if (cn == TR_NIL || cn->expr_node.lhs == TR_NIL)
1095 		return FALSE;
1096 	switch (cn->tag) {
1097 		default:
1098 			return FALSE;
1099 		case T_MINUS:
1100 			negd = 1 - negd;
1101 			/* and fall through */
1102 		case T_PLUS:
1103 			sgnd++;
1104 			cn = cn->un_expr.expr;
1105 			goto loop;
1106 		case T_NIL:
1107 			con.cpval = NIL;
1108 			con.cival = 0;
1109 			con.crval = con.cival;
1110 			con.ctype = nl + TNIL;
1111 			break;
1112 		case T_VAR:
1113 			np = lookup(cn->var_node.cptr);
1114 			if (np == NLNIL || np->class != CONST) {
1115 				return FALSE;
1116 			}
1117 			if ( cn->var_node.qual != TR_NIL ) {
1118 				return FALSE;
1119 			}
1120 			con.ctype = np->type;
1121 			switch (classify(np->type)) {
1122 				case TINT:
1123 					con.crval = np->range[0];
1124 					break;
1125 				case TDOUBLE:
1126 					con.crval = np->real;
1127 					break;
1128 				case TBOOL:
1129 				case TCHAR:
1130 				case TSCAL:
1131 					con.cival = np->value[0];
1132 					con.crval = con.cival;
1133 					break;
1134 				case TSTR:
1135 					con.cpval = (char *) np->ptr[0];
1136 					break;
1137 				default:
1138 					con.ctype = NIL;
1139 					return FALSE;
1140 			}
1141 			break;
1142 		case T_BINT:
1143 			con.crval = a8tol(cn->const_node.cptr);
1144 			goto restcon;
1145 		case T_INT:
1146 			con.crval = atof(cn->const_node.cptr);
1147 			if (con.crval > MAXINT || con.crval < MININT) {
1148 				derror("Constant too large for this implementation");
1149 				con.crval = 0;
1150 			}
1151 restcon:
1152 			ci = con.crval;
1153 #ifndef PI0
1154 			if (bytes(ci, ci) <= 2)
1155 				con.ctype = nl+T2INT;
1156 			else
1157 #endif
1158 				con.ctype = nl+T4INT;
1159 			break;
1160 		case T_FINT:
1161 			con.ctype = nl+TDOUBLE;
1162 			con.crval = atof(cn->const_node.cptr);
1163 			break;
1164 		case T_STRNG:
1165 			cp = cn->const_node.cptr;
1166 			if (cp[1] == 0) {
1167 				con.ctype = nl+T1CHAR;
1168 				con.cival = cp[0];
1169 				con.crval = con.cival;
1170 				break;
1171 			}
1172 			con.ctype = nl+TSTR;
1173 			con.cpval = cp;
1174 			break;
1175 	}
1176 	if (sgnd) {
1177 		if (isnta(con.ctype, "id")) {
1178 			derror("%s constants cannot be signed", nameof(con.ctype));
1179 			return FALSE;
1180 		} else if (negd)
1181 			con.crval = -con.crval;
1182 	}
1183 	return TRUE;
1184 }
1185