1771Speter /* Copyright (c) 1979 Regents of the University of California */ 2771Speter 315931Smckusick ifndef lint 4*15937Smckusick static char sccsid[] = "@(#)rval.c 1.19 02/04/84"; 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" 14771Speter # include "pcops.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[] = { 38771Speter P2EQ , P2NE , 39771Speter P2LT , P2GT , 40771Speter P2LE , P2GE 41771Speter }; 42771Speter long mathop[] = { P2MUL , P2PLUS , P2MINUS }; 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 49771Speter * if constant sets or constant strings are involved, the latter 50771Speter * because of string padding. 51771Speter * required is a flag whether an lvalue or an rvalue is required. 52771Speter * only VARs and structured things can have gt their lvalue this way. 53771Speter */ 5415931Smckusick /*ARGSUSED*/ 55771Speter struct nl * 56771Speter rvalue(r, contype , required ) 5715931Smckusick struct tnode *r; 58771Speter struct nl *contype; 59771Speter int required; 60771Speter { 61771Speter register struct nl *p, *p1; 62771Speter register struct nl *q; 6315931Smckusick int c, c1, w; 6415931Smckusick #ifdef OBJ 6515931Smckusick int g; 6615931Smckusick #endif 6715931Smckusick struct tnode *rt; 68771Speter char *cp, *cp1, *opname; 69771Speter long l; 7015931Smckusick union 7115931Smckusick { 7215931Smckusick long plong[2]; 7315931Smckusick double pdouble; 7415931Smckusick }f; 75771Speter extern int flagwas; 76771Speter struct csetstr csetd; 77771Speter # ifdef PC 78771Speter struct nl *rettype; 79771Speter long ctype; 803834Speter struct nl *tempnlp; 81771Speter # endif PC 82771Speter 8315931Smckusick if (r == TR_NIL) 8415931Smckusick return (NLNIL); 85771Speter if (nowexp(r)) 8615931Smckusick return (NLNIL); 87771Speter /* 88771Speter * Pick up the name of the operation 89771Speter * for future error messages. 90771Speter */ 9115931Smckusick if (r->tag <= T_IN) 9215931Smckusick opname = opnames[r->tag]; 93771Speter 94771Speter /* 95771Speter * The root of the tree tells us what sort of expression we have. 96771Speter */ 9715931Smckusick switch (r->tag) { 98771Speter 99771Speter /* 100771Speter * The constant nil 101771Speter */ 102771Speter case T_NIL: 103771Speter # ifdef OBJ 10415931Smckusick (void) put(2, O_CON2, 0); 105771Speter # endif OBJ 106771Speter # ifdef PC 10715931Smckusick putleaf( P2ICON , 0 , 0 , P2PTR|P2UNDEF , (char *) 0 ); 108771Speter # endif PC 109771Speter return (nl+TNIL); 110771Speter 111771Speter /* 112771Speter * Function call with arguments. 113771Speter */ 114771Speter case T_FCALL: 115771Speter # ifdef OBJ 116771Speter return (funccod(r)); 117771Speter # endif OBJ 118771Speter # ifdef PC 119771Speter return (pcfunccod( r )); 120771Speter # endif PC 121771Speter 122771Speter case T_VAR: 12315931Smckusick p = lookup(r->var_node.cptr); 12415931Smckusick if (p == NLNIL || p->class == BADUSE) 12515931Smckusick return (NLNIL); 126771Speter switch (p->class) { 127771Speter case VAR: 128771Speter /* 129771Speter * If a variable is 130771Speter * qualified then get 131771Speter * the rvalue by a 132771Speter * lvalue and an ind. 133771Speter */ 13415931Smckusick if (r->var_node.qual != TR_NIL) 135771Speter goto ind; 136771Speter q = p->type; 137771Speter if (q == NIL) 13815931Smckusick return (NLNIL); 139771Speter # ifdef OBJ 140771Speter w = width(q); 141771Speter switch (w) { 142771Speter case 8: 14315931Smckusick (void) put(2, O_RV8 | bn << 8+INDX, 1443078Smckusic (int)p->value[0]); 145771Speter break; 146771Speter case 4: 14715931Smckusick (void) put(2, O_RV4 | bn << 8+INDX, 1483078Smckusic (int)p->value[0]); 149771Speter break; 150771Speter case 2: 15115931Smckusick (void) put(2, O_RV2 | bn << 8+INDX, 1523078Smckusic (int)p->value[0]); 153771Speter break; 154771Speter case 1: 15515931Smckusick (void) put(2, O_RV1 | bn << 8+INDX, 1563078Smckusic (int)p->value[0]); 157771Speter break; 158771Speter default: 15915931Smckusick (void) put(3, O_RV | bn << 8+INDX, 1603078Smckusic (int)p->value[0], w); 161771Speter } 162771Speter # endif OBJ 163771Speter # ifdef PC 164771Speter if ( required == RREQ ) { 1653834Speter putRV( p -> symbol , bn , p -> value[0] , 1663834Speter p -> extra_flags , p2type( q ) ); 167771Speter } else { 1683834Speter putLV( p -> symbol , bn , p -> value[0] , 1693834Speter p -> extra_flags , p2type( q ) ); 170771Speter } 171771Speter # endif PC 172771Speter return (q); 173771Speter 174771Speter case WITHPTR: 175771Speter case REF: 176771Speter /* 177771Speter * A lvalue for these 178771Speter * is actually what one 179771Speter * might consider a rvalue. 180771Speter */ 181771Speter ind: 182771Speter q = lvalue(r, NOFLAGS , LREQ ); 183771Speter if (q == NIL) 18415931Smckusick return (NLNIL); 185771Speter # ifdef OBJ 186771Speter w = width(q); 187771Speter switch (w) { 188771Speter case 8: 18915931Smckusick (void) put(1, O_IND8); 190771Speter break; 191771Speter case 4: 19215931Smckusick (void) put(1, O_IND4); 193771Speter break; 194771Speter case 2: 19515931Smckusick (void) put(1, O_IND2); 196771Speter break; 197771Speter case 1: 19815931Smckusick (void) put(1, O_IND1); 199771Speter break; 200771Speter default: 20115931Smckusick (void) put(2, O_IND, w); 202771Speter } 203771Speter # endif OBJ 204771Speter # ifdef PC 205771Speter if ( required == RREQ ) { 206771Speter putop( P2UNARY P2MUL , p2type( q ) ); 207771Speter } 208771Speter # endif PC 209771Speter return (q); 210771Speter 211771Speter case CONST: 21215931Smckusick if (r->var_node.qual != TR_NIL) { 21315931Smckusick error("%s is a constant and cannot be qualified", r->var_node.cptr); 21415931Smckusick return (NLNIL); 215771Speter } 216771Speter q = p->type; 21715931Smckusick if (q == NLNIL) 21815931Smckusick return (NLNIL); 219771Speter if (q == nl+TSTR) { 220771Speter /* 221771Speter * Find the size of the string 222771Speter * constant if needed. 223771Speter */ 22415931Smckusick cp = (char *) p->ptr[0]; 225771Speter cstrng: 226771Speter cp1 = cp; 227771Speter for (c = 0; *cp++; c++) 228771Speter continue; 2293078Smckusic w = c; 230771Speter if (contype != NIL && !opt('s')) { 231771Speter if (width(contype) < c && classify(contype) == TSTR) { 232771Speter error("Constant string too long"); 23315931Smckusick return (NLNIL); 234771Speter } 2353078Smckusic w = width(contype); 236771Speter } 237771Speter # ifdef OBJ 23815931Smckusick (void) put(2, O_CONG, w); 2393078Smckusic putstr(cp1, w - c); 240771Speter # endif OBJ 241771Speter # ifdef PC 2423155Smckusic putCONG( cp1 , w , required ); 243771Speter # endif PC 244771Speter /* 245771Speter * Define the string temporarily 246771Speter * so later people can know its 247771Speter * width. 248771Speter * cleaned out by stat. 249771Speter */ 25015931Smckusick q = defnl((char *) 0, STR, NLNIL, w); 251771Speter q->type = q; 252771Speter return (q); 253771Speter } 254771Speter if (q == nl+T1CHAR) { 255771Speter # ifdef OBJ 25615931Smckusick (void) put(2, O_CONC, (int)p->value[0]); 257771Speter # endif OBJ 258771Speter # ifdef PC 259771Speter putleaf( P2ICON , p -> value[0] , 0 26015931Smckusick , P2CHAR , (char *) 0 ); 261771Speter # endif PC 262771Speter return (q); 263771Speter } 264771Speter /* 265771Speter * Every other kind of constant here 266771Speter */ 267771Speter switch (width(q)) { 268771Speter case 8: 269771Speter #ifndef DEBUG 270771Speter # ifdef OBJ 27115931Smckusick (void) put(2, O_CON8, p->real); 272771Speter # endif OBJ 273771Speter # ifdef PC 274771Speter putCON8( p -> real ); 275771Speter # endif PC 276771Speter #else 277771Speter if (hp21mx) { 27815931Smckusick f.pdouble = p->real; 27915931Smckusick conv((int *) (&f.pdouble)); 28015931Smckusick l = f.plong[1]; 28115931Smckusick (void) put(2, O_CON4, l); 282771Speter } else 283771Speter # ifdef OBJ 28415931Smckusick (void) put(2, O_CON8, p->real); 285771Speter # endif OBJ 286771Speter # ifdef PC 287771Speter putCON8( p -> real ); 288771Speter # endif PC 289771Speter #endif 290771Speter break; 291771Speter case 4: 292771Speter # ifdef OBJ 29315931Smckusick (void) put(2, O_CON4, p->range[0]); 294771Speter # endif OBJ 295771Speter # ifdef PC 29615931Smckusick putleaf( P2ICON , (int) p->range[0] , 0 29715931Smckusick , P2INT , (char *) 0 ); 298771Speter # endif PC 299771Speter break; 300771Speter case 2: 301771Speter # ifdef OBJ 30215931Smckusick (void) put(2, O_CON2, (short)p->range[0]); 303771Speter # endif OBJ 304771Speter # ifdef PC 305771Speter putleaf( P2ICON , (short) p -> range[0] 30615931Smckusick , 0 , P2SHORT , (char *) 0 ); 307771Speter # endif PC 308771Speter break; 309771Speter case 1: 310771Speter # ifdef OBJ 31115931Smckusick (void) put(2, O_CON1, p->value[0]); 312771Speter # endif OBJ 313771Speter # ifdef PC 314771Speter putleaf( P2ICON , p -> value[0] , 0 31515931Smckusick , P2CHAR , (char *) 0 ); 316771Speter # endif PC 317771Speter break; 318771Speter default: 319771Speter panic("rval"); 320771Speter } 321771Speter return (q); 322771Speter 323771Speter case FUNC: 3241200Speter case FFUNC: 325771Speter /* 326771Speter * Function call with no arguments. 327771Speter */ 32815931Smckusick if (r->var_node.qual != TR_NIL) { 329771Speter error("Can't qualify a function result value"); 33015931Smckusick return (NLNIL); 331771Speter } 332771Speter # ifdef OBJ 33315931Smckusick return (funccod(r)); 334771Speter # endif OBJ 335771Speter # ifdef PC 336771Speter return (pcfunccod( r )); 337771Speter # endif PC 338771Speter 339771Speter case TYPE: 340771Speter error("Type names (e.g. %s) allowed only in declarations", p->symbol); 34115931Smckusick return (NLNIL); 342771Speter 343771Speter case PROC: 3441200Speter case FPROC: 345771Speter error("Procedure %s found where expression required", p->symbol); 34615931Smckusick return (NLNIL); 347771Speter default: 348771Speter panic("rvid"); 349771Speter } 350771Speter /* 351771Speter * Constant sets 352771Speter */ 353771Speter case T_CSET: 354771Speter # ifdef OBJ 355771Speter if ( precset( r , contype , &csetd ) ) { 356771Speter if ( csetd.csettype == NIL ) { 35715931Smckusick return (NLNIL); 358771Speter } 359771Speter postcset( r , &csetd ); 360771Speter } else { 36115931Smckusick (void) put( 2, O_PUSH, -lwidth(csetd.csettype)); 362771Speter postcset( r , &csetd ); 363771Speter setran( ( csetd.csettype ) -> type ); 36415931Smckusick (void) put( 2, O_CON24, set.uprbp); 36515931Smckusick (void) put( 2, O_CON24, set.lwrb); 36615931Smckusick (void) put( 2, O_CTTOT, 3673078Smckusic (int)(4 + csetd.singcnt + 2 * csetd.paircnt)); 368771Speter } 369771Speter return csetd.csettype; 370771Speter # endif OBJ 371771Speter # ifdef PC 372771Speter if ( precset( r , contype , &csetd ) ) { 373771Speter if ( csetd.csettype == NIL ) { 37415931Smckusick return (NLNIL); 375771Speter } 376771Speter postcset( r , &csetd ); 377771Speter } else { 378771Speter putleaf( P2ICON , 0 , 0 379771Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 380771Speter , "_CTTOT" ); 381771Speter /* 382771Speter * allocate a temporary and use it 383771Speter */ 3843834Speter tempnlp = tmpalloc(lwidth(csetd.csettype), 3853227Smckusic csetd.csettype, NOREG); 38615931Smckusick putLV( (char *) 0 , cbn , tempnlp -> value[ NL_OFFS ] , 3873834Speter tempnlp -> extra_flags , P2PTR|P2STRTY ); 388771Speter setran( ( csetd.csettype ) -> type ); 38915931Smckusick putleaf( P2ICON , set.lwrb , 0 , P2INT , (char *) 0 ); 390771Speter putop( P2LISTOP , P2INT ); 39115931Smckusick putleaf( P2ICON , set.uprbp , 0 , P2INT , (char *) 0 ); 392771Speter putop( P2LISTOP , P2INT ); 393771Speter postcset( r , &csetd ); 394771Speter putop( P2CALL , P2INT ); 395771Speter } 396771Speter return csetd.csettype; 397771Speter # endif PC 398771Speter 399771Speter /* 400771Speter * Unary plus and minus 401771Speter */ 402771Speter case T_PLUS: 403771Speter case T_MINUS: 40415931Smckusick q = rvalue(r->un_expr.expr, NLNIL , RREQ ); 40515931Smckusick if (q == NLNIL) 40615931Smckusick return (NLNIL); 407771Speter if (isnta(q, "id")) { 408771Speter error("Operand of %s must be integer or real, not %s", opname, nameof(q)); 40915931Smckusick return (NLNIL); 410771Speter } 41115931Smckusick if (r->tag == T_MINUS) { 412771Speter # ifdef OBJ 41315931Smckusick (void) put(1, O_NEG2 + (width(q) >> 2)); 41410670Speter return (isa(q, "d") ? q : nl+T4INT); 415771Speter # endif OBJ 416771Speter # ifdef PC 41710670Speter if (isa(q, "i")) { 41810670Speter sconv(p2type(q), P2INT); 41910670Speter putop( P2UNARY P2MINUS, P2INT); 42010670Speter return nl+T4INT; 42110670Speter } 42210670Speter putop( P2UNARY P2MINUS, P2DOUBLE); 42310670Speter return nl+TDOUBLE; 424771Speter # endif PC 425771Speter } 426771Speter return (q); 427771Speter 428771Speter case T_NOT: 42915931Smckusick q = rvalue(r->un_expr.expr, NLNIL , RREQ ); 43015931Smckusick if (q == NLNIL) 43115931Smckusick return (NLNIL); 432771Speter if (isnta(q, "b")) { 433771Speter error("not must operate on a Boolean, not %s", nameof(q)); 43415931Smckusick return (NLNIL); 435771Speter } 436771Speter # ifdef OBJ 43715931Smckusick (void) put(1, O_NOT); 438771Speter # endif OBJ 439771Speter # ifdef PC 44010364Smckusick sconv(p2type(q), P2INT); 44110364Smckusick putop( P2NOT , P2INT); 44210364Smckusick sconv(P2INT, p2type(q)); 443771Speter # endif PC 444771Speter return (nl+T1BOOL); 445771Speter 446771Speter case T_AND: 447771Speter case T_OR: 44815931Smckusick p = rvalue(r->expr_node.lhs, NLNIL , RREQ ); 44910364Smckusick # ifdef PC 45010364Smckusick sconv(p2type(p),P2INT); 45110364Smckusick # endif PC 45215931Smckusick p1 = rvalue(r->expr_node.rhs, NLNIL , RREQ ); 45310364Smckusick # ifdef PC 45410364Smckusick sconv(p2type(p1),P2INT); 45510364Smckusick # endif PC 45615931Smckusick if (p == NLNIL || p1 == NLNIL) 45715931Smckusick return (NLNIL); 458771Speter if (isnta(p, "b")) { 459771Speter error("Left operand of %s must be Boolean, not %s", opname, nameof(p)); 46015931Smckusick return (NLNIL); 461771Speter } 462771Speter if (isnta(p1, "b")) { 463771Speter error("Right operand of %s must be Boolean, not %s", opname, nameof(p1)); 46415931Smckusick return (NLNIL); 465771Speter } 466771Speter # ifdef OBJ 46715931Smckusick (void) put(1, r->tag == T_AND ? O_AND : O_OR); 468771Speter # endif OBJ 469771Speter # ifdef PC 470771Speter /* 471771Speter * note the use of & and | rather than && and || 472771Speter * to force evaluation of all the expressions. 473771Speter */ 47415931Smckusick putop( r->tag == T_AND ? P2AND : P2OR , P2INT ); 47510364Smckusick sconv(P2INT, p2type(p)); 476771Speter # endif PC 477771Speter return (nl+T1BOOL); 478771Speter 479771Speter case T_DIVD: 480771Speter # ifdef OBJ 48115931Smckusick p = rvalue(r->expr_node.lhs, NLNIL , RREQ ); 48215931Smckusick p1 = rvalue(r->expr_node.rhs, NLNIL , RREQ ); 483771Speter # endif OBJ 484771Speter # ifdef PC 485771Speter /* 486771Speter * force these to be doubles for the divide 487771Speter */ 48815931Smckusick p = rvalue( r->expr_node.lhs , NLNIL , RREQ ); 48910364Smckusick sconv(p2type(p), P2DOUBLE); 49015931Smckusick p1 = rvalue( r->expr_node.rhs , NLNIL , RREQ ); 49110364Smckusick sconv(p2type(p1), P2DOUBLE); 492771Speter # endif PC 49315931Smckusick if (p == NLNIL || p1 == NLNIL) 49415931Smckusick return (NLNIL); 495771Speter if (isnta(p, "id")) { 496771Speter error("Left operand of / must be integer or real, not %s", nameof(p)); 49715931Smckusick return (NLNIL); 498771Speter } 499771Speter if (isnta(p1, "id")) { 500771Speter error("Right operand of / must be integer or real, not %s", nameof(p1)); 50115931Smckusick return (NLNIL); 502771Speter } 503771Speter # ifdef OBJ 50415931Smckusick return gen(NIL, r->tag, width(p), width(p1)); 505771Speter # endif OBJ 506771Speter # ifdef PC 507771Speter putop( P2DIV , P2DOUBLE ); 508771Speter return nl + TDOUBLE; 509771Speter # endif PC 510771Speter 511771Speter case T_MULT: 512771Speter case T_ADD: 513771Speter case T_SUB: 514771Speter # ifdef OBJ 515771Speter /* 5161555Speter * If the context hasn't told us the type 5171555Speter * and a constant set is present 5181555Speter * we need to infer the type 5191555Speter * before generating code. 520771Speter */ 521*15937Smckusick if ( contype == NLNIL ) { 522771Speter codeoff(); 52315931Smckusick contype = rvalue( r->expr_node.rhs , NLNIL , RREQ ); 524771Speter codeon(); 525771Speter } 526*15937Smckusick if ( contype == NLNIL ) { 52715931Smckusick return NLNIL; 5281555Speter } 52915931Smckusick p = rvalue( r->expr_node.lhs , contype , RREQ ); 53015931Smckusick p1 = rvalue( r->expr_node.rhs , p , RREQ ); 531*15937Smckusick if ( p == NLNIL || p1 == NLNIL ) 53215931Smckusick return NLNIL; 533771Speter if (isa(p, "id") && isa(p1, "id")) 53415931Smckusick return (gen(NIL, r->tag, width(p), width(p1))); 535771Speter if (isa(p, "t") && isa(p1, "t")) { 536771Speter if (p != p1) { 537771Speter error("Set types of operands of %s must be identical", opname); 53815931Smckusick return (NLNIL); 539771Speter } 54015931Smckusick (void) gen(TSET, r->tag, width(p), 0); 541771Speter return (p); 542771Speter } 543771Speter # endif OBJ 544771Speter # ifdef PC 545771Speter /* 546771Speter * the second pass can't do 547771Speter * long op double or double op long 548771Speter * so we have to know the type of both operands 549771Speter * also, it gets tricky for sets, which are done 550771Speter * by function calls. 551771Speter */ 552771Speter codeoff(); 55315931Smckusick p1 = rvalue( r->expr_node.rhs , contype , RREQ ); 554771Speter codeon(); 555771Speter if ( isa( p1 , "id" ) ) { 55615931Smckusick p = rvalue( r->expr_node.lhs , contype , RREQ ); 557*15937Smckusick if ( ( p == NLNIL ) || ( p1 == NLNIL ) ) { 55815931Smckusick return NLNIL; 559771Speter } 56015931Smckusick tuac(p, p1, &rettype, (int *) (&ctype)); 56115931Smckusick p1 = rvalue( r->expr_node.rhs , contype , RREQ ); 56215931Smckusick tuac(p1, p, &rettype, (int *) (&ctype)); 563771Speter if ( isa( p , "id" ) ) { 56415931Smckusick putop( (int) mathop[r->tag - T_MULT], (int) ctype); 565771Speter return rettype; 566771Speter } 567771Speter } 568771Speter if ( isa( p1 , "t" ) ) { 569771Speter putleaf( P2ICON , 0 , 0 570771Speter , ADDTYPE( ADDTYPE( P2PTR | P2STRTY , P2FTN ) 571771Speter , P2PTR ) 57215931Smckusick , setop[ r->tag - T_MULT ] ); 573*15937Smckusick if ( contype == NLNIL ) { 574*15937Smckusick codeoff(); 575*15937Smckusick contype = rvalue( r->expr_node.lhs, p1 , LREQ ); 576*15937Smckusick codeon(); 5771555Speter } 578*15937Smckusick if ( contype == NLNIL ) { 57915931Smckusick return NLNIL; 5801555Speter } 5811555Speter /* 5821555Speter * allocate a temporary and use it 5831555Speter */ 5843834Speter tempnlp = tmpalloc(lwidth(contype), contype, NOREG); 58515931Smckusick putLV((char *) 0 , cbn , tempnlp -> value[ NL_OFFS ] , 5863834Speter tempnlp -> extra_flags , P2PTR|P2STRTY ); 58715931Smckusick p = rvalue( r->expr_node.lhs , contype , LREQ ); 588771Speter if ( isa( p , "t" ) ) { 589771Speter putop( P2LISTOP , P2INT ); 590*15937Smckusick if ( p == NLNIL || p1 == NLNIL ) { 59115931Smckusick return NLNIL; 592771Speter } 59315931Smckusick p1 = rvalue( r->expr_node.rhs , p , LREQ ); 594771Speter if ( p != p1 ) { 595771Speter error("Set types of operands of %s must be identical", opname); 59615931Smckusick return NLNIL; 597771Speter } 598771Speter putop( P2LISTOP , P2INT ); 59915931Smckusick putleaf( P2ICON , (int) (lwidth(p1)) / sizeof( long ) , 0 60015931Smckusick , P2INT , (char *) 0 ); 601771Speter putop( P2LISTOP , P2INT ); 602771Speter putop( P2CALL , P2PTR | P2STRTY ); 603771Speter return p; 604771Speter } 605771Speter } 606771Speter if ( isnta( p1 , "idt" ) ) { 607771Speter /* 608771Speter * find type of left operand for error message. 609771Speter */ 61015931Smckusick p = rvalue( r->expr_node.lhs , contype , RREQ ); 611771Speter } 612771Speter /* 613771Speter * don't give spurious error messages. 614771Speter */ 615*15937Smckusick if ( p == NLNIL || p1 == NLNIL ) { 61615931Smckusick return NLNIL; 617771Speter } 618771Speter # endif PC 619771Speter if (isnta(p, "idt")) { 620771Speter error("Left operand of %s must be integer, real or set, not %s", opname, nameof(p)); 62115931Smckusick return (NLNIL); 622771Speter } 623771Speter if (isnta(p1, "idt")) { 624771Speter error("Right operand of %s must be integer, real or set, not %s", opname, nameof(p1)); 62515931Smckusick return (NLNIL); 626771Speter } 627771Speter error("Cannot mix sets with integers and reals as operands of %s", opname); 62815931Smckusick return (NLNIL); 629771Speter 630771Speter case T_MOD: 631771Speter case T_DIV: 63215931Smckusick p = rvalue(r->expr_node.lhs, NLNIL , RREQ ); 63310364Smckusick # ifdef PC 63410364Smckusick sconv(p2type(p), P2INT); 63510364Smckusick # endif PC 63615931Smckusick p1 = rvalue(r->expr_node.rhs, NLNIL , RREQ ); 63710364Smckusick # ifdef PC 63810364Smckusick sconv(p2type(p1), P2INT); 63910364Smckusick # endif PC 640*15937Smckusick if (p == NLNIL || p1 == NLNIL) 64115931Smckusick return (NLNIL); 642771Speter if (isnta(p, "i")) { 643771Speter error("Left operand of %s must be integer, not %s", opname, nameof(p)); 64415931Smckusick return (NLNIL); 645771Speter } 646771Speter if (isnta(p1, "i")) { 647771Speter error("Right operand of %s must be integer, not %s", opname, nameof(p1)); 64815931Smckusick return (NLNIL); 649771Speter } 650771Speter # ifdef OBJ 65115931Smckusick return (gen(NIL, r->tag, width(p), width(p1))); 652771Speter # endif OBJ 653771Speter # ifdef PC 65415931Smckusick putop( r->tag == T_DIV ? P2DIV : P2MOD , P2INT ); 655771Speter return ( nl + T4INT ); 656771Speter # endif PC 657771Speter 658771Speter case T_EQ: 659771Speter case T_NE: 660771Speter case T_LT: 661771Speter case T_GT: 662771Speter case T_LE: 663771Speter case T_GE: 664771Speter /* 665771Speter * Since there can be no, a priori, knowledge 666771Speter * of the context type should a constant string 667771Speter * or set arise, we must poke around to find such 668771Speter * a type if possible. Since constant strings can 669771Speter * always masquerade as identifiers, this is always 670771Speter * necessary. 671771Speter */ 672771Speter codeoff(); 67315931Smckusick p1 = rvalue(r->expr_node.rhs, NLNIL , RREQ ); 674771Speter codeon(); 67515931Smckusick if (p1 == NLNIL) 67615931Smckusick return (NLNIL); 677771Speter contype = p1; 678771Speter # ifdef OBJ 6791555Speter if (p1->class == STR) { 680771Speter /* 681771Speter * For constant strings we want 682771Speter * the longest type so as to be 683771Speter * able to do padding (more importantly 684771Speter * avoiding truncation). For clarity, 685771Speter * we get this length here. 686771Speter */ 687771Speter codeoff(); 68815931Smckusick p = rvalue(r->expr_node.lhs, NLNIL , RREQ ); 689771Speter codeon(); 69015931Smckusick if (p == NLNIL) 69115931Smckusick return (NLNIL); 6921555Speter if (width(p) > width(p1)) 693771Speter contype = p; 694771Speter } 695771Speter /* 696771Speter * Now we generate code for 697771Speter * the operands of the relational 698771Speter * operation. 699771Speter */ 70015931Smckusick p = rvalue(r->expr_node.lhs, contype , RREQ ); 70115931Smckusick if (p == NLNIL) 70215931Smckusick return (NLNIL); 70315931Smckusick p1 = rvalue(r->expr_node.rhs, p , RREQ ); 70415931Smckusick if (p1 == NLNIL) 70515931Smckusick return (NLNIL); 706771Speter # endif OBJ 707771Speter # ifdef PC 708771Speter c1 = classify( p1 ); 709771Speter if ( c1 == TSET || c1 == TSTR || c1 == TREC ) { 710771Speter putleaf( P2ICON , 0 , 0 711771Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 71215931Smckusick , c1 == TSET ? relts[ r->tag - T_EQ ] 71315931Smckusick : relss[ r->tag - T_EQ ] ); 714771Speter /* 715771Speter * for [] and strings, comparisons are done on 716771Speter * the maximum width of the two sides. 717771Speter * for other sets, we have to ask the left side 718771Speter * what type it is based on the type of the right. 719771Speter * (this matters for intsets). 720771Speter */ 7211555Speter if ( c1 == TSTR ) { 722771Speter codeoff(); 72315931Smckusick p = rvalue( r->expr_node.lhs , NLNIL , LREQ ); 724771Speter codeon(); 72515931Smckusick if ( p == NLNIL ) { 72615931Smckusick return NLNIL; 7271555Speter } 7281555Speter if ( lwidth( p ) > lwidth( p1 ) ) { 729771Speter contype = p; 730771Speter } 7311555Speter } else if ( c1 == TSET ) { 732*15937Smckusick codeoff(); 733*15937Smckusick p = rvalue( r->expr_node.lhs , contype , LREQ ); 734*15937Smckusick codeon(); 735*15937Smckusick if ( p == NLNIL ) { 736*15937Smckusick return NLNIL; 7371555Speter } 738*15937Smckusick contype = p; 7391627Speter } 740771Speter /* 741771Speter * put out the width of the comparison. 742771Speter */ 74315931Smckusick putleaf(P2ICON, (int) lwidth(contype), 0, P2INT, (char *) 0); 744771Speter /* 745771Speter * and the left hand side, 746771Speter * for sets, strings, records 747771Speter */ 74815931Smckusick p = rvalue( r->expr_node.lhs , contype , LREQ ); 74915931Smckusick if ( p == NLNIL ) { 75015931Smckusick return NLNIL; 7515413Speter } 752771Speter putop( P2LISTOP , P2INT ); 75315931Smckusick p1 = rvalue( r->expr_node.rhs , p , LREQ ); 75415931Smckusick if ( p1 == NLNIL ) { 75515931Smckusick return NLNIL; 7565413Speter } 757771Speter putop( P2LISTOP , P2INT ); 758771Speter putop( P2CALL , P2INT ); 759771Speter } else { 760771Speter /* 761771Speter * the easy (scalar or error) case 762771Speter */ 76315931Smckusick p = rvalue( r->expr_node.lhs , contype , RREQ ); 76415931Smckusick if ( p == NLNIL ) { 76515931Smckusick return NLNIL; 7662056Speter } 767771Speter /* 768771Speter * since the second pass can't do 769771Speter * long op double or double op long 770771Speter * we may have to do some coercing. 771771Speter */ 77215931Smckusick tuac(p, p1, &rettype, (int *) (&ctype)); 77315931Smckusick p1 = rvalue( r->expr_node.rhs , p , RREQ ); 77415931Smckusick if ( p1 == NLNIL ) { 77515931Smckusick return NLNIL; 7765413Speter } 77715931Smckusick tuac(p1, p, &rettype, (int *) (&ctype)); 77815931Smckusick putop((int) relops[ r->tag - T_EQ ] , P2INT ); 77910364Smckusick sconv(P2INT, P2CHAR); 780771Speter } 781771Speter # endif PC 782771Speter c = classify(p); 783771Speter c1 = classify(p1); 784771Speter if (nocomp(c) || nocomp(c1)) 78515931Smckusick return (NLNIL); 78615931Smckusick # ifdef OBJ 78715931Smckusick g = NIL; 78815931Smckusick # endif 789771Speter switch (c) { 790771Speter case TBOOL: 791771Speter case TCHAR: 792771Speter if (c != c1) 793771Speter goto clash; 794771Speter break; 795771Speter case TINT: 796771Speter case TDOUBLE: 797771Speter if (c1 != TINT && c1 != TDOUBLE) 798771Speter goto clash; 799771Speter break; 800771Speter case TSCAL: 801771Speter if (c1 != TSCAL) 802771Speter goto clash; 803771Speter if (scalar(p) != scalar(p1)) 804771Speter goto nonident; 805771Speter break; 806771Speter case TSET: 807771Speter if (c1 != TSET) 808771Speter goto clash; 8093397Speter if ( opt( 's' ) && 81015931Smckusick ( ( r->tag == T_LT) || (r->tag == T_GT) ) && 8113397Speter ( line != nssetline ) ) { 8123397Speter nssetline = line; 8133397Speter standard(); 8143397Speter error("%s comparison on sets is non-standard" , opname ); 8153397Speter } 816771Speter if (p != p1) 817771Speter goto nonident; 81815931Smckusick # ifdef OBJ 81915931Smckusick g = TSET; 82015931Smckusick # endif 821771Speter break; 822771Speter case TREC: 823771Speter if ( c1 != TREC ) { 824771Speter goto clash; 825771Speter } 826771Speter if ( p != p1 ) { 827771Speter goto nonident; 828771Speter } 82915931Smckusick if (r->tag != T_EQ && r->tag != T_NE) { 830771Speter error("%s not allowed on records - only allow = and <>" , opname ); 83115931Smckusick return (NLNIL); 832771Speter } 83315931Smckusick # ifdef OBJ 83415931Smckusick g = TREC; 83515931Smckusick # endif 836771Speter break; 837771Speter case TPTR: 838771Speter case TNIL: 839771Speter if (c1 != TPTR && c1 != TNIL) 840771Speter goto clash; 84115931Smckusick if (r->tag != T_EQ && r->tag != T_NE) { 842771Speter error("%s not allowed on pointers - only allow = and <>" , opname ); 84315931Smckusick return (NLNIL); 844771Speter } 845*15937Smckusick if (p != nl+TNIL && p1 != nl+TNIL && p != p1) 846*15937Smckusick goto nonident; 847771Speter break; 848771Speter case TSTR: 849771Speter if (c1 != TSTR) 850771Speter goto clash; 851771Speter if (width(p) != width(p1)) { 852771Speter error("Strings not same length in %s comparison", opname); 85315931Smckusick return (NLNIL); 854771Speter } 85515931Smckusick # ifdef OBJ 85615931Smckusick g = TSTR; 85715931Smckusick # endif OBJ 858771Speter break; 859771Speter default: 860771Speter panic("rval2"); 861771Speter } 862771Speter # ifdef OBJ 86315931Smckusick return (gen(g, r->tag, width(p), width(p1))); 864771Speter # endif OBJ 865771Speter # ifdef PC 866771Speter return nl + TBOOL; 867771Speter # endif PC 868771Speter clash: 869771Speter error("%ss and %ss cannot be compared - operator was %s", clnames[c], clnames[c1], opname); 87015931Smckusick return (NLNIL); 871771Speter nonident: 872771Speter error("%s types must be identical in comparisons - operator was %s", clnames[c1], opname); 87315931Smckusick return (NLNIL); 874771Speter 875771Speter case T_IN: 87615931Smckusick rt = r->expr_node.rhs; 877771Speter # ifdef OBJ 87815931Smckusick if (rt != TR_NIL && rt->tag == T_CSET) { 87915931Smckusick (void) precset( rt , NLNIL , &csetd ); 880771Speter p1 = csetd.csettype; 88115931Smckusick if (p1 == NLNIL) 88215931Smckusick return NLNIL; 883771Speter postcset( rt, &csetd); 884771Speter } else { 88515931Smckusick p1 = stkrval(r->expr_node.rhs, NLNIL , (long) RREQ ); 88615931Smckusick rt = TR_NIL; 887771Speter } 888771Speter # endif OBJ 889771Speter # ifdef PC 89015931Smckusick if (rt != TR_NIL && rt->tag == T_CSET) { 89115931Smckusick if ( precset( rt , NLNIL , &csetd ) ) { 8921555Speter putleaf( P2ICON , 0 , 0 8931555Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 8941555Speter , "_IN" ); 895771Speter } else { 896771Speter putleaf( P2ICON , 0 , 0 897771Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 898771Speter , "_INCT" ); 899771Speter } 900771Speter p1 = csetd.csettype; 901771Speter if (p1 == NIL) 90215931Smckusick return NLNIL; 903771Speter } else { 904771Speter putleaf( P2ICON , 0 , 0 905771Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 906771Speter , "_IN" ); 907771Speter codeoff(); 90815931Smckusick p1 = rvalue(r->expr_node.rhs, NLNIL , LREQ ); 909771Speter codeon(); 910771Speter } 911771Speter # endif PC 91215931Smckusick p = stkrval(r->expr_node.lhs, NLNIL , (long) RREQ ); 913771Speter if (p == NIL || p1 == NIL) 91415931Smckusick return (NLNIL); 91515931Smckusick if (p1->class != (char) SET) { 916771Speter error("Right operand of 'in' must be a set, not %s", nameof(p1)); 91715931Smckusick return (NLNIL); 918771Speter } 91915931Smckusick if (incompat(p, p1->type, r->expr_node.lhs)) { 920771Speter cerror("Index type clashed with set component type for 'in'"); 92115931Smckusick return (NLNIL); 922771Speter } 923771Speter setran(p1->type); 924771Speter # ifdef OBJ 92515931Smckusick if (rt == TR_NIL || csetd.comptime) 92615931Smckusick (void) put(4, O_IN, width(p1), set.lwrb, set.uprbp); 927771Speter else 92815931Smckusick (void) put(2, O_INCT, 9293078Smckusic (int)(3 + csetd.singcnt + 2*csetd.paircnt)); 930771Speter # endif OBJ 931771Speter # ifdef PC 93215931Smckusick if ( rt == TR_NIL || rt->tag != T_CSET ) { 93315931Smckusick putleaf( P2ICON , set.lwrb , 0 , P2INT , (char *) 0 ); 934771Speter putop( P2LISTOP , P2INT ); 93515931Smckusick putleaf( P2ICON , set.uprbp , 0 , P2INT , (char *) 0 ); 936771Speter putop( P2LISTOP , P2INT ); 93715931Smckusick p1 = rvalue( r->expr_node.rhs , NLNIL , LREQ ); 93815931Smckusick if ( p1 == NLNIL ) { 93915931Smckusick return NLNIL; 9405413Speter } 941771Speter putop( P2LISTOP , P2INT ); 942771Speter } else if ( csetd.comptime ) { 94315931Smckusick putleaf( P2ICON , set.lwrb , 0 , P2INT , (char *) 0 ); 944771Speter putop( P2LISTOP , P2INT ); 94515931Smckusick putleaf( P2ICON , set.uprbp , 0 , P2INT , (char *) 0 ); 946771Speter putop( P2LISTOP , P2INT ); 94715931Smckusick postcset( r->expr_node.rhs , &csetd ); 948771Speter putop( P2LISTOP , P2INT ); 949771Speter } else { 95015931Smckusick postcset( r->expr_node.rhs , &csetd ); 951771Speter } 952771Speter putop( P2CALL , P2INT ); 95310364Smckusick sconv(P2INT, P2CHAR); 954771Speter # endif PC 955771Speter return (nl+T1BOOL); 956771Speter default: 95715931Smckusick if (r->expr_node.lhs == TR_NIL) 95815931Smckusick return (NLNIL); 95915931Smckusick switch (r->tag) { 960771Speter default: 961771Speter panic("rval3"); 962771Speter 963771Speter 964771Speter /* 965771Speter * An octal number 966771Speter */ 967771Speter case T_BINT: 96815931Smckusick f.pdouble = a8tol(r->const_node.cptr); 969771Speter goto conint; 970771Speter 971771Speter /* 972771Speter * A decimal number 973771Speter */ 974771Speter case T_INT: 97515931Smckusick f.pdouble = atof(r->const_node.cptr); 976771Speter conint: 97715931Smckusick if (f.pdouble > MAXINT || f.pdouble < MININT) { 978771Speter error("Constant too large for this implementation"); 97915931Smckusick return (NLNIL); 980771Speter } 98115931Smckusick l = f.pdouble; 98210364Smckusick # ifdef OBJ 98310364Smckusick if (bytes(l, l) <= 2) { 98415931Smckusick (void) put(2, O_CON2, ( short ) l); 98510364Smckusick return (nl+T2INT); 98610364Smckusick } 98715931Smckusick (void) put(2, O_CON4, l); 98810364Smckusick return (nl+T4INT); 989771Speter # endif OBJ 990771Speter # ifdef PC 99110364Smckusick switch (bytes(l, l)) { 99210364Smckusick case 1: 99315931Smckusick putleaf(P2ICON, (int) l, 0, P2CHAR, 99415931Smckusick (char *) 0); 99510364Smckusick return nl+T1INT; 99610364Smckusick case 2: 99715931Smckusick putleaf(P2ICON, (int) l, 0, P2SHORT, 99815931Smckusick (char *) 0); 99910364Smckusick return nl+T2INT; 100010364Smckusick case 4: 100115931Smckusick putleaf(P2ICON, (int) l, 0, P2INT, 100215931Smckusick (char *) 0); 100310364Smckusick return nl+T4INT; 100410364Smckusick } 1005771Speter # endif PC 1006771Speter 1007771Speter /* 1008771Speter * A floating point number 1009771Speter */ 1010771Speter case T_FINT: 1011771Speter # ifdef OBJ 101215931Smckusick (void) put(2, O_CON8, atof(r->const_node.cptr)); 1013771Speter # endif OBJ 1014771Speter # ifdef PC 101515931Smckusick putCON8( atof( r->const_node.cptr ) ); 1016771Speter # endif PC 1017771Speter return (nl+TDOUBLE); 1018771Speter 1019771Speter /* 1020771Speter * Constant strings. Note that constant characters 1021771Speter * are constant strings of length one; there is 1022771Speter * no constant string of length one. 1023771Speter */ 1024771Speter case T_STRNG: 102515931Smckusick cp = r->const_node.cptr; 1026771Speter if (cp[1] == 0) { 1027771Speter # ifdef OBJ 102815931Smckusick (void) put(2, O_CONC, cp[0]); 1029771Speter # endif OBJ 1030771Speter # ifdef PC 103115931Smckusick putleaf( P2ICON , cp[0] , 0 , P2CHAR , 103215931Smckusick (char *) 0 ); 1033771Speter # endif PC 1034771Speter return (nl+T1CHAR); 1035771Speter } 1036771Speter goto cstrng; 1037771Speter } 1038771Speter 1039771Speter } 1040771Speter } 1041771Speter 1042771Speter /* 1043771Speter * Can a class appear 1044771Speter * in a comparison ? 1045771Speter */ 1046771Speter nocomp(c) 1047771Speter int c; 1048771Speter { 1049771Speter 1050771Speter switch (c) { 1051771Speter case TREC: 10521627Speter if ( line != reccompline ) { 10531627Speter reccompline = line; 10541627Speter warning(); 10551627Speter if ( opt( 's' ) ) { 10561627Speter standard(); 10571627Speter } 1058771Speter error("record comparison is non-standard"); 1059771Speter } 1060771Speter break; 1061771Speter case TFILE: 1062771Speter case TARY: 1063771Speter error("%ss may not participate in comparisons", clnames[c]); 1064771Speter return (1); 1065771Speter } 1066771Speter return (NIL); 1067771Speter } 1068771Speter 1069771Speter /* 1070771Speter * this is sort of like gconst, except it works on expression trees 1071771Speter * rather than declaration trees, and doesn't give error messages for 1072771Speter * non-constant things. 1073771Speter * as a side effect this fills in the con structure that gconst uses. 1074771Speter * this returns TRUE or FALSE. 1075771Speter */ 107615931Smckusick 107715931Smckusick bool 1078771Speter constval(r) 107915931Smckusick register struct tnode *r; 1080771Speter { 1081771Speter register struct nl *np; 108215931Smckusick register struct tnode *cn; 1083771Speter char *cp; 1084771Speter int negd, sgnd; 1085771Speter long ci; 1086771Speter 1087771Speter con.ctype = NIL; 1088771Speter cn = r; 1089771Speter negd = sgnd = 0; 1090771Speter loop: 1091771Speter /* 1092771Speter * cn[2] is nil if error recovery generated a T_STRNG 1093771Speter */ 109415931Smckusick if (cn == TR_NIL || cn->expr_node.lhs == TR_NIL) 1095771Speter return FALSE; 109615931Smckusick switch (cn->tag) { 1097771Speter default: 1098771Speter return FALSE; 1099771Speter case T_MINUS: 1100771Speter negd = 1 - negd; 1101771Speter /* and fall through */ 1102771Speter case T_PLUS: 1103771Speter sgnd++; 110415931Smckusick cn = cn->un_expr.expr; 1105771Speter goto loop; 1106771Speter case T_NIL: 1107771Speter con.cpval = NIL; 1108771Speter con.cival = 0; 1109771Speter con.crval = con.cival; 1110771Speter con.ctype = nl + TNIL; 1111771Speter break; 1112771Speter case T_VAR: 111315931Smckusick np = lookup(cn->var_node.cptr); 111415931Smckusick if (np == NLNIL || np->class != CONST) { 1115771Speter return FALSE; 1116771Speter } 111715931Smckusick if ( cn->var_node.qual != TR_NIL ) { 1118771Speter return FALSE; 1119771Speter } 1120771Speter con.ctype = np->type; 1121771Speter switch (classify(np->type)) { 1122771Speter case TINT: 1123771Speter con.crval = np->range[0]; 1124771Speter break; 1125771Speter case TDOUBLE: 1126771Speter con.crval = np->real; 1127771Speter break; 1128771Speter case TBOOL: 1129771Speter case TCHAR: 1130771Speter case TSCAL: 1131771Speter con.cival = np->value[0]; 1132771Speter con.crval = con.cival; 1133771Speter break; 1134771Speter case TSTR: 113515931Smckusick con.cpval = (char *) np->ptr[0]; 1136771Speter break; 1137771Speter default: 1138771Speter con.ctype = NIL; 1139771Speter return FALSE; 1140771Speter } 1141771Speter break; 1142771Speter case T_BINT: 114315931Smckusick con.crval = a8tol(cn->const_node.cptr); 1144771Speter goto restcon; 1145771Speter case T_INT: 114615931Smckusick con.crval = atof(cn->const_node.cptr); 1147771Speter if (con.crval > MAXINT || con.crval < MININT) { 1148771Speter derror("Constant too large for this implementation"); 1149771Speter con.crval = 0; 1150771Speter } 1151771Speter restcon: 1152771Speter ci = con.crval; 1153771Speter #ifndef PI0 1154771Speter if (bytes(ci, ci) <= 2) 1155771Speter con.ctype = nl+T2INT; 1156771Speter else 1157771Speter #endif 1158771Speter con.ctype = nl+T4INT; 1159771Speter break; 1160771Speter case T_FINT: 1161771Speter con.ctype = nl+TDOUBLE; 116215931Smckusick con.crval = atof(cn->const_node.cptr); 1163771Speter break; 1164771Speter case T_STRNG: 116515931Smckusick cp = cn->const_node.cptr; 1166771Speter if (cp[1] == 0) { 1167771Speter con.ctype = nl+T1CHAR; 1168771Speter con.cival = cp[0]; 1169771Speter con.crval = con.cival; 1170771Speter break; 1171771Speter } 1172771Speter con.ctype = nl+TSTR; 1173771Speter con.cpval = cp; 1174771Speter break; 1175771Speter } 1176771Speter if (sgnd) { 1177771Speter if (isnta(con.ctype, "id")) { 1178771Speter derror("%s constants cannot be signed", nameof(con.ctype)); 1179771Speter return FALSE; 1180771Speter } else if (negd) 1181771Speter con.crval = -con.crval; 1182771Speter } 1183771Speter return TRUE; 1184771Speter } 1185