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