1771Speter /* Copyright (c) 1979 Regents of the University of California */ 2771Speter 3*11328Speter static char sccsid[] = "@(#)rval.c 1.16 02/28/83"; 4771Speter 5771Speter #include "whoami.h" 6771Speter #include "0.h" 7771Speter #include "tree.h" 8771Speter #include "opcode.h" 9771Speter #include "objfmt.h" 10771Speter #ifdef PC 11771Speter # include "pc.h" 12771Speter # include "pcops.h" 13771Speter #endif PC 14*11328Speter #include "tmps.h" 15771Speter 16771Speter extern char *opnames[]; 17771Speter 181627Speter /* line number of the last record comparison warning */ 191627Speter short reccompline = 0; 203397Speter /* line number of the last non-standard set comparison */ 213397Speter short nssetline = 0; 221627Speter 23771Speter #ifdef PC 24771Speter char *relts[] = { 25771Speter "_RELEQ" , "_RELNE" , 26771Speter "_RELTLT" , "_RELTGT" , 27771Speter "_RELTLE" , "_RELTGE" 28771Speter }; 29771Speter char *relss[] = { 30771Speter "_RELEQ" , "_RELNE" , 31771Speter "_RELSLT" , "_RELSGT" , 32771Speter "_RELSLE" , "_RELSGE" 33771Speter }; 34771Speter long relops[] = { 35771Speter P2EQ , P2NE , 36771Speter P2LT , P2GT , 37771Speter P2LE , P2GE 38771Speter }; 39771Speter long mathop[] = { P2MUL , P2PLUS , P2MINUS }; 40771Speter char *setop[] = { "_MULT" , "_ADDT" , "_SUBT" }; 41771Speter #endif PC 42771Speter /* 43771Speter * Rvalue - an expression. 44771Speter * 45771Speter * Contype is the type that the caller would prefer, nand is important 46771Speter * if constant sets or constant strings are involved, the latter 47771Speter * because of string padding. 48771Speter * required is a flag whether an lvalue or an rvalue is required. 49771Speter * only VARs and structured things can have gt their lvalue this way. 50771Speter */ 51771Speter struct nl * 52771Speter rvalue(r, contype , required ) 53771Speter int *r; 54771Speter struct nl *contype; 55771Speter int required; 56771Speter { 57771Speter register struct nl *p, *p1; 58771Speter register struct nl *q; 59771Speter int c, c1, *rt, w, g; 60771Speter char *cp, *cp1, *opname; 61771Speter long l; 62771Speter double f; 63771Speter extern int flagwas; 64771Speter struct csetstr csetd; 65771Speter # ifdef PC 66771Speter struct nl *rettype; 67771Speter long ctype; 683834Speter struct nl *tempnlp; 69771Speter # endif PC 70771Speter 71771Speter if (r == NIL) 72771Speter return (NIL); 73771Speter if (nowexp(r)) 74771Speter return (NIL); 75771Speter /* 76771Speter * Pick up the name of the operation 77771Speter * for future error messages. 78771Speter */ 79771Speter if (r[0] <= T_IN) 80771Speter opname = opnames[r[0]]; 81771Speter 82771Speter /* 83771Speter * The root of the tree tells us what sort of expression we have. 84771Speter */ 85771Speter switch (r[0]) { 86771Speter 87771Speter /* 88771Speter * The constant nil 89771Speter */ 90771Speter case T_NIL: 91771Speter # ifdef OBJ 92771Speter put(2, O_CON2, 0); 93771Speter # endif OBJ 94771Speter # ifdef PC 951477Speter putleaf( P2ICON , 0 , 0 , P2PTR|P2UNDEF , 0 ); 96771Speter # endif PC 97771Speter return (nl+TNIL); 98771Speter 99771Speter /* 100771Speter * Function call with arguments. 101771Speter */ 102771Speter case T_FCALL: 103771Speter # ifdef OBJ 104771Speter return (funccod(r)); 105771Speter # endif OBJ 106771Speter # ifdef PC 107771Speter return (pcfunccod( r )); 108771Speter # endif PC 109771Speter 110771Speter case T_VAR: 111771Speter p = lookup(r[2]); 112771Speter if (p == NIL || p->class == BADUSE) 113771Speter return (NIL); 114771Speter switch (p->class) { 115771Speter case VAR: 116771Speter /* 117771Speter * If a variable is 118771Speter * qualified then get 119771Speter * the rvalue by a 120771Speter * lvalue and an ind. 121771Speter */ 122771Speter if (r[3] != NIL) 123771Speter goto ind; 124771Speter q = p->type; 125771Speter if (q == NIL) 126771Speter return (NIL); 127771Speter # ifdef OBJ 128771Speter w = width(q); 129771Speter switch (w) { 130771Speter case 8: 1313078Smckusic put(2, O_RV8 | bn << 8+INDX, 1323078Smckusic (int)p->value[0]); 133771Speter break; 134771Speter case 4: 1353078Smckusic put(2, O_RV4 | bn << 8+INDX, 1363078Smckusic (int)p->value[0]); 137771Speter break; 138771Speter case 2: 1393078Smckusic put(2, O_RV2 | bn << 8+INDX, 1403078Smckusic (int)p->value[0]); 141771Speter break; 142771Speter case 1: 1433078Smckusic put(2, O_RV1 | bn << 8+INDX, 1443078Smckusic (int)p->value[0]); 145771Speter break; 146771Speter default: 1473078Smckusic put(3, O_RV | bn << 8+INDX, 1483078Smckusic (int)p->value[0], w); 149771Speter } 150771Speter # endif OBJ 151771Speter # ifdef PC 152771Speter if ( required == RREQ ) { 1533834Speter putRV( p -> symbol , bn , p -> value[0] , 1543834Speter p -> extra_flags , p2type( q ) ); 155771Speter } else { 1563834Speter putLV( p -> symbol , bn , p -> value[0] , 1573834Speter p -> extra_flags , p2type( q ) ); 158771Speter } 159771Speter # endif PC 160771Speter return (q); 161771Speter 162771Speter case WITHPTR: 163771Speter case REF: 164771Speter /* 165771Speter * A lvalue for these 166771Speter * is actually what one 167771Speter * might consider a rvalue. 168771Speter */ 169771Speter ind: 170771Speter q = lvalue(r, NOFLAGS , LREQ ); 171771Speter if (q == NIL) 172771Speter return (NIL); 173771Speter # ifdef OBJ 174771Speter w = width(q); 175771Speter switch (w) { 176771Speter case 8: 177771Speter put(1, O_IND8); 178771Speter break; 179771Speter case 4: 180771Speter put(1, O_IND4); 181771Speter break; 182771Speter case 2: 183771Speter put(1, O_IND2); 184771Speter break; 185771Speter case 1: 186771Speter put(1, O_IND1); 187771Speter break; 188771Speter default: 189771Speter put(2, O_IND, w); 190771Speter } 191771Speter # endif OBJ 192771Speter # ifdef PC 193771Speter if ( required == RREQ ) { 194771Speter putop( P2UNARY P2MUL , p2type( q ) ); 195771Speter } 196771Speter # endif PC 197771Speter return (q); 198771Speter 199771Speter case CONST: 200771Speter if (r[3] != NIL) { 201771Speter error("%s is a constant and cannot be qualified", r[2]); 202771Speter return (NIL); 203771Speter } 204771Speter q = p->type; 205771Speter if (q == NIL) 206771Speter return (NIL); 207771Speter if (q == nl+TSTR) { 208771Speter /* 209771Speter * Find the size of the string 210771Speter * constant if needed. 211771Speter */ 212771Speter cp = p->ptr[0]; 213771Speter cstrng: 214771Speter cp1 = cp; 215771Speter for (c = 0; *cp++; c++) 216771Speter continue; 2173078Smckusic w = c; 218771Speter if (contype != NIL && !opt('s')) { 219771Speter if (width(contype) < c && classify(contype) == TSTR) { 220771Speter error("Constant string too long"); 221771Speter return (NIL); 222771Speter } 2233078Smckusic w = width(contype); 224771Speter } 225771Speter # ifdef OBJ 2263078Smckusic put(2, O_CONG, w); 2273078Smckusic putstr(cp1, w - c); 228771Speter # endif OBJ 229771Speter # ifdef PC 2303155Smckusic putCONG( cp1 , w , required ); 231771Speter # endif PC 232771Speter /* 233771Speter * Define the string temporarily 234771Speter * so later people can know its 235771Speter * width. 236771Speter * cleaned out by stat. 237771Speter */ 2383078Smckusic q = defnl(0, STR, 0, w); 239771Speter q->type = q; 240771Speter return (q); 241771Speter } 242771Speter if (q == nl+T1CHAR) { 243771Speter # ifdef OBJ 2443078Smckusic put(2, O_CONC, (int)p->value[0]); 245771Speter # endif OBJ 246771Speter # ifdef PC 247771Speter putleaf( P2ICON , p -> value[0] , 0 248771Speter , P2CHAR , 0 ); 249771Speter # endif PC 250771Speter return (q); 251771Speter } 252771Speter /* 253771Speter * Every other kind of constant here 254771Speter */ 255771Speter switch (width(q)) { 256771Speter case 8: 257771Speter #ifndef DEBUG 258771Speter # ifdef OBJ 259771Speter put(2, O_CON8, p->real); 260771Speter # endif OBJ 261771Speter # ifdef PC 262771Speter putCON8( p -> real ); 263771Speter # endif PC 264771Speter #else 265771Speter if (hp21mx) { 266771Speter f = p->real; 267771Speter conv(&f); 268771Speter l = f.plong; 269771Speter put(2, O_CON4, l); 270771Speter } else 271771Speter # ifdef OBJ 272771Speter put(2, O_CON8, p->real); 273771Speter # endif OBJ 274771Speter # ifdef PC 275771Speter putCON8( p -> real ); 276771Speter # endif PC 277771Speter #endif 278771Speter break; 279771Speter case 4: 280771Speter # ifdef OBJ 281771Speter put(2, O_CON4, p->range[0]); 282771Speter # endif OBJ 283771Speter # ifdef PC 284771Speter putleaf( P2ICON , p -> range[0] , 0 285771Speter , P2INT , 0 ); 286771Speter # endif PC 287771Speter break; 288771Speter case 2: 289771Speter # ifdef OBJ 2903078Smckusic put(2, O_CON2, (short)p->range[0]); 291771Speter # endif OBJ 292771Speter # ifdef PC 293771Speter putleaf( P2ICON , (short) p -> range[0] 29410364Smckusick , 0 , P2SHORT , 0 ); 295771Speter # endif PC 296771Speter break; 297771Speter case 1: 298771Speter # ifdef OBJ 299771Speter put(2, O_CON1, p->value[0]); 300771Speter # endif OBJ 301771Speter # ifdef PC 302771Speter putleaf( P2ICON , p -> value[0] , 0 30310364Smckusick , P2CHAR , 0 ); 304771Speter # endif PC 305771Speter break; 306771Speter default: 307771Speter panic("rval"); 308771Speter } 309771Speter return (q); 310771Speter 311771Speter case FUNC: 3121200Speter case FFUNC: 313771Speter /* 314771Speter * Function call with no arguments. 315771Speter */ 316771Speter if (r[3]) { 317771Speter error("Can't qualify a function result value"); 318771Speter return (NIL); 319771Speter } 320771Speter # ifdef OBJ 321771Speter return (funccod((int *) r)); 322771Speter # endif OBJ 323771Speter # ifdef PC 324771Speter return (pcfunccod( r )); 325771Speter # endif PC 326771Speter 327771Speter case TYPE: 328771Speter error("Type names (e.g. %s) allowed only in declarations", p->symbol); 329771Speter return (NIL); 330771Speter 331771Speter case PROC: 3321200Speter case FPROC: 333771Speter error("Procedure %s found where expression required", p->symbol); 334771Speter return (NIL); 335771Speter default: 336771Speter panic("rvid"); 337771Speter } 338771Speter /* 339771Speter * Constant sets 340771Speter */ 341771Speter case T_CSET: 342771Speter # ifdef OBJ 343771Speter if ( precset( r , contype , &csetd ) ) { 344771Speter if ( csetd.csettype == NIL ) { 345771Speter return NIL; 346771Speter } 347771Speter postcset( r , &csetd ); 348771Speter } else { 3493078Smckusic put( 2, O_PUSH, -lwidth(csetd.csettype)); 350771Speter postcset( r , &csetd ); 351771Speter setran( ( csetd.csettype ) -> type ); 352771Speter put( 2, O_CON24, set.uprbp); 353771Speter put( 2, O_CON24, set.lwrb); 3543078Smckusic put( 2, O_CTTOT, 3553078Smckusic (int)(4 + csetd.singcnt + 2 * csetd.paircnt)); 356771Speter } 357771Speter return csetd.csettype; 358771Speter # endif OBJ 359771Speter # ifdef PC 360771Speter if ( precset( r , contype , &csetd ) ) { 361771Speter if ( csetd.csettype == NIL ) { 362771Speter return NIL; 363771Speter } 364771Speter postcset( r , &csetd ); 365771Speter } else { 366771Speter putleaf( P2ICON , 0 , 0 367771Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 368771Speter , "_CTTOT" ); 369771Speter /* 370771Speter * allocate a temporary and use it 371771Speter */ 3723834Speter tempnlp = tmpalloc(lwidth(csetd.csettype), 3733227Smckusic csetd.csettype, NOREG); 3743834Speter putLV( 0 , cbn , tempnlp -> value[ NL_OFFS ] , 3753834Speter tempnlp -> extra_flags , P2PTR|P2STRTY ); 376771Speter setran( ( csetd.csettype ) -> type ); 377771Speter putleaf( P2ICON , set.lwrb , 0 , P2INT , 0 ); 378771Speter putop( P2LISTOP , P2INT ); 379771Speter putleaf( P2ICON , set.uprbp , 0 , P2INT , 0 ); 380771Speter putop( P2LISTOP , P2INT ); 381771Speter postcset( r , &csetd ); 382771Speter putop( P2CALL , P2INT ); 383771Speter } 384771Speter return csetd.csettype; 385771Speter # endif PC 386771Speter 387771Speter /* 388771Speter * Unary plus and minus 389771Speter */ 390771Speter case T_PLUS: 391771Speter case T_MINUS: 392771Speter q = rvalue(r[2], NIL , RREQ ); 393771Speter if (q == NIL) 394771Speter return (NIL); 395771Speter if (isnta(q, "id")) { 396771Speter error("Operand of %s must be integer or real, not %s", opname, nameof(q)); 397771Speter return (NIL); 398771Speter } 399771Speter if (r[0] == T_MINUS) { 400771Speter # ifdef OBJ 401771Speter put(1, O_NEG2 + (width(q) >> 2)); 40210670Speter return (isa(q, "d") ? q : nl+T4INT); 403771Speter # endif OBJ 404771Speter # ifdef PC 40510670Speter if (isa(q, "i")) { 40610670Speter sconv(p2type(q), P2INT); 40710670Speter putop( P2UNARY P2MINUS, P2INT); 40810670Speter return nl+T4INT; 40910670Speter } 41010670Speter putop( P2UNARY P2MINUS, P2DOUBLE); 41110670Speter return nl+TDOUBLE; 412771Speter # endif PC 413771Speter } 414771Speter return (q); 415771Speter 416771Speter case T_NOT: 417771Speter q = rvalue(r[2], NIL , RREQ ); 418771Speter if (q == NIL) 419771Speter return (NIL); 420771Speter if (isnta(q, "b")) { 421771Speter error("not must operate on a Boolean, not %s", nameof(q)); 422771Speter return (NIL); 423771Speter } 424771Speter # ifdef OBJ 425771Speter put(1, O_NOT); 426771Speter # endif OBJ 427771Speter # ifdef PC 42810364Smckusick sconv(p2type(q), P2INT); 42910364Smckusick putop( P2NOT , P2INT); 43010364Smckusick sconv(P2INT, p2type(q)); 431771Speter # endif PC 432771Speter return (nl+T1BOOL); 433771Speter 434771Speter case T_AND: 435771Speter case T_OR: 436771Speter p = rvalue(r[2], NIL , RREQ ); 43710364Smckusick # ifdef PC 43810364Smckusick sconv(p2type(p),P2INT); 43910364Smckusick # endif PC 440771Speter p1 = rvalue(r[3], NIL , RREQ ); 44110364Smckusick # ifdef PC 44210364Smckusick sconv(p2type(p1),P2INT); 44310364Smckusick # endif PC 444771Speter if (p == NIL || p1 == NIL) 445771Speter return (NIL); 446771Speter if (isnta(p, "b")) { 447771Speter error("Left operand of %s must be Boolean, not %s", opname, nameof(p)); 448771Speter return (NIL); 449771Speter } 450771Speter if (isnta(p1, "b")) { 451771Speter error("Right operand of %s must be Boolean, not %s", opname, nameof(p1)); 452771Speter return (NIL); 453771Speter } 454771Speter # ifdef OBJ 455771Speter put(1, r[0] == T_AND ? O_AND : O_OR); 456771Speter # endif OBJ 457771Speter # ifdef PC 458771Speter /* 459771Speter * note the use of & and | rather than && and || 460771Speter * to force evaluation of all the expressions. 461771Speter */ 462771Speter putop( r[ 0 ] == T_AND ? P2AND : P2OR , P2INT ); 46310364Smckusick sconv(P2INT, p2type(p)); 464771Speter # endif PC 465771Speter return (nl+T1BOOL); 466771Speter 467771Speter case T_DIVD: 468771Speter # ifdef OBJ 469771Speter p = rvalue(r[2], NIL , RREQ ); 470771Speter p1 = rvalue(r[3], NIL , RREQ ); 471771Speter # endif OBJ 472771Speter # ifdef PC 473771Speter /* 474771Speter * force these to be doubles for the divide 475771Speter */ 476771Speter p = rvalue( r[ 2 ] , NIL , RREQ ); 47710364Smckusick sconv(p2type(p), P2DOUBLE); 478771Speter p1 = rvalue( r[ 3 ] , NIL , RREQ ); 47910364Smckusick sconv(p2type(p1), P2DOUBLE); 480771Speter # endif PC 481771Speter if (p == NIL || p1 == NIL) 482771Speter return (NIL); 483771Speter if (isnta(p, "id")) { 484771Speter error("Left operand of / must be integer or real, not %s", nameof(p)); 485771Speter return (NIL); 486771Speter } 487771Speter if (isnta(p1, "id")) { 488771Speter error("Right operand of / must be integer or real, not %s", nameof(p1)); 489771Speter return (NIL); 490771Speter } 491771Speter # ifdef OBJ 492771Speter return gen(NIL, r[0], width(p), width(p1)); 493771Speter # endif OBJ 494771Speter # ifdef PC 495771Speter putop( P2DIV , P2DOUBLE ); 496771Speter return nl + TDOUBLE; 497771Speter # endif PC 498771Speter 499771Speter case T_MULT: 500771Speter case T_ADD: 501771Speter case T_SUB: 502771Speter # ifdef OBJ 503771Speter /* 5041555Speter * If the context hasn't told us the type 5051555Speter * and a constant set is present 5061555Speter * we need to infer the type 5071555Speter * before generating code. 508771Speter */ 5091555Speter if ( contype == NIL ) { 510771Speter codeoff(); 5111555Speter contype = rvalue( r[3] , NIL , RREQ ); 512771Speter codeon(); 5131555Speter if ( contype == lookup( intset ) -> type ) { 5141555Speter codeoff(); 5151555Speter contype = rvalue( r[2] , NIL , RREQ ); 5161555Speter codeon(); 5171555Speter } 518771Speter } 5191555Speter if ( contype == NIL ) { 5201555Speter return NIL; 5211555Speter } 5221555Speter p = rvalue( r[2] , contype , RREQ ); 5231555Speter p1 = rvalue( r[3] , p , RREQ ); 5241555Speter if ( p == NIL || p1 == NIL ) 5251555Speter return NIL; 526771Speter if (isa(p, "id") && isa(p1, "id")) 527771Speter return (gen(NIL, r[0], width(p), width(p1))); 528771Speter if (isa(p, "t") && isa(p1, "t")) { 529771Speter if (p != p1) { 530771Speter error("Set types of operands of %s must be identical", opname); 531771Speter return (NIL); 532771Speter } 533771Speter gen(TSET, r[0], width(p), 0); 534771Speter return (p); 535771Speter } 536771Speter # endif OBJ 537771Speter # ifdef PC 538771Speter /* 539771Speter * the second pass can't do 540771Speter * long op double or double op long 541771Speter * so we have to know the type of both operands 542771Speter * also, it gets tricky for sets, which are done 543771Speter * by function calls. 544771Speter */ 545771Speter codeoff(); 546771Speter p1 = rvalue( r[ 3 ] , contype , RREQ ); 547771Speter codeon(); 548771Speter if ( isa( p1 , "id" ) ) { 549771Speter p = rvalue( r[ 2 ] , contype , RREQ ); 550771Speter if ( ( p == NIL ) || ( p1 == NIL ) ) { 551771Speter return NIL; 552771Speter } 55310364Smckusick tuac(p, p1, &rettype, &ctype); 554771Speter p1 = rvalue( r[ 3 ] , contype , RREQ ); 55510364Smckusick tuac(p1, p, &rettype, &ctype); 556771Speter if ( isa( p , "id" ) ) { 557771Speter putop( mathop[ r[0] - T_MULT ] , ctype ); 558771Speter return rettype; 559771Speter } 560771Speter } 561771Speter if ( isa( p1 , "t" ) ) { 562771Speter putleaf( P2ICON , 0 , 0 563771Speter , ADDTYPE( ADDTYPE( P2PTR | P2STRTY , P2FTN ) 564771Speter , P2PTR ) 565771Speter , setop[ r[0] - T_MULT ] ); 5661555Speter if ( contype == NIL ) { 5671555Speter contype = p1; 5681555Speter if ( contype == lookup( intset ) -> type ) { 5691555Speter codeoff(); 5701555Speter contype = rvalue( r[2] , NIL , LREQ ); 5711555Speter codeon(); 5721555Speter } 5731555Speter } 5741555Speter if ( contype == NIL ) { 5751555Speter return NIL; 5761555Speter } 5771555Speter /* 5781555Speter * allocate a temporary and use it 5791555Speter */ 5803834Speter tempnlp = tmpalloc(lwidth(contype), contype, NOREG); 5813834Speter putLV( 0 , cbn , tempnlp -> value[ NL_OFFS ] , 5823834Speter tempnlp -> extra_flags , P2PTR|P2STRTY ); 5831555Speter p = rvalue( r[2] , contype , LREQ ); 584771Speter if ( isa( p , "t" ) ) { 585771Speter putop( P2LISTOP , P2INT ); 586771Speter if ( p == NIL || p1 == NIL ) { 587771Speter return NIL; 588771Speter } 589771Speter p1 = rvalue( r[3] , p , LREQ ); 590771Speter if ( p != p1 ) { 591771Speter error("Set types of operands of %s must be identical", opname); 592771Speter return NIL; 593771Speter } 594771Speter putop( P2LISTOP , P2INT ); 595771Speter putleaf( P2ICON , lwidth( p1 ) / sizeof( long ) , 0 596771Speter , P2INT , 0 ); 597771Speter putop( P2LISTOP , P2INT ); 598771Speter putop( P2CALL , P2PTR | P2STRTY ); 599771Speter return p; 600771Speter } 601771Speter } 602771Speter if ( isnta( p1 , "idt" ) ) { 603771Speter /* 604771Speter * find type of left operand for error message. 605771Speter */ 606771Speter p = rvalue( r[2] , contype , RREQ ); 607771Speter } 608771Speter /* 609771Speter * don't give spurious error messages. 610771Speter */ 611771Speter if ( p == NIL || p1 == NIL ) { 612771Speter return NIL; 613771Speter } 614771Speter # endif PC 615771Speter if (isnta(p, "idt")) { 616771Speter error("Left operand of %s must be integer, real or set, not %s", opname, nameof(p)); 617771Speter return (NIL); 618771Speter } 619771Speter if (isnta(p1, "idt")) { 620771Speter error("Right operand of %s must be integer, real or set, not %s", opname, nameof(p1)); 621771Speter return (NIL); 622771Speter } 623771Speter error("Cannot mix sets with integers and reals as operands of %s", opname); 624771Speter return (NIL); 625771Speter 626771Speter case T_MOD: 627771Speter case T_DIV: 628771Speter p = rvalue(r[2], NIL , RREQ ); 62910364Smckusick # ifdef PC 63010364Smckusick sconv(p2type(p), P2INT); 63110364Smckusick # endif PC 632771Speter p1 = rvalue(r[3], NIL , RREQ ); 63310364Smckusick # ifdef PC 63410364Smckusick sconv(p2type(p1), P2INT); 63510364Smckusick # endif PC 636771Speter if (p == NIL || p1 == NIL) 637771Speter return (NIL); 638771Speter if (isnta(p, "i")) { 639771Speter error("Left operand of %s must be integer, not %s", opname, nameof(p)); 640771Speter return (NIL); 641771Speter } 642771Speter if (isnta(p1, "i")) { 643771Speter error("Right operand of %s must be integer, not %s", opname, nameof(p1)); 644771Speter return (NIL); 645771Speter } 646771Speter # ifdef OBJ 647771Speter return (gen(NIL, r[0], width(p), width(p1))); 648771Speter # endif OBJ 649771Speter # ifdef PC 650771Speter putop( r[ 0 ] == T_DIV ? P2DIV : P2MOD , P2INT ); 651771Speter return ( nl + T4INT ); 652771Speter # endif PC 653771Speter 654771Speter case T_EQ: 655771Speter case T_NE: 656771Speter case T_LT: 657771Speter case T_GT: 658771Speter case T_LE: 659771Speter case T_GE: 660771Speter /* 661771Speter * Since there can be no, a priori, knowledge 662771Speter * of the context type should a constant string 663771Speter * or set arise, we must poke around to find such 664771Speter * a type if possible. Since constant strings can 665771Speter * always masquerade as identifiers, this is always 666771Speter * necessary. 667771Speter */ 668771Speter codeoff(); 669771Speter p1 = rvalue(r[3], NIL , RREQ ); 670771Speter codeon(); 671771Speter if (p1 == NIL) 672771Speter return (NIL); 673771Speter contype = p1; 674771Speter # ifdef OBJ 6751555Speter if (p1->class == STR) { 676771Speter /* 677771Speter * For constant strings we want 678771Speter * the longest type so as to be 679771Speter * able to do padding (more importantly 680771Speter * avoiding truncation). For clarity, 681771Speter * we get this length here. 682771Speter */ 683771Speter codeoff(); 684771Speter p = rvalue(r[2], NIL , RREQ ); 685771Speter codeon(); 686771Speter if (p == NIL) 687771Speter return (NIL); 6881555Speter if (width(p) > width(p1)) 689771Speter contype = p; 6901555Speter } else if ( isa( p1 , "t" ) ) { 6911555Speter if ( contype == lookup( intset ) -> type ) { 6921555Speter codeoff(); 6931555Speter contype = rvalue( r[2] , NIL , RREQ ); 6941555Speter codeon(); 6951555Speter if ( contype == NIL ) { 6961555Speter return NIL; 6971555Speter } 6981555Speter } 699771Speter } 700771Speter /* 701771Speter * Now we generate code for 702771Speter * the operands of the relational 703771Speter * operation. 704771Speter */ 705771Speter p = rvalue(r[2], contype , RREQ ); 706771Speter if (p == NIL) 707771Speter return (NIL); 708771Speter p1 = rvalue(r[3], p , RREQ ); 709771Speter if (p1 == NIL) 710771Speter return (NIL); 711771Speter # endif OBJ 712771Speter # ifdef PC 713771Speter c1 = classify( p1 ); 714771Speter if ( c1 == TSET || c1 == TSTR || c1 == TREC ) { 715771Speter putleaf( P2ICON , 0 , 0 716771Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 717771Speter , c1 == TSET ? relts[ r[0] - T_EQ ] 718771Speter : relss[ r[0] - T_EQ ] ); 719771Speter /* 720771Speter * for [] and strings, comparisons are done on 721771Speter * the maximum width of the two sides. 722771Speter * for other sets, we have to ask the left side 723771Speter * what type it is based on the type of the right. 724771Speter * (this matters for intsets). 725771Speter */ 7261555Speter if ( c1 == TSTR ) { 727771Speter codeoff(); 728771Speter p = rvalue( r[ 2 ] , NIL , LREQ ); 729771Speter codeon(); 7301555Speter if ( p == NIL ) { 7311555Speter return NIL; 7321555Speter } 7331555Speter if ( lwidth( p ) > lwidth( p1 ) ) { 734771Speter contype = p; 735771Speter } 7361555Speter } else if ( c1 == TSET ) { 7371555Speter if ( contype == lookup( intset ) -> type ) { 7381555Speter codeoff(); 7391555Speter p = rvalue( r[ 2 ] , NIL , LREQ ); 7401555Speter codeon(); 7411555Speter if ( p == NIL ) { 7421555Speter return NIL; 7431555Speter } 7441555Speter contype = p; 7451555Speter } 7461627Speter } 747771Speter /* 748771Speter * put out the width of the comparison. 749771Speter */ 750771Speter putleaf( P2ICON , lwidth( contype ) , 0 , P2INT , 0 ); 751771Speter /* 752771Speter * and the left hand side, 753771Speter * for sets, strings, records 754771Speter */ 755771Speter p = rvalue( r[ 2 ] , contype , LREQ ); 7565413Speter if ( p == NIL ) { 7575413Speter return NIL; 7585413Speter } 759771Speter putop( P2LISTOP , P2INT ); 760771Speter p1 = rvalue( r[ 3 ] , p , LREQ ); 7615413Speter if ( p1 == NIL ) { 7625413Speter return NIL; 7635413Speter } 764771Speter putop( P2LISTOP , P2INT ); 765771Speter putop( P2CALL , P2INT ); 766771Speter } else { 767771Speter /* 768771Speter * the easy (scalar or error) case 769771Speter */ 770771Speter p = rvalue( r[ 2 ] , contype , RREQ ); 771771Speter if ( p == NIL ) { 772771Speter return NIL; 7732056Speter } 774771Speter /* 775771Speter * since the second pass can't do 776771Speter * long op double or double op long 777771Speter * we may have to do some coercing. 778771Speter */ 77910364Smckusick tuac(p, p1, &rettype, &ctype); 780771Speter p1 = rvalue( r[ 3 ] , p , RREQ ); 7815413Speter if ( p1 == NIL ) { 7825413Speter return NIL; 7835413Speter } 78410364Smckusick tuac(p1, p, &rettype, &ctype); 785771Speter putop( relops[ r[0] - T_EQ ] , P2INT ); 78610364Smckusick sconv(P2INT, P2CHAR); 787771Speter } 788771Speter # endif PC 789771Speter c = classify(p); 790771Speter c1 = classify(p1); 791771Speter if (nocomp(c) || nocomp(c1)) 792771Speter return (NIL); 793771Speter g = NIL; 794771Speter switch (c) { 795771Speter case TBOOL: 796771Speter case TCHAR: 797771Speter if (c != c1) 798771Speter goto clash; 799771Speter break; 800771Speter case TINT: 801771Speter case TDOUBLE: 802771Speter if (c1 != TINT && c1 != TDOUBLE) 803771Speter goto clash; 804771Speter break; 805771Speter case TSCAL: 806771Speter if (c1 != TSCAL) 807771Speter goto clash; 808771Speter if (scalar(p) != scalar(p1)) 809771Speter goto nonident; 810771Speter break; 811771Speter case TSET: 812771Speter if (c1 != TSET) 813771Speter goto clash; 8143397Speter if ( opt( 's' ) && 8153397Speter ( ( r[0] == T_LT ) || ( r[0] == T_GT ) ) && 8163397Speter ( line != nssetline ) ) { 8173397Speter nssetline = line; 8183397Speter standard(); 8193397Speter error("%s comparison on sets is non-standard" , opname ); 8203397Speter } 821771Speter if (p != p1) 822771Speter goto nonident; 823771Speter g = TSET; 824771Speter break; 825771Speter case TREC: 826771Speter if ( c1 != TREC ) { 827771Speter goto clash; 828771Speter } 829771Speter if ( p != p1 ) { 830771Speter goto nonident; 831771Speter } 832771Speter if (r[0] != T_EQ && r[0] != T_NE) { 833771Speter error("%s not allowed on records - only allow = and <>" , opname ); 834771Speter return (NIL); 835771Speter } 836771Speter g = TREC; 837771Speter break; 838771Speter case TPTR: 839771Speter case TNIL: 840771Speter if (c1 != TPTR && c1 != TNIL) 841771Speter goto clash; 842771Speter if (r[0] != T_EQ && r[0] != T_NE) { 843771Speter error("%s not allowed on pointers - only allow = and <>" , opname ); 844771Speter return (NIL); 845771Speter } 846771Speter break; 847771Speter case TSTR: 848771Speter if (c1 != TSTR) 849771Speter goto clash; 850771Speter if (width(p) != width(p1)) { 851771Speter error("Strings not same length in %s comparison", opname); 852771Speter return (NIL); 853771Speter } 854771Speter g = TSTR; 855771Speter break; 856771Speter default: 857771Speter panic("rval2"); 858771Speter } 859771Speter # ifdef OBJ 860771Speter return (gen(g, r[0], width(p), width(p1))); 861771Speter # endif OBJ 862771Speter # ifdef PC 863771Speter return nl + TBOOL; 864771Speter # endif PC 865771Speter clash: 866771Speter error("%ss and %ss cannot be compared - operator was %s", clnames[c], clnames[c1], opname); 867771Speter return (NIL); 868771Speter nonident: 869771Speter error("%s types must be identical in comparisons - operator was %s", clnames[c1], opname); 870771Speter return (NIL); 871771Speter 872771Speter case T_IN: 873771Speter rt = r[3]; 874771Speter # ifdef OBJ 875771Speter if (rt != NIL && rt[0] == T_CSET) { 876771Speter precset( rt , NIL , &csetd ); 877771Speter p1 = csetd.csettype; 878771Speter if (p1 == NIL) 879771Speter return NIL; 880771Speter postcset( rt, &csetd); 881771Speter } else { 882771Speter p1 = stkrval(r[3], NIL , RREQ ); 883771Speter rt = NIL; 884771Speter } 885771Speter # endif OBJ 886771Speter # ifdef PC 887771Speter if (rt != NIL && rt[0] == T_CSET) { 888771Speter if ( precset( rt , NIL , &csetd ) ) { 8891555Speter putleaf( P2ICON , 0 , 0 8901555Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 8911555Speter , "_IN" ); 892771Speter } else { 893771Speter putleaf( P2ICON , 0 , 0 894771Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 895771Speter , "_INCT" ); 896771Speter } 897771Speter p1 = csetd.csettype; 898771Speter if (p1 == NIL) 899771Speter return NIL; 900771Speter } else { 901771Speter putleaf( P2ICON , 0 , 0 902771Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 903771Speter , "_IN" ); 904771Speter codeoff(); 905771Speter p1 = rvalue(r[3], NIL , LREQ ); 906771Speter codeon(); 907771Speter } 908771Speter # endif PC 909771Speter p = stkrval(r[2], NIL , RREQ ); 910771Speter if (p == NIL || p1 == NIL) 911771Speter return (NIL); 912771Speter if (p1->class != SET) { 913771Speter error("Right operand of 'in' must be a set, not %s", nameof(p1)); 914771Speter return (NIL); 915771Speter } 916771Speter if (incompat(p, p1->type, r[2])) { 917771Speter cerror("Index type clashed with set component type for 'in'"); 918771Speter return (NIL); 919771Speter } 920771Speter setran(p1->type); 921771Speter # ifdef OBJ 922771Speter if (rt == NIL || csetd.comptime) 923771Speter put(4, O_IN, width(p1), set.lwrb, set.uprbp); 924771Speter else 9253078Smckusic put(2, O_INCT, 9263078Smckusic (int)(3 + csetd.singcnt + 2*csetd.paircnt)); 927771Speter # endif OBJ 928771Speter # ifdef PC 929771Speter if ( rt == NIL || rt[0] != T_CSET ) { 930771Speter putleaf( P2ICON , set.lwrb , 0 , P2INT , 0 ); 931771Speter putop( P2LISTOP , P2INT ); 932771Speter putleaf( P2ICON , set.uprbp , 0 , P2INT , 0 ); 933771Speter putop( P2LISTOP , P2INT ); 934771Speter p1 = rvalue( r[3] , NIL , LREQ ); 9355413Speter if ( p1 == NIL ) { 9365413Speter return NIL; 9375413Speter } 938771Speter putop( P2LISTOP , P2INT ); 939771Speter } else if ( csetd.comptime ) { 940771Speter putleaf( P2ICON , set.lwrb , 0 , P2INT , 0 ); 941771Speter putop( P2LISTOP , P2INT ); 942771Speter putleaf( P2ICON , set.uprbp , 0 , P2INT , 0 ); 943771Speter putop( P2LISTOP , P2INT ); 944771Speter postcset( r[3] , &csetd ); 945771Speter putop( P2LISTOP , P2INT ); 946771Speter } else { 947771Speter postcset( r[3] , &csetd ); 948771Speter } 949771Speter putop( P2CALL , P2INT ); 95010364Smckusick sconv(P2INT, P2CHAR); 951771Speter # endif PC 952771Speter return (nl+T1BOOL); 953771Speter default: 954771Speter if (r[2] == NIL) 955771Speter return (NIL); 956771Speter switch (r[0]) { 957771Speter default: 958771Speter panic("rval3"); 959771Speter 960771Speter 961771Speter /* 962771Speter * An octal number 963771Speter */ 964771Speter case T_BINT: 965771Speter f = a8tol(r[2]); 966771Speter goto conint; 967771Speter 968771Speter /* 969771Speter * A decimal number 970771Speter */ 971771Speter case T_INT: 972771Speter f = atof(r[2]); 973771Speter conint: 974771Speter if (f > MAXINT || f < MININT) { 975771Speter error("Constant too large for this implementation"); 976771Speter return (NIL); 977771Speter } 978771Speter l = f; 97910364Smckusick # ifdef OBJ 98010364Smckusick if (bytes(l, l) <= 2) { 981771Speter put(2, O_CON2, ( short ) l); 98210364Smckusick return (nl+T2INT); 98310364Smckusick } 984771Speter put(2, O_CON4, l); 98510364Smckusick return (nl+T4INT); 986771Speter # endif OBJ 987771Speter # ifdef PC 98810364Smckusick switch (bytes(l, l)) { 98910364Smckusick case 1: 99010364Smckusick putleaf(P2ICON, l, 0, P2CHAR, 0); 99110364Smckusick return nl+T1INT; 99210364Smckusick case 2: 99310364Smckusick putleaf(P2ICON, l, 0, P2SHORT, 0); 99410364Smckusick return nl+T2INT; 99510364Smckusick case 4: 99610364Smckusick putleaf(P2ICON, l, 0, P2INT, 0); 99710364Smckusick return nl+T4INT; 99810364Smckusick } 999771Speter # endif PC 1000771Speter 1001771Speter /* 1002771Speter * A floating point number 1003771Speter */ 1004771Speter case T_FINT: 1005771Speter # ifdef OBJ 1006771Speter put(2, O_CON8, atof(r[2])); 1007771Speter # endif OBJ 1008771Speter # ifdef PC 1009771Speter putCON8( atof( r[2] ) ); 1010771Speter # endif PC 1011771Speter return (nl+TDOUBLE); 1012771Speter 1013771Speter /* 1014771Speter * Constant strings. Note that constant characters 1015771Speter * are constant strings of length one; there is 1016771Speter * no constant string of length one. 1017771Speter */ 1018771Speter case T_STRNG: 1019771Speter cp = r[2]; 1020771Speter if (cp[1] == 0) { 1021771Speter # ifdef OBJ 1022771Speter put(2, O_CONC, cp[0]); 1023771Speter # endif OBJ 1024771Speter # ifdef PC 1025771Speter putleaf( P2ICON , cp[0] , 0 , P2CHAR , 0 ); 1026771Speter # endif PC 1027771Speter return (nl+T1CHAR); 1028771Speter } 1029771Speter goto cstrng; 1030771Speter } 1031771Speter 1032771Speter } 1033771Speter } 1034771Speter 1035771Speter /* 1036771Speter * Can a class appear 1037771Speter * in a comparison ? 1038771Speter */ 1039771Speter nocomp(c) 1040771Speter int c; 1041771Speter { 1042771Speter 1043771Speter switch (c) { 1044771Speter case TREC: 10451627Speter if ( line != reccompline ) { 10461627Speter reccompline = line; 10471627Speter warning(); 10481627Speter if ( opt( 's' ) ) { 10491627Speter standard(); 10501627Speter } 1051771Speter error("record comparison is non-standard"); 1052771Speter } 1053771Speter break; 1054771Speter case TFILE: 1055771Speter case TARY: 1056771Speter error("%ss may not participate in comparisons", clnames[c]); 1057771Speter return (1); 1058771Speter } 1059771Speter return (NIL); 1060771Speter } 1061771Speter 1062771Speter /* 1063771Speter * this is sort of like gconst, except it works on expression trees 1064771Speter * rather than declaration trees, and doesn't give error messages for 1065771Speter * non-constant things. 1066771Speter * as a side effect this fills in the con structure that gconst uses. 1067771Speter * this returns TRUE or FALSE. 1068771Speter */ 1069771Speter constval(r) 1070771Speter register int *r; 1071771Speter { 1072771Speter register struct nl *np; 1073771Speter register *cn; 1074771Speter char *cp; 1075771Speter int negd, sgnd; 1076771Speter long ci; 1077771Speter 1078771Speter con.ctype = NIL; 1079771Speter cn = r; 1080771Speter negd = sgnd = 0; 1081771Speter loop: 1082771Speter /* 1083771Speter * cn[2] is nil if error recovery generated a T_STRNG 1084771Speter */ 1085771Speter if (cn == NIL || cn[2] == NIL) 1086771Speter return FALSE; 1087771Speter switch (cn[0]) { 1088771Speter default: 1089771Speter return FALSE; 1090771Speter case T_MINUS: 1091771Speter negd = 1 - negd; 1092771Speter /* and fall through */ 1093771Speter case T_PLUS: 1094771Speter sgnd++; 1095771Speter cn = cn[2]; 1096771Speter goto loop; 1097771Speter case T_NIL: 1098771Speter con.cpval = NIL; 1099771Speter con.cival = 0; 1100771Speter con.crval = con.cival; 1101771Speter con.ctype = nl + TNIL; 1102771Speter break; 1103771Speter case T_VAR: 1104771Speter np = lookup(cn[2]); 1105771Speter if (np == NIL || np->class != CONST) { 1106771Speter return FALSE; 1107771Speter } 1108771Speter if ( cn[3] != NIL ) { 1109771Speter return FALSE; 1110771Speter } 1111771Speter con.ctype = np->type; 1112771Speter switch (classify(np->type)) { 1113771Speter case TINT: 1114771Speter con.crval = np->range[0]; 1115771Speter break; 1116771Speter case TDOUBLE: 1117771Speter con.crval = np->real; 1118771Speter break; 1119771Speter case TBOOL: 1120771Speter case TCHAR: 1121771Speter case TSCAL: 1122771Speter con.cival = np->value[0]; 1123771Speter con.crval = con.cival; 1124771Speter break; 1125771Speter case TSTR: 1126771Speter con.cpval = np->ptr[0]; 1127771Speter break; 1128771Speter default: 1129771Speter con.ctype = NIL; 1130771Speter return FALSE; 1131771Speter } 1132771Speter break; 1133771Speter case T_BINT: 1134771Speter con.crval = a8tol(cn[2]); 1135771Speter goto restcon; 1136771Speter case T_INT: 1137771Speter con.crval = atof(cn[2]); 1138771Speter if (con.crval > MAXINT || con.crval < MININT) { 1139771Speter derror("Constant too large for this implementation"); 1140771Speter con.crval = 0; 1141771Speter } 1142771Speter restcon: 1143771Speter ci = con.crval; 1144771Speter #ifndef PI0 1145771Speter if (bytes(ci, ci) <= 2) 1146771Speter con.ctype = nl+T2INT; 1147771Speter else 1148771Speter #endif 1149771Speter con.ctype = nl+T4INT; 1150771Speter break; 1151771Speter case T_FINT: 1152771Speter con.ctype = nl+TDOUBLE; 1153771Speter con.crval = atof(cn[2]); 1154771Speter break; 1155771Speter case T_STRNG: 1156771Speter cp = cn[2]; 1157771Speter if (cp[1] == 0) { 1158771Speter con.ctype = nl+T1CHAR; 1159771Speter con.cival = cp[0]; 1160771Speter con.crval = con.cival; 1161771Speter break; 1162771Speter } 1163771Speter con.ctype = nl+TSTR; 1164771Speter con.cpval = cp; 1165771Speter break; 1166771Speter } 1167771Speter if (sgnd) { 1168771Speter if (isnta(con.ctype, "id")) { 1169771Speter derror("%s constants cannot be signed", nameof(con.ctype)); 1170771Speter return FALSE; 1171771Speter } else if (negd) 1172771Speter con.crval = -con.crval; 1173771Speter } 1174771Speter return TRUE; 1175771Speter } 1176