1771Speter /* Copyright (c) 1979 Regents of the University of California */ 2771Speter 3*3227Smckusic static char sccsid[] = "@(#)rval.c 1.10 03/11/81"; 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 14771Speter 15771Speter extern char *opnames[]; 16771Speter 171627Speter /* line number of the last record comparison warning */ 181627Speter short reccompline = 0; 191627Speter 20771Speter #ifdef PC 21771Speter char *relts[] = { 22771Speter "_RELEQ" , "_RELNE" , 23771Speter "_RELTLT" , "_RELTGT" , 24771Speter "_RELTLE" , "_RELTGE" 25771Speter }; 26771Speter char *relss[] = { 27771Speter "_RELEQ" , "_RELNE" , 28771Speter "_RELSLT" , "_RELSGT" , 29771Speter "_RELSLE" , "_RELSGE" 30771Speter }; 31771Speter long relops[] = { 32771Speter P2EQ , P2NE , 33771Speter P2LT , P2GT , 34771Speter P2LE , P2GE 35771Speter }; 36771Speter long mathop[] = { P2MUL , P2PLUS , P2MINUS }; 37771Speter char *setop[] = { "_MULT" , "_ADDT" , "_SUBT" }; 38771Speter #endif PC 39771Speter /* 40771Speter * Rvalue - an expression. 41771Speter * 42771Speter * Contype is the type that the caller would prefer, nand is important 43771Speter * if constant sets or constant strings are involved, the latter 44771Speter * because of string padding. 45771Speter * required is a flag whether an lvalue or an rvalue is required. 46771Speter * only VARs and structured things can have gt their lvalue this way. 47771Speter */ 48771Speter struct nl * 49771Speter rvalue(r, contype , required ) 50771Speter int *r; 51771Speter struct nl *contype; 52771Speter int required; 53771Speter { 54771Speter register struct nl *p, *p1; 55771Speter register struct nl *q; 56771Speter int c, c1, *rt, w, g; 57771Speter char *cp, *cp1, *opname; 58771Speter long l; 59771Speter double f; 60771Speter extern int flagwas; 61771Speter struct csetstr csetd; 62771Speter # ifdef PC 63771Speter struct nl *rettype; 64771Speter long ctype; 65771Speter long tempoff; 66771Speter # endif PC 67771Speter 68771Speter if (r == NIL) 69771Speter return (NIL); 70771Speter if (nowexp(r)) 71771Speter return (NIL); 72771Speter /* 73771Speter * Pick up the name of the operation 74771Speter * for future error messages. 75771Speter */ 76771Speter if (r[0] <= T_IN) 77771Speter opname = opnames[r[0]]; 78771Speter 79771Speter /* 80771Speter * The root of the tree tells us what sort of expression we have. 81771Speter */ 82771Speter switch (r[0]) { 83771Speter 84771Speter /* 85771Speter * The constant nil 86771Speter */ 87771Speter case T_NIL: 88771Speter # ifdef OBJ 89771Speter put(2, O_CON2, 0); 90771Speter # endif OBJ 91771Speter # ifdef PC 921477Speter putleaf( P2ICON , 0 , 0 , P2PTR|P2UNDEF , 0 ); 93771Speter # endif PC 94771Speter return (nl+TNIL); 95771Speter 96771Speter /* 97771Speter * Function call with arguments. 98771Speter */ 99771Speter case T_FCALL: 100771Speter # ifdef OBJ 101771Speter return (funccod(r)); 102771Speter # endif OBJ 103771Speter # ifdef PC 104771Speter return (pcfunccod( r )); 105771Speter # endif PC 106771Speter 107771Speter case T_VAR: 108771Speter p = lookup(r[2]); 109771Speter if (p == NIL || p->class == BADUSE) 110771Speter return (NIL); 111771Speter switch (p->class) { 112771Speter case VAR: 113771Speter /* 114771Speter * If a variable is 115771Speter * qualified then get 116771Speter * the rvalue by a 117771Speter * lvalue and an ind. 118771Speter */ 119771Speter if (r[3] != NIL) 120771Speter goto ind; 121771Speter q = p->type; 122771Speter if (q == NIL) 123771Speter return (NIL); 124771Speter # ifdef OBJ 125771Speter w = width(q); 126771Speter switch (w) { 127771Speter case 8: 1283078Smckusic put(2, O_RV8 | bn << 8+INDX, 1293078Smckusic (int)p->value[0]); 130771Speter break; 131771Speter case 4: 1323078Smckusic put(2, O_RV4 | bn << 8+INDX, 1333078Smckusic (int)p->value[0]); 134771Speter break; 135771Speter case 2: 1363078Smckusic put(2, O_RV2 | bn << 8+INDX, 1373078Smckusic (int)p->value[0]); 138771Speter break; 139771Speter case 1: 1403078Smckusic put(2, O_RV1 | bn << 8+INDX, 1413078Smckusic (int)p->value[0]); 142771Speter break; 143771Speter default: 1443078Smckusic put(3, O_RV | bn << 8+INDX, 1453078Smckusic (int)p->value[0], w); 146771Speter } 147771Speter # endif OBJ 148771Speter # ifdef PC 149771Speter if ( required == RREQ ) { 150771Speter putRV( p -> symbol , bn , p -> value[0] 151771Speter , p2type( q ) ); 152771Speter } else { 153771Speter putLV( p -> symbol , bn , p -> value[0] 154771Speter , p2type( q ) ); 155771Speter } 156771Speter # endif PC 157771Speter return (q); 158771Speter 159771Speter case WITHPTR: 160771Speter case REF: 161771Speter /* 162771Speter * A lvalue for these 163771Speter * is actually what one 164771Speter * might consider a rvalue. 165771Speter */ 166771Speter ind: 167771Speter q = lvalue(r, NOFLAGS , LREQ ); 168771Speter if (q == NIL) 169771Speter return (NIL); 170771Speter # ifdef OBJ 171771Speter w = width(q); 172771Speter switch (w) { 173771Speter case 8: 174771Speter put(1, O_IND8); 175771Speter break; 176771Speter case 4: 177771Speter put(1, O_IND4); 178771Speter break; 179771Speter case 2: 180771Speter put(1, O_IND2); 181771Speter break; 182771Speter case 1: 183771Speter put(1, O_IND1); 184771Speter break; 185771Speter default: 186771Speter put(2, O_IND, w); 187771Speter } 188771Speter # endif OBJ 189771Speter # ifdef PC 190771Speter if ( required == RREQ ) { 191771Speter putop( P2UNARY P2MUL , p2type( q ) ); 192771Speter } 193771Speter # endif PC 194771Speter return (q); 195771Speter 196771Speter case CONST: 197771Speter if (r[3] != NIL) { 198771Speter error("%s is a constant and cannot be qualified", r[2]); 199771Speter return (NIL); 200771Speter } 201771Speter q = p->type; 202771Speter if (q == NIL) 203771Speter return (NIL); 204771Speter if (q == nl+TSTR) { 205771Speter /* 206771Speter * Find the size of the string 207771Speter * constant if needed. 208771Speter */ 209771Speter cp = p->ptr[0]; 210771Speter cstrng: 211771Speter cp1 = cp; 212771Speter for (c = 0; *cp++; c++) 213771Speter continue; 2143078Smckusic w = c; 215771Speter if (contype != NIL && !opt('s')) { 216771Speter if (width(contype) < c && classify(contype) == TSTR) { 217771Speter error("Constant string too long"); 218771Speter return (NIL); 219771Speter } 2203078Smckusic w = width(contype); 221771Speter } 222771Speter # ifdef OBJ 2233078Smckusic put(2, O_CONG, w); 2243078Smckusic putstr(cp1, w - c); 225771Speter # endif OBJ 226771Speter # ifdef PC 2273155Smckusic putCONG( cp1 , w , required ); 228771Speter # endif PC 229771Speter /* 230771Speter * Define the string temporarily 231771Speter * so later people can know its 232771Speter * width. 233771Speter * cleaned out by stat. 234771Speter */ 2353078Smckusic q = defnl(0, STR, 0, w); 236771Speter q->type = q; 237771Speter return (q); 238771Speter } 239771Speter if (q == nl+T1CHAR) { 240771Speter # ifdef OBJ 2413078Smckusic put(2, O_CONC, (int)p->value[0]); 242771Speter # endif OBJ 243771Speter # ifdef PC 244771Speter putleaf( P2ICON , p -> value[0] , 0 245771Speter , P2CHAR , 0 ); 246771Speter # endif PC 247771Speter return (q); 248771Speter } 249771Speter /* 250771Speter * Every other kind of constant here 251771Speter */ 252771Speter switch (width(q)) { 253771Speter case 8: 254771Speter #ifndef DEBUG 255771Speter # ifdef OBJ 256771Speter put(2, O_CON8, p->real); 257771Speter # endif OBJ 258771Speter # ifdef PC 259771Speter putCON8( p -> real ); 260771Speter # endif PC 261771Speter #else 262771Speter if (hp21mx) { 263771Speter f = p->real; 264771Speter conv(&f); 265771Speter l = f.plong; 266771Speter put(2, O_CON4, l); 267771Speter } else 268771Speter # ifdef OBJ 269771Speter put(2, O_CON8, p->real); 270771Speter # endif OBJ 271771Speter # ifdef PC 272771Speter putCON8( p -> real ); 273771Speter # endif PC 274771Speter #endif 275771Speter break; 276771Speter case 4: 277771Speter # ifdef OBJ 278771Speter put(2, O_CON4, p->range[0]); 279771Speter # endif OBJ 280771Speter # ifdef PC 281771Speter putleaf( P2ICON , p -> range[0] , 0 282771Speter , P2INT , 0 ); 283771Speter # endif PC 284771Speter break; 285771Speter case 2: 286771Speter # ifdef OBJ 2873078Smckusic put(2, O_CON2, (short)p->range[0]); 288771Speter # endif OBJ 289771Speter # ifdef PC 290771Speter /* 291771Speter * make short constants ints 292771Speter */ 293771Speter putleaf( P2ICON , (short) p -> range[0] 294771Speter , 0 , P2INT , 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 /* 303771Speter * make char constants ints 304771Speter */ 305771Speter putleaf( P2ICON , p -> value[0] , 0 306771Speter , P2INT , 0 ); 307771Speter # endif PC 308771Speter break; 309771Speter default: 310771Speter panic("rval"); 311771Speter } 312771Speter return (q); 313771Speter 314771Speter case FUNC: 3151200Speter case FFUNC: 316771Speter /* 317771Speter * Function call with no arguments. 318771Speter */ 319771Speter if (r[3]) { 320771Speter error("Can't qualify a function result value"); 321771Speter return (NIL); 322771Speter } 323771Speter # ifdef OBJ 324771Speter return (funccod((int *) r)); 325771Speter # endif OBJ 326771Speter # ifdef PC 327771Speter return (pcfunccod( r )); 328771Speter # endif PC 329771Speter 330771Speter case TYPE: 331771Speter error("Type names (e.g. %s) allowed only in declarations", p->symbol); 332771Speter return (NIL); 333771Speter 334771Speter case PROC: 3351200Speter case FPROC: 336771Speter error("Procedure %s found where expression required", p->symbol); 337771Speter return (NIL); 338771Speter default: 339771Speter panic("rvid"); 340771Speter } 341771Speter /* 342771Speter * Constant sets 343771Speter */ 344771Speter case T_CSET: 345771Speter # ifdef OBJ 346771Speter if ( precset( r , contype , &csetd ) ) { 347771Speter if ( csetd.csettype == NIL ) { 348771Speter return NIL; 349771Speter } 350771Speter postcset( r , &csetd ); 351771Speter } else { 3523078Smckusic put( 2, O_PUSH, -lwidth(csetd.csettype)); 353771Speter postcset( r , &csetd ); 354771Speter setran( ( csetd.csettype ) -> type ); 355771Speter put( 2, O_CON24, set.uprbp); 356771Speter put( 2, O_CON24, set.lwrb); 3573078Smckusic put( 2, O_CTTOT, 3583078Smckusic (int)(4 + csetd.singcnt + 2 * csetd.paircnt)); 359771Speter } 360771Speter return csetd.csettype; 361771Speter # endif OBJ 362771Speter # ifdef PC 363771Speter if ( precset( r , contype , &csetd ) ) { 364771Speter if ( csetd.csettype == NIL ) { 365771Speter return NIL; 366771Speter } 367771Speter postcset( r , &csetd ); 368771Speter } else { 369771Speter putleaf( P2ICON , 0 , 0 370771Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 371771Speter , "_CTTOT" ); 372771Speter /* 373771Speter * allocate a temporary and use it 374771Speter */ 375*3227Smckusic tempoff = tmpalloc(lwidth(csetd.csettype), 376*3227Smckusic csetd.csettype, NOREG); 377771Speter putLV( 0 , cbn , tempoff , P2PTR|P2STRTY ); 378771Speter setran( ( csetd.csettype ) -> type ); 379771Speter putleaf( P2ICON , set.lwrb , 0 , P2INT , 0 ); 380771Speter putop( P2LISTOP , P2INT ); 381771Speter putleaf( P2ICON , set.uprbp , 0 , P2INT , 0 ); 382771Speter putop( P2LISTOP , P2INT ); 383771Speter postcset( r , &csetd ); 384771Speter putop( P2CALL , P2INT ); 385771Speter } 386771Speter return csetd.csettype; 387771Speter # endif PC 388771Speter 389771Speter /* 390771Speter * Unary plus and minus 391771Speter */ 392771Speter case T_PLUS: 393771Speter case T_MINUS: 394771Speter q = rvalue(r[2], NIL , RREQ ); 395771Speter if (q == NIL) 396771Speter return (NIL); 397771Speter if (isnta(q, "id")) { 398771Speter error("Operand of %s must be integer or real, not %s", opname, nameof(q)); 399771Speter return (NIL); 400771Speter } 401771Speter if (r[0] == T_MINUS) { 402771Speter # ifdef OBJ 403771Speter put(1, O_NEG2 + (width(q) >> 2)); 404771Speter # endif OBJ 405771Speter # ifdef PC 406771Speter putop( P2UNARY P2MINUS , p2type( q ) ); 407771Speter # endif PC 408771Speter return (isa(q, "d") ? q : nl+T4INT); 409771Speter } 410771Speter return (q); 411771Speter 412771Speter case T_NOT: 413771Speter q = rvalue(r[2], NIL , RREQ ); 414771Speter if (q == NIL) 415771Speter return (NIL); 416771Speter if (isnta(q, "b")) { 417771Speter error("not must operate on a Boolean, not %s", nameof(q)); 418771Speter return (NIL); 419771Speter } 420771Speter # ifdef OBJ 421771Speter put(1, O_NOT); 422771Speter # endif OBJ 423771Speter # ifdef PC 424771Speter putop( P2NOT , P2INT ); 425771Speter # endif PC 426771Speter return (nl+T1BOOL); 427771Speter 428771Speter case T_AND: 429771Speter case T_OR: 430771Speter p = rvalue(r[2], NIL , RREQ ); 431771Speter p1 = rvalue(r[3], NIL , RREQ ); 432771Speter if (p == NIL || p1 == NIL) 433771Speter return (NIL); 434771Speter if (isnta(p, "b")) { 435771Speter error("Left operand of %s must be Boolean, not %s", opname, nameof(p)); 436771Speter return (NIL); 437771Speter } 438771Speter if (isnta(p1, "b")) { 439771Speter error("Right operand of %s must be Boolean, not %s", opname, nameof(p1)); 440771Speter return (NIL); 441771Speter } 442771Speter # ifdef OBJ 443771Speter put(1, r[0] == T_AND ? O_AND : O_OR); 444771Speter # endif OBJ 445771Speter # ifdef PC 446771Speter /* 447771Speter * note the use of & and | rather than && and || 448771Speter * to force evaluation of all the expressions. 449771Speter */ 450771Speter putop( r[ 0 ] == T_AND ? P2AND : P2OR , P2INT ); 451771Speter # endif PC 452771Speter return (nl+T1BOOL); 453771Speter 454771Speter case T_DIVD: 455771Speter # ifdef OBJ 456771Speter p = rvalue(r[2], NIL , RREQ ); 457771Speter p1 = rvalue(r[3], NIL , RREQ ); 458771Speter # endif OBJ 459771Speter # ifdef PC 460771Speter /* 461771Speter * force these to be doubles for the divide 462771Speter */ 463771Speter p = rvalue( r[ 2 ] , NIL , RREQ ); 464771Speter if ( isnta( p , "d" ) ) { 465771Speter putop( P2SCONV , P2DOUBLE ); 466771Speter } 467771Speter p1 = rvalue( r[ 3 ] , NIL , RREQ ); 468771Speter if ( isnta( p1 , "d" ) ) { 469771Speter putop( P2SCONV , P2DOUBLE ); 470771Speter } 471771Speter # endif PC 472771Speter if (p == NIL || p1 == NIL) 473771Speter return (NIL); 474771Speter if (isnta(p, "id")) { 475771Speter error("Left operand of / must be integer or real, not %s", nameof(p)); 476771Speter return (NIL); 477771Speter } 478771Speter if (isnta(p1, "id")) { 479771Speter error("Right operand of / must be integer or real, not %s", nameof(p1)); 480771Speter return (NIL); 481771Speter } 482771Speter # ifdef OBJ 483771Speter return gen(NIL, r[0], width(p), width(p1)); 484771Speter # endif OBJ 485771Speter # ifdef PC 486771Speter putop( P2DIV , P2DOUBLE ); 487771Speter return nl + TDOUBLE; 488771Speter # endif PC 489771Speter 490771Speter case T_MULT: 491771Speter case T_ADD: 492771Speter case T_SUB: 493771Speter # ifdef OBJ 494771Speter /* 4951555Speter * If the context hasn't told us the type 4961555Speter * and a constant set is present 4971555Speter * we need to infer the type 4981555Speter * before generating code. 499771Speter */ 5001555Speter if ( contype == NIL ) { 501771Speter codeoff(); 5021555Speter contype = rvalue( r[3] , NIL , RREQ ); 503771Speter codeon(); 5041555Speter if ( contype == lookup( intset ) -> type ) { 5051555Speter codeoff(); 5061555Speter contype = rvalue( r[2] , NIL , RREQ ); 5071555Speter codeon(); 5081555Speter } 509771Speter } 5101555Speter if ( contype == NIL ) { 5111555Speter return NIL; 5121555Speter } 5131555Speter p = rvalue( r[2] , contype , RREQ ); 5141555Speter p1 = rvalue( r[3] , p , RREQ ); 5151555Speter if ( p == NIL || p1 == NIL ) 5161555Speter return NIL; 517771Speter if (isa(p, "id") && isa(p1, "id")) 518771Speter return (gen(NIL, r[0], width(p), width(p1))); 519771Speter if (isa(p, "t") && isa(p1, "t")) { 520771Speter if (p != p1) { 521771Speter error("Set types of operands of %s must be identical", opname); 522771Speter return (NIL); 523771Speter } 524771Speter gen(TSET, r[0], width(p), 0); 525771Speter return (p); 526771Speter } 527771Speter # endif OBJ 528771Speter # ifdef PC 529771Speter /* 530771Speter * the second pass can't do 531771Speter * long op double or double op long 532771Speter * so we have to know the type of both operands 533771Speter * also, it gets tricky for sets, which are done 534771Speter * by function calls. 535771Speter */ 536771Speter codeoff(); 537771Speter p1 = rvalue( r[ 3 ] , contype , RREQ ); 538771Speter codeon(); 539771Speter if ( isa( p1 , "id" ) ) { 540771Speter p = rvalue( r[ 2 ] , contype , RREQ ); 541771Speter if ( ( p == NIL ) || ( p1 == NIL ) ) { 542771Speter return NIL; 543771Speter } 544771Speter if ( isa( p , "i" ) && isa( p1 , "d" ) ) { 545771Speter putop( P2SCONV , P2DOUBLE ); 546771Speter } 547771Speter p1 = rvalue( r[ 3 ] , contype , RREQ ); 548771Speter if ( isa( p , "d" ) && isa( p1 , "i" ) ) { 549771Speter putop( P2SCONV , P2DOUBLE ); 550771Speter } 551771Speter if ( isa( p , "id" ) ) { 552771Speter if ( isa( p , "d" ) || isa( p1 , "d" ) ) { 553771Speter ctype = P2DOUBLE; 554771Speter rettype = nl + TDOUBLE; 555771Speter } else { 556771Speter ctype = P2INT; 557771Speter rettype = nl + T4INT; 558771Speter } 559771Speter putop( mathop[ r[0] - T_MULT ] , ctype ); 560771Speter return rettype; 561771Speter } 562771Speter } 563771Speter if ( isa( p1 , "t" ) ) { 564771Speter putleaf( P2ICON , 0 , 0 565771Speter , ADDTYPE( ADDTYPE( P2PTR | P2STRTY , P2FTN ) 566771Speter , P2PTR ) 567771Speter , setop[ r[0] - T_MULT ] ); 5681555Speter if ( contype == NIL ) { 5691555Speter contype = p1; 5701555Speter if ( contype == lookup( intset ) -> type ) { 5711555Speter codeoff(); 5721555Speter contype = rvalue( r[2] , NIL , LREQ ); 5731555Speter codeon(); 5741555Speter } 5751555Speter } 5761555Speter if ( contype == NIL ) { 5771555Speter return NIL; 5781555Speter } 5791555Speter /* 5801555Speter * allocate a temporary and use it 5811555Speter */ 582*3227Smckusic tempoff = tmpalloc(lwidth(contype), contype, NOREG); 583771Speter putLV( 0 , cbn , tempoff , P2PTR|P2STRTY ); 5841555Speter p = rvalue( r[2] , contype , LREQ ); 585771Speter if ( isa( p , "t" ) ) { 586771Speter putop( P2LISTOP , P2INT ); 587771Speter if ( p == NIL || p1 == NIL ) { 588771Speter return NIL; 589771Speter } 590771Speter p1 = rvalue( r[3] , p , LREQ ); 591771Speter if ( p != p1 ) { 592771Speter error("Set types of operands of %s must be identical", opname); 593771Speter return NIL; 594771Speter } 595771Speter putop( P2LISTOP , P2INT ); 596771Speter putleaf( P2ICON , lwidth( p1 ) / sizeof( long ) , 0 597771Speter , P2INT , 0 ); 598771Speter putop( P2LISTOP , P2INT ); 599771Speter putop( P2CALL , P2PTR | P2STRTY ); 600771Speter return p; 601771Speter } 602771Speter } 603771Speter if ( isnta( p1 , "idt" ) ) { 604771Speter /* 605771Speter * find type of left operand for error message. 606771Speter */ 607771Speter p = rvalue( r[2] , contype , RREQ ); 608771Speter } 609771Speter /* 610771Speter * don't give spurious error messages. 611771Speter */ 612771Speter if ( p == NIL || p1 == NIL ) { 613771Speter return NIL; 614771Speter } 615771Speter # endif PC 616771Speter if (isnta(p, "idt")) { 617771Speter error("Left operand of %s must be integer, real or set, not %s", opname, nameof(p)); 618771Speter return (NIL); 619771Speter } 620771Speter if (isnta(p1, "idt")) { 621771Speter error("Right operand of %s must be integer, real or set, not %s", opname, nameof(p1)); 622771Speter return (NIL); 623771Speter } 624771Speter error("Cannot mix sets with integers and reals as operands of %s", opname); 625771Speter return (NIL); 626771Speter 627771Speter case T_MOD: 628771Speter case T_DIV: 629771Speter p = rvalue(r[2], NIL , RREQ ); 630771Speter p1 = rvalue(r[3], NIL , RREQ ); 631771Speter if (p == NIL || p1 == NIL) 632771Speter return (NIL); 633771Speter if (isnta(p, "i")) { 634771Speter error("Left operand of %s must be integer, not %s", opname, nameof(p)); 635771Speter return (NIL); 636771Speter } 637771Speter if (isnta(p1, "i")) { 638771Speter error("Right operand of %s must be integer, not %s", opname, nameof(p1)); 639771Speter return (NIL); 640771Speter } 641771Speter # ifdef OBJ 642771Speter return (gen(NIL, r[0], width(p), width(p1))); 643771Speter # endif OBJ 644771Speter # ifdef PC 645771Speter putop( r[ 0 ] == T_DIV ? P2DIV : P2MOD , P2INT ); 646771Speter return ( nl + T4INT ); 647771Speter # endif PC 648771Speter 649771Speter case T_EQ: 650771Speter case T_NE: 651771Speter case T_LT: 652771Speter case T_GT: 653771Speter case T_LE: 654771Speter case T_GE: 655771Speter /* 656771Speter * Since there can be no, a priori, knowledge 657771Speter * of the context type should a constant string 658771Speter * or set arise, we must poke around to find such 659771Speter * a type if possible. Since constant strings can 660771Speter * always masquerade as identifiers, this is always 661771Speter * necessary. 662771Speter */ 663771Speter codeoff(); 664771Speter p1 = rvalue(r[3], NIL , RREQ ); 665771Speter codeon(); 666771Speter if (p1 == NIL) 667771Speter return (NIL); 668771Speter contype = p1; 669771Speter # ifdef OBJ 6701555Speter if (p1->class == STR) { 671771Speter /* 672771Speter * For constant strings we want 673771Speter * the longest type so as to be 674771Speter * able to do padding (more importantly 675771Speter * avoiding truncation). For clarity, 676771Speter * we get this length here. 677771Speter */ 678771Speter codeoff(); 679771Speter p = rvalue(r[2], NIL , RREQ ); 680771Speter codeon(); 681771Speter if (p == NIL) 682771Speter return (NIL); 6831555Speter if (width(p) > width(p1)) 684771Speter contype = p; 6851555Speter } else if ( isa( p1 , "t" ) ) { 6861555Speter if ( contype == lookup( intset ) -> type ) { 6871555Speter codeoff(); 6881555Speter contype = rvalue( r[2] , NIL , RREQ ); 6891555Speter codeon(); 6901555Speter if ( contype == NIL ) { 6911555Speter return NIL; 6921555Speter } 6931555Speter } 694771Speter } 695771Speter /* 696771Speter * Now we generate code for 697771Speter * the operands of the relational 698771Speter * operation. 699771Speter */ 700771Speter p = rvalue(r[2], contype , RREQ ); 701771Speter if (p == NIL) 702771Speter return (NIL); 703771Speter p1 = rvalue(r[3], p , RREQ ); 704771Speter if (p1 == NIL) 705771Speter return (NIL); 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 ) 712771Speter , c1 == TSET ? relts[ r[0] - T_EQ ] 713771Speter : relss[ r[0] - 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(); 723771Speter p = rvalue( r[ 2 ] , NIL , LREQ ); 724771Speter codeon(); 7251555Speter if ( p == NIL ) { 7261555Speter return NIL; 7271555Speter } 7281555Speter if ( lwidth( p ) > lwidth( p1 ) ) { 729771Speter contype = p; 730771Speter } 7311555Speter } else if ( c1 == TSET ) { 7321555Speter if ( contype == lookup( intset ) -> type ) { 7331555Speter codeoff(); 7341555Speter p = rvalue( r[ 2 ] , NIL , LREQ ); 7351555Speter codeon(); 7361555Speter if ( p == NIL ) { 7371555Speter return NIL; 7381555Speter } 7391555Speter contype = p; 7401555Speter } 7411627Speter } 742771Speter /* 743771Speter * put out the width of the comparison. 744771Speter */ 745771Speter putleaf( P2ICON , lwidth( contype ) , 0 , P2INT , 0 ); 746771Speter /* 747771Speter * and the left hand side, 748771Speter * for sets, strings, records 749771Speter */ 750771Speter p = rvalue( r[ 2 ] , contype , LREQ ); 751771Speter putop( P2LISTOP , P2INT ); 752771Speter p1 = rvalue( r[ 3 ] , p , LREQ ); 753771Speter putop( P2LISTOP , P2INT ); 754771Speter putop( P2CALL , P2INT ); 755771Speter } else { 756771Speter /* 757771Speter * the easy (scalar or error) case 758771Speter */ 759771Speter p = rvalue( r[ 2 ] , contype , RREQ ); 760771Speter if ( p == NIL ) { 761771Speter return NIL; 7622056Speter } 763771Speter /* 764771Speter * since the second pass can't do 765771Speter * long op double or double op long 766771Speter * we may have to do some coercing. 767771Speter */ 7682056Speter if ( isa( p , "i" ) && isa( p1 , "d" ) ) { 769771Speter putop( P2SCONV , P2DOUBLE ); 770771Speter } 771771Speter p1 = rvalue( r[ 3 ] , p , RREQ ); 772771Speter if ( isa( p , "d" ) && isa( p1 , "i" ) ) 773771Speter putop( P2SCONV , P2DOUBLE ); 774771Speter putop( relops[ r[0] - T_EQ ] , P2INT ); 775771Speter } 776771Speter # endif PC 777771Speter c = classify(p); 778771Speter c1 = classify(p1); 779771Speter if (nocomp(c) || nocomp(c1)) 780771Speter return (NIL); 781771Speter g = NIL; 782771Speter switch (c) { 783771Speter case TBOOL: 784771Speter case TCHAR: 785771Speter if (c != c1) 786771Speter goto clash; 787771Speter break; 788771Speter case TINT: 789771Speter case TDOUBLE: 790771Speter if (c1 != TINT && c1 != TDOUBLE) 791771Speter goto clash; 792771Speter break; 793771Speter case TSCAL: 794771Speter if (c1 != TSCAL) 795771Speter goto clash; 796771Speter if (scalar(p) != scalar(p1)) 797771Speter goto nonident; 798771Speter break; 799771Speter case TSET: 800771Speter if (c1 != TSET) 801771Speter goto clash; 802771Speter if (p != p1) 803771Speter goto nonident; 804771Speter g = TSET; 805771Speter break; 806771Speter case TREC: 807771Speter if ( c1 != TREC ) { 808771Speter goto clash; 809771Speter } 810771Speter if ( p != p1 ) { 811771Speter goto nonident; 812771Speter } 813771Speter if (r[0] != T_EQ && r[0] != T_NE) { 814771Speter error("%s not allowed on records - only allow = and <>" , opname ); 815771Speter return (NIL); 816771Speter } 817771Speter g = TREC; 818771Speter break; 819771Speter case TPTR: 820771Speter case TNIL: 821771Speter if (c1 != TPTR && c1 != TNIL) 822771Speter goto clash; 823771Speter if (r[0] != T_EQ && r[0] != T_NE) { 824771Speter error("%s not allowed on pointers - only allow = and <>" , opname ); 825771Speter return (NIL); 826771Speter } 827771Speter break; 828771Speter case TSTR: 829771Speter if (c1 != TSTR) 830771Speter goto clash; 831771Speter if (width(p) != width(p1)) { 832771Speter error("Strings not same length in %s comparison", opname); 833771Speter return (NIL); 834771Speter } 835771Speter g = TSTR; 836771Speter break; 837771Speter default: 838771Speter panic("rval2"); 839771Speter } 840771Speter # ifdef OBJ 841771Speter return (gen(g, r[0], width(p), width(p1))); 842771Speter # endif OBJ 843771Speter # ifdef PC 844771Speter return nl + TBOOL; 845771Speter # endif PC 846771Speter clash: 847771Speter error("%ss and %ss cannot be compared - operator was %s", clnames[c], clnames[c1], opname); 848771Speter return (NIL); 849771Speter nonident: 850771Speter error("%s types must be identical in comparisons - operator was %s", clnames[c1], opname); 851771Speter return (NIL); 852771Speter 853771Speter case T_IN: 854771Speter rt = r[3]; 855771Speter # ifdef OBJ 856771Speter if (rt != NIL && rt[0] == T_CSET) { 857771Speter precset( rt , NIL , &csetd ); 858771Speter p1 = csetd.csettype; 859771Speter if (p1 == NIL) 860771Speter return NIL; 861771Speter postcset( rt, &csetd); 862771Speter } else { 863771Speter p1 = stkrval(r[3], NIL , RREQ ); 864771Speter rt = NIL; 865771Speter } 866771Speter # endif OBJ 867771Speter # ifdef PC 868771Speter if (rt != NIL && rt[0] == T_CSET) { 869771Speter if ( precset( rt , NIL , &csetd ) ) { 8701555Speter putleaf( P2ICON , 0 , 0 8711555Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 8721555Speter , "_IN" ); 873771Speter } else { 874771Speter putleaf( P2ICON , 0 , 0 875771Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 876771Speter , "_INCT" ); 877771Speter } 878771Speter p1 = csetd.csettype; 879771Speter if (p1 == NIL) 880771Speter return NIL; 881771Speter } else { 882771Speter putleaf( P2ICON , 0 , 0 883771Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 884771Speter , "_IN" ); 885771Speter codeoff(); 886771Speter p1 = rvalue(r[3], NIL , LREQ ); 887771Speter codeon(); 888771Speter } 889771Speter # endif PC 890771Speter p = stkrval(r[2], NIL , RREQ ); 891771Speter if (p == NIL || p1 == NIL) 892771Speter return (NIL); 893771Speter if (p1->class != SET) { 894771Speter error("Right operand of 'in' must be a set, not %s", nameof(p1)); 895771Speter return (NIL); 896771Speter } 897771Speter if (incompat(p, p1->type, r[2])) { 898771Speter cerror("Index type clashed with set component type for 'in'"); 899771Speter return (NIL); 900771Speter } 901771Speter setran(p1->type); 902771Speter # ifdef OBJ 903771Speter if (rt == NIL || csetd.comptime) 904771Speter put(4, O_IN, width(p1), set.lwrb, set.uprbp); 905771Speter else 9063078Smckusic put(2, O_INCT, 9073078Smckusic (int)(3 + csetd.singcnt + 2*csetd.paircnt)); 908771Speter # endif OBJ 909771Speter # ifdef PC 910771Speter if ( rt == NIL || rt[0] != T_CSET ) { 911771Speter putleaf( P2ICON , set.lwrb , 0 , P2INT , 0 ); 912771Speter putop( P2LISTOP , P2INT ); 913771Speter putleaf( P2ICON , set.uprbp , 0 , P2INT , 0 ); 914771Speter putop( P2LISTOP , P2INT ); 915771Speter p1 = rvalue( r[3] , NIL , LREQ ); 916771Speter putop( P2LISTOP , P2INT ); 917771Speter } else if ( csetd.comptime ) { 918771Speter putleaf( P2ICON , set.lwrb , 0 , P2INT , 0 ); 919771Speter putop( P2LISTOP , P2INT ); 920771Speter putleaf( P2ICON , set.uprbp , 0 , P2INT , 0 ); 921771Speter putop( P2LISTOP , P2INT ); 922771Speter postcset( r[3] , &csetd ); 923771Speter putop( P2LISTOP , P2INT ); 924771Speter } else { 925771Speter postcset( r[3] , &csetd ); 926771Speter } 927771Speter putop( P2CALL , P2INT ); 928771Speter # endif PC 929771Speter return (nl+T1BOOL); 930771Speter default: 931771Speter if (r[2] == NIL) 932771Speter return (NIL); 933771Speter switch (r[0]) { 934771Speter default: 935771Speter panic("rval3"); 936771Speter 937771Speter 938771Speter /* 939771Speter * An octal number 940771Speter */ 941771Speter case T_BINT: 942771Speter f = a8tol(r[2]); 943771Speter goto conint; 944771Speter 945771Speter /* 946771Speter * A decimal number 947771Speter */ 948771Speter case T_INT: 949771Speter f = atof(r[2]); 950771Speter conint: 951771Speter if (f > MAXINT || f < MININT) { 952771Speter error("Constant too large for this implementation"); 953771Speter return (NIL); 954771Speter } 955771Speter l = f; 956771Speter if (bytes(l, l) <= 2) { 957771Speter # ifdef OBJ 958771Speter put(2, O_CON2, ( short ) l); 959771Speter # endif OBJ 960771Speter # ifdef PC 961771Speter /* 962771Speter * short constants are ints 963771Speter */ 964771Speter putleaf( P2ICON , l , 0 , P2INT , 0 ); 965771Speter # endif PC 966771Speter return (nl+T2INT); 967771Speter } 968771Speter # ifdef OBJ 969771Speter put(2, O_CON4, l); 970771Speter # endif OBJ 971771Speter # ifdef PC 972771Speter putleaf( P2ICON , l , 0 , P2INT , 0 ); 973771Speter # endif PC 974771Speter return (nl+T4INT); 975771Speter 976771Speter /* 977771Speter * A floating point number 978771Speter */ 979771Speter case T_FINT: 980771Speter # ifdef OBJ 981771Speter put(2, O_CON8, atof(r[2])); 982771Speter # endif OBJ 983771Speter # ifdef PC 984771Speter putCON8( atof( r[2] ) ); 985771Speter # endif PC 986771Speter return (nl+TDOUBLE); 987771Speter 988771Speter /* 989771Speter * Constant strings. Note that constant characters 990771Speter * are constant strings of length one; there is 991771Speter * no constant string of length one. 992771Speter */ 993771Speter case T_STRNG: 994771Speter cp = r[2]; 995771Speter if (cp[1] == 0) { 996771Speter # ifdef OBJ 997771Speter put(2, O_CONC, cp[0]); 998771Speter # endif OBJ 999771Speter # ifdef PC 1000771Speter putleaf( P2ICON , cp[0] , 0 , P2CHAR , 0 ); 1001771Speter # endif PC 1002771Speter return (nl+T1CHAR); 1003771Speter } 1004771Speter goto cstrng; 1005771Speter } 1006771Speter 1007771Speter } 1008771Speter } 1009771Speter 1010771Speter /* 1011771Speter * Can a class appear 1012771Speter * in a comparison ? 1013771Speter */ 1014771Speter nocomp(c) 1015771Speter int c; 1016771Speter { 1017771Speter 1018771Speter switch (c) { 1019771Speter case TREC: 10201627Speter if ( line != reccompline ) { 10211627Speter reccompline = line; 10221627Speter warning(); 10231627Speter if ( opt( 's' ) ) { 10241627Speter standard(); 10251627Speter } 1026771Speter error("record comparison is non-standard"); 1027771Speter } 1028771Speter break; 1029771Speter case TFILE: 1030771Speter case TARY: 1031771Speter error("%ss may not participate in comparisons", clnames[c]); 1032771Speter return (1); 1033771Speter } 1034771Speter return (NIL); 1035771Speter } 1036771Speter 1037771Speter /* 1038771Speter * this is sort of like gconst, except it works on expression trees 1039771Speter * rather than declaration trees, and doesn't give error messages for 1040771Speter * non-constant things. 1041771Speter * as a side effect this fills in the con structure that gconst uses. 1042771Speter * this returns TRUE or FALSE. 1043771Speter */ 1044771Speter constval(r) 1045771Speter register int *r; 1046771Speter { 1047771Speter register struct nl *np; 1048771Speter register *cn; 1049771Speter char *cp; 1050771Speter int negd, sgnd; 1051771Speter long ci; 1052771Speter 1053771Speter con.ctype = NIL; 1054771Speter cn = r; 1055771Speter negd = sgnd = 0; 1056771Speter loop: 1057771Speter /* 1058771Speter * cn[2] is nil if error recovery generated a T_STRNG 1059771Speter */ 1060771Speter if (cn == NIL || cn[2] == NIL) 1061771Speter return FALSE; 1062771Speter switch (cn[0]) { 1063771Speter default: 1064771Speter return FALSE; 1065771Speter case T_MINUS: 1066771Speter negd = 1 - negd; 1067771Speter /* and fall through */ 1068771Speter case T_PLUS: 1069771Speter sgnd++; 1070771Speter cn = cn[2]; 1071771Speter goto loop; 1072771Speter case T_NIL: 1073771Speter con.cpval = NIL; 1074771Speter con.cival = 0; 1075771Speter con.crval = con.cival; 1076771Speter con.ctype = nl + TNIL; 1077771Speter break; 1078771Speter case T_VAR: 1079771Speter np = lookup(cn[2]); 1080771Speter if (np == NIL || np->class != CONST) { 1081771Speter return FALSE; 1082771Speter } 1083771Speter if ( cn[3] != NIL ) { 1084771Speter return FALSE; 1085771Speter } 1086771Speter con.ctype = np->type; 1087771Speter switch (classify(np->type)) { 1088771Speter case TINT: 1089771Speter con.crval = np->range[0]; 1090771Speter break; 1091771Speter case TDOUBLE: 1092771Speter con.crval = np->real; 1093771Speter break; 1094771Speter case TBOOL: 1095771Speter case TCHAR: 1096771Speter case TSCAL: 1097771Speter con.cival = np->value[0]; 1098771Speter con.crval = con.cival; 1099771Speter break; 1100771Speter case TSTR: 1101771Speter con.cpval = np->ptr[0]; 1102771Speter break; 1103771Speter default: 1104771Speter con.ctype = NIL; 1105771Speter return FALSE; 1106771Speter } 1107771Speter break; 1108771Speter case T_BINT: 1109771Speter con.crval = a8tol(cn[2]); 1110771Speter goto restcon; 1111771Speter case T_INT: 1112771Speter con.crval = atof(cn[2]); 1113771Speter if (con.crval > MAXINT || con.crval < MININT) { 1114771Speter derror("Constant too large for this implementation"); 1115771Speter con.crval = 0; 1116771Speter } 1117771Speter restcon: 1118771Speter ci = con.crval; 1119771Speter #ifndef PI0 1120771Speter if (bytes(ci, ci) <= 2) 1121771Speter con.ctype = nl+T2INT; 1122771Speter else 1123771Speter #endif 1124771Speter con.ctype = nl+T4INT; 1125771Speter break; 1126771Speter case T_FINT: 1127771Speter con.ctype = nl+TDOUBLE; 1128771Speter con.crval = atof(cn[2]); 1129771Speter break; 1130771Speter case T_STRNG: 1131771Speter cp = cn[2]; 1132771Speter if (cp[1] == 0) { 1133771Speter con.ctype = nl+T1CHAR; 1134771Speter con.cival = cp[0]; 1135771Speter con.crval = con.cival; 1136771Speter break; 1137771Speter } 1138771Speter con.ctype = nl+TSTR; 1139771Speter con.cpval = cp; 1140771Speter break; 1141771Speter } 1142771Speter if (sgnd) { 1143771Speter if (isnta(con.ctype, "id")) { 1144771Speter derror("%s constants cannot be signed", nameof(con.ctype)); 1145771Speter return FALSE; 1146771Speter } else if (negd) 1147771Speter con.crval = -con.crval; 1148771Speter } 1149771Speter return TRUE; 1150771Speter } 1151