1771Speter /* Copyright (c) 1979 Regents of the University of California */ 2771Speter 3*3155Smckusic static char sccsid[] = "@(#)rval.c 1.9 03/09/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 227*3155Smckusic 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 */ 375771Speter sizes[ cbn ].om_off -= lwidth( csetd.csettype ); 376771Speter tempoff = sizes[ cbn ].om_off; 377771Speter putlbracket( ftnno , -tempoff ); 378771Speter if ( tempoff < sizes[ cbn ].om_max ) { 379771Speter sizes[ cbn ].om_max = tempoff; 380771Speter } 381771Speter putLV( 0 , cbn , tempoff , P2PTR|P2STRTY ); 382771Speter setran( ( csetd.csettype ) -> type ); 383771Speter putleaf( P2ICON , set.lwrb , 0 , P2INT , 0 ); 384771Speter putop( P2LISTOP , P2INT ); 385771Speter putleaf( P2ICON , set.uprbp , 0 , P2INT , 0 ); 386771Speter putop( P2LISTOP , P2INT ); 387771Speter postcset( r , &csetd ); 388771Speter putop( P2CALL , P2INT ); 389771Speter } 390771Speter return csetd.csettype; 391771Speter # endif PC 392771Speter 393771Speter /* 394771Speter * Unary plus and minus 395771Speter */ 396771Speter case T_PLUS: 397771Speter case T_MINUS: 398771Speter q = rvalue(r[2], NIL , RREQ ); 399771Speter if (q == NIL) 400771Speter return (NIL); 401771Speter if (isnta(q, "id")) { 402771Speter error("Operand of %s must be integer or real, not %s", opname, nameof(q)); 403771Speter return (NIL); 404771Speter } 405771Speter if (r[0] == T_MINUS) { 406771Speter # ifdef OBJ 407771Speter put(1, O_NEG2 + (width(q) >> 2)); 408771Speter # endif OBJ 409771Speter # ifdef PC 410771Speter putop( P2UNARY P2MINUS , p2type( q ) ); 411771Speter # endif PC 412771Speter return (isa(q, "d") ? q : nl+T4INT); 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 428771Speter putop( P2NOT , P2INT ); 429771Speter # endif PC 430771Speter return (nl+T1BOOL); 431771Speter 432771Speter case T_AND: 433771Speter case T_OR: 434771Speter p = rvalue(r[2], NIL , RREQ ); 435771Speter p1 = rvalue(r[3], NIL , RREQ ); 436771Speter if (p == NIL || p1 == NIL) 437771Speter return (NIL); 438771Speter if (isnta(p, "b")) { 439771Speter error("Left operand of %s must be Boolean, not %s", opname, nameof(p)); 440771Speter return (NIL); 441771Speter } 442771Speter if (isnta(p1, "b")) { 443771Speter error("Right operand of %s must be Boolean, not %s", opname, nameof(p1)); 444771Speter return (NIL); 445771Speter } 446771Speter # ifdef OBJ 447771Speter put(1, r[0] == T_AND ? O_AND : O_OR); 448771Speter # endif OBJ 449771Speter # ifdef PC 450771Speter /* 451771Speter * note the use of & and | rather than && and || 452771Speter * to force evaluation of all the expressions. 453771Speter */ 454771Speter putop( r[ 0 ] == T_AND ? P2AND : P2OR , P2INT ); 455771Speter # endif PC 456771Speter return (nl+T1BOOL); 457771Speter 458771Speter case T_DIVD: 459771Speter # ifdef OBJ 460771Speter p = rvalue(r[2], NIL , RREQ ); 461771Speter p1 = rvalue(r[3], NIL , RREQ ); 462771Speter # endif OBJ 463771Speter # ifdef PC 464771Speter /* 465771Speter * force these to be doubles for the divide 466771Speter */ 467771Speter p = rvalue( r[ 2 ] , NIL , RREQ ); 468771Speter if ( isnta( p , "d" ) ) { 469771Speter putop( P2SCONV , P2DOUBLE ); 470771Speter } 471771Speter p1 = rvalue( r[ 3 ] , NIL , RREQ ); 472771Speter if ( isnta( p1 , "d" ) ) { 473771Speter putop( P2SCONV , P2DOUBLE ); 474771Speter } 475771Speter # endif PC 476771Speter if (p == NIL || p1 == NIL) 477771Speter return (NIL); 478771Speter if (isnta(p, "id")) { 479771Speter error("Left operand of / must be integer or real, not %s", nameof(p)); 480771Speter return (NIL); 481771Speter } 482771Speter if (isnta(p1, "id")) { 483771Speter error("Right operand of / must be integer or real, not %s", nameof(p1)); 484771Speter return (NIL); 485771Speter } 486771Speter # ifdef OBJ 487771Speter return gen(NIL, r[0], width(p), width(p1)); 488771Speter # endif OBJ 489771Speter # ifdef PC 490771Speter putop( P2DIV , P2DOUBLE ); 491771Speter return nl + TDOUBLE; 492771Speter # endif PC 493771Speter 494771Speter case T_MULT: 495771Speter case T_ADD: 496771Speter case T_SUB: 497771Speter # ifdef OBJ 498771Speter /* 4991555Speter * If the context hasn't told us the type 5001555Speter * and a constant set is present 5011555Speter * we need to infer the type 5021555Speter * before generating code. 503771Speter */ 5041555Speter if ( contype == NIL ) { 505771Speter codeoff(); 5061555Speter contype = rvalue( r[3] , NIL , RREQ ); 507771Speter codeon(); 5081555Speter if ( contype == lookup( intset ) -> type ) { 5091555Speter codeoff(); 5101555Speter contype = rvalue( r[2] , NIL , RREQ ); 5111555Speter codeon(); 5121555Speter } 513771Speter } 5141555Speter if ( contype == NIL ) { 5151555Speter return NIL; 5161555Speter } 5171555Speter p = rvalue( r[2] , contype , RREQ ); 5181555Speter p1 = rvalue( r[3] , p , RREQ ); 5191555Speter if ( p == NIL || p1 == NIL ) 5201555Speter return NIL; 521771Speter if (isa(p, "id") && isa(p1, "id")) 522771Speter return (gen(NIL, r[0], width(p), width(p1))); 523771Speter if (isa(p, "t") && isa(p1, "t")) { 524771Speter if (p != p1) { 525771Speter error("Set types of operands of %s must be identical", opname); 526771Speter return (NIL); 527771Speter } 528771Speter gen(TSET, r[0], width(p), 0); 529771Speter return (p); 530771Speter } 531771Speter # endif OBJ 532771Speter # ifdef PC 533771Speter /* 534771Speter * the second pass can't do 535771Speter * long op double or double op long 536771Speter * so we have to know the type of both operands 537771Speter * also, it gets tricky for sets, which are done 538771Speter * by function calls. 539771Speter */ 540771Speter codeoff(); 541771Speter p1 = rvalue( r[ 3 ] , contype , RREQ ); 542771Speter codeon(); 543771Speter if ( isa( p1 , "id" ) ) { 544771Speter p = rvalue( r[ 2 ] , contype , RREQ ); 545771Speter if ( ( p == NIL ) || ( p1 == NIL ) ) { 546771Speter return NIL; 547771Speter } 548771Speter if ( isa( p , "i" ) && isa( p1 , "d" ) ) { 549771Speter putop( P2SCONV , P2DOUBLE ); 550771Speter } 551771Speter p1 = rvalue( r[ 3 ] , contype , RREQ ); 552771Speter if ( isa( p , "d" ) && isa( p1 , "i" ) ) { 553771Speter putop( P2SCONV , P2DOUBLE ); 554771Speter } 555771Speter if ( isa( p , "id" ) ) { 556771Speter if ( isa( p , "d" ) || isa( p1 , "d" ) ) { 557771Speter ctype = P2DOUBLE; 558771Speter rettype = nl + TDOUBLE; 559771Speter } else { 560771Speter ctype = P2INT; 561771Speter rettype = nl + T4INT; 562771Speter } 563771Speter putop( mathop[ r[0] - T_MULT ] , ctype ); 564771Speter return rettype; 565771Speter } 566771Speter } 567771Speter if ( isa( p1 , "t" ) ) { 568771Speter putleaf( P2ICON , 0 , 0 569771Speter , ADDTYPE( ADDTYPE( P2PTR | P2STRTY , P2FTN ) 570771Speter , P2PTR ) 571771Speter , setop[ r[0] - T_MULT ] ); 5721555Speter if ( contype == NIL ) { 5731555Speter contype = p1; 5741555Speter if ( contype == lookup( intset ) -> type ) { 5751555Speter codeoff(); 5761555Speter contype = rvalue( r[2] , NIL , LREQ ); 5771555Speter codeon(); 5781555Speter } 5791555Speter } 5801555Speter if ( contype == NIL ) { 5811555Speter return NIL; 5821555Speter } 5831555Speter /* 5841555Speter * allocate a temporary and use it 5851555Speter */ 5861555Speter sizes[ cbn ].om_off -= lwidth( contype ); 587771Speter tempoff = sizes[ cbn ].om_off; 588771Speter putlbracket( ftnno , -tempoff ); 589771Speter if ( tempoff < sizes[ cbn ].om_max ) { 590771Speter sizes[ cbn ].om_max = tempoff; 591771Speter } 592771Speter putLV( 0 , cbn , tempoff , P2PTR|P2STRTY ); 5931555Speter p = rvalue( r[2] , contype , LREQ ); 594771Speter if ( isa( p , "t" ) ) { 595771Speter putop( P2LISTOP , P2INT ); 596771Speter if ( p == NIL || p1 == NIL ) { 597771Speter return NIL; 598771Speter } 599771Speter p1 = rvalue( r[3] , p , LREQ ); 600771Speter if ( p != p1 ) { 601771Speter error("Set types of operands of %s must be identical", opname); 602771Speter return NIL; 603771Speter } 604771Speter putop( P2LISTOP , P2INT ); 605771Speter putleaf( P2ICON , lwidth( p1 ) / sizeof( long ) , 0 606771Speter , P2INT , 0 ); 607771Speter putop( P2LISTOP , P2INT ); 608771Speter putop( P2CALL , P2PTR | P2STRTY ); 609771Speter return p; 610771Speter } 611771Speter } 612771Speter if ( isnta( p1 , "idt" ) ) { 613771Speter /* 614771Speter * find type of left operand for error message. 615771Speter */ 616771Speter p = rvalue( r[2] , contype , RREQ ); 617771Speter } 618771Speter /* 619771Speter * don't give spurious error messages. 620771Speter */ 621771Speter if ( p == NIL || p1 == NIL ) { 622771Speter return NIL; 623771Speter } 624771Speter # endif PC 625771Speter if (isnta(p, "idt")) { 626771Speter error("Left operand of %s must be integer, real or set, not %s", opname, nameof(p)); 627771Speter return (NIL); 628771Speter } 629771Speter if (isnta(p1, "idt")) { 630771Speter error("Right operand of %s must be integer, real or set, not %s", opname, nameof(p1)); 631771Speter return (NIL); 632771Speter } 633771Speter error("Cannot mix sets with integers and reals as operands of %s", opname); 634771Speter return (NIL); 635771Speter 636771Speter case T_MOD: 637771Speter case T_DIV: 638771Speter p = rvalue(r[2], NIL , RREQ ); 639771Speter p1 = rvalue(r[3], NIL , RREQ ); 640771Speter if (p == NIL || p1 == NIL) 641771Speter return (NIL); 642771Speter if (isnta(p, "i")) { 643771Speter error("Left operand of %s must be integer, not %s", opname, nameof(p)); 644771Speter return (NIL); 645771Speter } 646771Speter if (isnta(p1, "i")) { 647771Speter error("Right operand of %s must be integer, not %s", opname, nameof(p1)); 648771Speter return (NIL); 649771Speter } 650771Speter # ifdef OBJ 651771Speter return (gen(NIL, r[0], width(p), width(p1))); 652771Speter # endif OBJ 653771Speter # ifdef PC 654771Speter putop( r[ 0 ] == 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(); 673771Speter p1 = rvalue(r[3], NIL , RREQ ); 674771Speter codeon(); 675771Speter if (p1 == NIL) 676771Speter return (NIL); 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(); 688771Speter p = rvalue(r[2], NIL , RREQ ); 689771Speter codeon(); 690771Speter if (p == NIL) 691771Speter return (NIL); 6921555Speter if (width(p) > width(p1)) 693771Speter contype = p; 6941555Speter } else if ( isa( p1 , "t" ) ) { 6951555Speter if ( contype == lookup( intset ) -> type ) { 6961555Speter codeoff(); 6971555Speter contype = rvalue( r[2] , NIL , RREQ ); 6981555Speter codeon(); 6991555Speter if ( contype == NIL ) { 7001555Speter return NIL; 7011555Speter } 7021555Speter } 703771Speter } 704771Speter /* 705771Speter * Now we generate code for 706771Speter * the operands of the relational 707771Speter * operation. 708771Speter */ 709771Speter p = rvalue(r[2], contype , RREQ ); 710771Speter if (p == NIL) 711771Speter return (NIL); 712771Speter p1 = rvalue(r[3], p , RREQ ); 713771Speter if (p1 == NIL) 714771Speter return (NIL); 715771Speter # endif OBJ 716771Speter # ifdef PC 717771Speter c1 = classify( p1 ); 718771Speter if ( c1 == TSET || c1 == TSTR || c1 == TREC ) { 719771Speter putleaf( P2ICON , 0 , 0 720771Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 721771Speter , c1 == TSET ? relts[ r[0] - T_EQ ] 722771Speter : relss[ r[0] - T_EQ ] ); 723771Speter /* 724771Speter * for [] and strings, comparisons are done on 725771Speter * the maximum width of the two sides. 726771Speter * for other sets, we have to ask the left side 727771Speter * what type it is based on the type of the right. 728771Speter * (this matters for intsets). 729771Speter */ 7301555Speter if ( c1 == TSTR ) { 731771Speter codeoff(); 732771Speter p = rvalue( r[ 2 ] , NIL , LREQ ); 733771Speter codeon(); 7341555Speter if ( p == NIL ) { 7351555Speter return NIL; 7361555Speter } 7371555Speter if ( lwidth( p ) > lwidth( p1 ) ) { 738771Speter contype = p; 739771Speter } 7401555Speter } else if ( c1 == TSET ) { 7411555Speter if ( contype == lookup( intset ) -> type ) { 7421555Speter codeoff(); 7431555Speter p = rvalue( r[ 2 ] , NIL , LREQ ); 7441555Speter codeon(); 7451555Speter if ( p == NIL ) { 7461555Speter return NIL; 7471555Speter } 7481555Speter contype = p; 7491555Speter } 7501627Speter } 751771Speter /* 752771Speter * put out the width of the comparison. 753771Speter */ 754771Speter putleaf( P2ICON , lwidth( contype ) , 0 , P2INT , 0 ); 755771Speter /* 756771Speter * and the left hand side, 757771Speter * for sets, strings, records 758771Speter */ 759771Speter p = rvalue( r[ 2 ] , contype , LREQ ); 760771Speter putop( P2LISTOP , P2INT ); 761771Speter p1 = rvalue( r[ 3 ] , p , LREQ ); 762771Speter putop( P2LISTOP , P2INT ); 763771Speter putop( P2CALL , P2INT ); 764771Speter } else { 765771Speter /* 766771Speter * the easy (scalar or error) case 767771Speter */ 768771Speter p = rvalue( r[ 2 ] , contype , RREQ ); 769771Speter if ( p == NIL ) { 770771Speter return NIL; 7712056Speter } 772771Speter /* 773771Speter * since the second pass can't do 774771Speter * long op double or double op long 775771Speter * we may have to do some coercing. 776771Speter */ 7772056Speter if ( isa( p , "i" ) && isa( p1 , "d" ) ) { 778771Speter putop( P2SCONV , P2DOUBLE ); 779771Speter } 780771Speter p1 = rvalue( r[ 3 ] , p , RREQ ); 781771Speter if ( isa( p , "d" ) && isa( p1 , "i" ) ) 782771Speter putop( P2SCONV , P2DOUBLE ); 783771Speter putop( relops[ r[0] - T_EQ ] , P2INT ); 784771Speter } 785771Speter # endif PC 786771Speter c = classify(p); 787771Speter c1 = classify(p1); 788771Speter if (nocomp(c) || nocomp(c1)) 789771Speter return (NIL); 790771Speter g = NIL; 791771Speter switch (c) { 792771Speter case TBOOL: 793771Speter case TCHAR: 794771Speter if (c != c1) 795771Speter goto clash; 796771Speter break; 797771Speter case TINT: 798771Speter case TDOUBLE: 799771Speter if (c1 != TINT && c1 != TDOUBLE) 800771Speter goto clash; 801771Speter break; 802771Speter case TSCAL: 803771Speter if (c1 != TSCAL) 804771Speter goto clash; 805771Speter if (scalar(p) != scalar(p1)) 806771Speter goto nonident; 807771Speter break; 808771Speter case TSET: 809771Speter if (c1 != TSET) 810771Speter goto clash; 811771Speter if (p != p1) 812771Speter goto nonident; 813771Speter g = TSET; 814771Speter break; 815771Speter case TREC: 816771Speter if ( c1 != TREC ) { 817771Speter goto clash; 818771Speter } 819771Speter if ( p != p1 ) { 820771Speter goto nonident; 821771Speter } 822771Speter if (r[0] != T_EQ && r[0] != T_NE) { 823771Speter error("%s not allowed on records - only allow = and <>" , opname ); 824771Speter return (NIL); 825771Speter } 826771Speter g = TREC; 827771Speter break; 828771Speter case TPTR: 829771Speter case TNIL: 830771Speter if (c1 != TPTR && c1 != TNIL) 831771Speter goto clash; 832771Speter if (r[0] != T_EQ && r[0] != T_NE) { 833771Speter error("%s not allowed on pointers - only allow = and <>" , opname ); 834771Speter return (NIL); 835771Speter } 836771Speter break; 837771Speter case TSTR: 838771Speter if (c1 != TSTR) 839771Speter goto clash; 840771Speter if (width(p) != width(p1)) { 841771Speter error("Strings not same length in %s comparison", opname); 842771Speter return (NIL); 843771Speter } 844771Speter g = TSTR; 845771Speter break; 846771Speter default: 847771Speter panic("rval2"); 848771Speter } 849771Speter # ifdef OBJ 850771Speter return (gen(g, r[0], width(p), width(p1))); 851771Speter # endif OBJ 852771Speter # ifdef PC 853771Speter return nl + TBOOL; 854771Speter # endif PC 855771Speter clash: 856771Speter error("%ss and %ss cannot be compared - operator was %s", clnames[c], clnames[c1], opname); 857771Speter return (NIL); 858771Speter nonident: 859771Speter error("%s types must be identical in comparisons - operator was %s", clnames[c1], opname); 860771Speter return (NIL); 861771Speter 862771Speter case T_IN: 863771Speter rt = r[3]; 864771Speter # ifdef OBJ 865771Speter if (rt != NIL && rt[0] == T_CSET) { 866771Speter precset( rt , NIL , &csetd ); 867771Speter p1 = csetd.csettype; 868771Speter if (p1 == NIL) 869771Speter return NIL; 870771Speter postcset( rt, &csetd); 871771Speter } else { 872771Speter p1 = stkrval(r[3], NIL , RREQ ); 873771Speter rt = NIL; 874771Speter } 875771Speter # endif OBJ 876771Speter # ifdef PC 877771Speter if (rt != NIL && rt[0] == T_CSET) { 878771Speter if ( precset( rt , NIL , &csetd ) ) { 8791555Speter putleaf( P2ICON , 0 , 0 8801555Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 8811555Speter , "_IN" ); 882771Speter } else { 883771Speter putleaf( P2ICON , 0 , 0 884771Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 885771Speter , "_INCT" ); 886771Speter } 887771Speter p1 = csetd.csettype; 888771Speter if (p1 == NIL) 889771Speter return NIL; 890771Speter } else { 891771Speter putleaf( P2ICON , 0 , 0 892771Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 893771Speter , "_IN" ); 894771Speter codeoff(); 895771Speter p1 = rvalue(r[3], NIL , LREQ ); 896771Speter codeon(); 897771Speter } 898771Speter # endif PC 899771Speter p = stkrval(r[2], NIL , RREQ ); 900771Speter if (p == NIL || p1 == NIL) 901771Speter return (NIL); 902771Speter if (p1->class != SET) { 903771Speter error("Right operand of 'in' must be a set, not %s", nameof(p1)); 904771Speter return (NIL); 905771Speter } 906771Speter if (incompat(p, p1->type, r[2])) { 907771Speter cerror("Index type clashed with set component type for 'in'"); 908771Speter return (NIL); 909771Speter } 910771Speter setran(p1->type); 911771Speter # ifdef OBJ 912771Speter if (rt == NIL || csetd.comptime) 913771Speter put(4, O_IN, width(p1), set.lwrb, set.uprbp); 914771Speter else 9153078Smckusic put(2, O_INCT, 9163078Smckusic (int)(3 + csetd.singcnt + 2*csetd.paircnt)); 917771Speter # endif OBJ 918771Speter # ifdef PC 919771Speter if ( rt == NIL || rt[0] != T_CSET ) { 920771Speter putleaf( P2ICON , set.lwrb , 0 , P2INT , 0 ); 921771Speter putop( P2LISTOP , P2INT ); 922771Speter putleaf( P2ICON , set.uprbp , 0 , P2INT , 0 ); 923771Speter putop( P2LISTOP , P2INT ); 924771Speter p1 = rvalue( r[3] , NIL , LREQ ); 925771Speter putop( P2LISTOP , P2INT ); 926771Speter } else if ( csetd.comptime ) { 927771Speter putleaf( P2ICON , set.lwrb , 0 , P2INT , 0 ); 928771Speter putop( P2LISTOP , P2INT ); 929771Speter putleaf( P2ICON , set.uprbp , 0 , P2INT , 0 ); 930771Speter putop( P2LISTOP , P2INT ); 931771Speter postcset( r[3] , &csetd ); 932771Speter putop( P2LISTOP , P2INT ); 933771Speter } else { 934771Speter postcset( r[3] , &csetd ); 935771Speter } 936771Speter putop( P2CALL , P2INT ); 937771Speter # endif PC 938771Speter return (nl+T1BOOL); 939771Speter default: 940771Speter if (r[2] == NIL) 941771Speter return (NIL); 942771Speter switch (r[0]) { 943771Speter default: 944771Speter panic("rval3"); 945771Speter 946771Speter 947771Speter /* 948771Speter * An octal number 949771Speter */ 950771Speter case T_BINT: 951771Speter f = a8tol(r[2]); 952771Speter goto conint; 953771Speter 954771Speter /* 955771Speter * A decimal number 956771Speter */ 957771Speter case T_INT: 958771Speter f = atof(r[2]); 959771Speter conint: 960771Speter if (f > MAXINT || f < MININT) { 961771Speter error("Constant too large for this implementation"); 962771Speter return (NIL); 963771Speter } 964771Speter l = f; 965771Speter if (bytes(l, l) <= 2) { 966771Speter # ifdef OBJ 967771Speter put(2, O_CON2, ( short ) l); 968771Speter # endif OBJ 969771Speter # ifdef PC 970771Speter /* 971771Speter * short constants are ints 972771Speter */ 973771Speter putleaf( P2ICON , l , 0 , P2INT , 0 ); 974771Speter # endif PC 975771Speter return (nl+T2INT); 976771Speter } 977771Speter # ifdef OBJ 978771Speter put(2, O_CON4, l); 979771Speter # endif OBJ 980771Speter # ifdef PC 981771Speter putleaf( P2ICON , l , 0 , P2INT , 0 ); 982771Speter # endif PC 983771Speter return (nl+T4INT); 984771Speter 985771Speter /* 986771Speter * A floating point number 987771Speter */ 988771Speter case T_FINT: 989771Speter # ifdef OBJ 990771Speter put(2, O_CON8, atof(r[2])); 991771Speter # endif OBJ 992771Speter # ifdef PC 993771Speter putCON8( atof( r[2] ) ); 994771Speter # endif PC 995771Speter return (nl+TDOUBLE); 996771Speter 997771Speter /* 998771Speter * Constant strings. Note that constant characters 999771Speter * are constant strings of length one; there is 1000771Speter * no constant string of length one. 1001771Speter */ 1002771Speter case T_STRNG: 1003771Speter cp = r[2]; 1004771Speter if (cp[1] == 0) { 1005771Speter # ifdef OBJ 1006771Speter put(2, O_CONC, cp[0]); 1007771Speter # endif OBJ 1008771Speter # ifdef PC 1009771Speter putleaf( P2ICON , cp[0] , 0 , P2CHAR , 0 ); 1010771Speter # endif PC 1011771Speter return (nl+T1CHAR); 1012771Speter } 1013771Speter goto cstrng; 1014771Speter } 1015771Speter 1016771Speter } 1017771Speter } 1018771Speter 1019771Speter /* 1020771Speter * Can a class appear 1021771Speter * in a comparison ? 1022771Speter */ 1023771Speter nocomp(c) 1024771Speter int c; 1025771Speter { 1026771Speter 1027771Speter switch (c) { 1028771Speter case TREC: 10291627Speter if ( line != reccompline ) { 10301627Speter reccompline = line; 10311627Speter warning(); 10321627Speter if ( opt( 's' ) ) { 10331627Speter standard(); 10341627Speter } 1035771Speter error("record comparison is non-standard"); 1036771Speter } 1037771Speter break; 1038771Speter case TFILE: 1039771Speter case TARY: 1040771Speter error("%ss may not participate in comparisons", clnames[c]); 1041771Speter return (1); 1042771Speter } 1043771Speter return (NIL); 1044771Speter } 1045771Speter 1046771Speter /* 1047771Speter * this is sort of like gconst, except it works on expression trees 1048771Speter * rather than declaration trees, and doesn't give error messages for 1049771Speter * non-constant things. 1050771Speter * as a side effect this fills in the con structure that gconst uses. 1051771Speter * this returns TRUE or FALSE. 1052771Speter */ 1053771Speter constval(r) 1054771Speter register int *r; 1055771Speter { 1056771Speter register struct nl *np; 1057771Speter register *cn; 1058771Speter char *cp; 1059771Speter int negd, sgnd; 1060771Speter long ci; 1061771Speter 1062771Speter con.ctype = NIL; 1063771Speter cn = r; 1064771Speter negd = sgnd = 0; 1065771Speter loop: 1066771Speter /* 1067771Speter * cn[2] is nil if error recovery generated a T_STRNG 1068771Speter */ 1069771Speter if (cn == NIL || cn[2] == NIL) 1070771Speter return FALSE; 1071771Speter switch (cn[0]) { 1072771Speter default: 1073771Speter return FALSE; 1074771Speter case T_MINUS: 1075771Speter negd = 1 - negd; 1076771Speter /* and fall through */ 1077771Speter case T_PLUS: 1078771Speter sgnd++; 1079771Speter cn = cn[2]; 1080771Speter goto loop; 1081771Speter case T_NIL: 1082771Speter con.cpval = NIL; 1083771Speter con.cival = 0; 1084771Speter con.crval = con.cival; 1085771Speter con.ctype = nl + TNIL; 1086771Speter break; 1087771Speter case T_VAR: 1088771Speter np = lookup(cn[2]); 1089771Speter if (np == NIL || np->class != CONST) { 1090771Speter return FALSE; 1091771Speter } 1092771Speter if ( cn[3] != NIL ) { 1093771Speter return FALSE; 1094771Speter } 1095771Speter con.ctype = np->type; 1096771Speter switch (classify(np->type)) { 1097771Speter case TINT: 1098771Speter con.crval = np->range[0]; 1099771Speter break; 1100771Speter case TDOUBLE: 1101771Speter con.crval = np->real; 1102771Speter break; 1103771Speter case TBOOL: 1104771Speter case TCHAR: 1105771Speter case TSCAL: 1106771Speter con.cival = np->value[0]; 1107771Speter con.crval = con.cival; 1108771Speter break; 1109771Speter case TSTR: 1110771Speter con.cpval = np->ptr[0]; 1111771Speter break; 1112771Speter default: 1113771Speter con.ctype = NIL; 1114771Speter return FALSE; 1115771Speter } 1116771Speter break; 1117771Speter case T_BINT: 1118771Speter con.crval = a8tol(cn[2]); 1119771Speter goto restcon; 1120771Speter case T_INT: 1121771Speter con.crval = atof(cn[2]); 1122771Speter if (con.crval > MAXINT || con.crval < MININT) { 1123771Speter derror("Constant too large for this implementation"); 1124771Speter con.crval = 0; 1125771Speter } 1126771Speter restcon: 1127771Speter ci = con.crval; 1128771Speter #ifndef PI0 1129771Speter if (bytes(ci, ci) <= 2) 1130771Speter con.ctype = nl+T2INT; 1131771Speter else 1132771Speter #endif 1133771Speter con.ctype = nl+T4INT; 1134771Speter break; 1135771Speter case T_FINT: 1136771Speter con.ctype = nl+TDOUBLE; 1137771Speter con.crval = atof(cn[2]); 1138771Speter break; 1139771Speter case T_STRNG: 1140771Speter cp = cn[2]; 1141771Speter if (cp[1] == 0) { 1142771Speter con.ctype = nl+T1CHAR; 1143771Speter con.cival = cp[0]; 1144771Speter con.crval = con.cival; 1145771Speter break; 1146771Speter } 1147771Speter con.ctype = nl+TSTR; 1148771Speter con.cpval = cp; 1149771Speter break; 1150771Speter } 1151771Speter if (sgnd) { 1152771Speter if (isnta(con.ctype, "id")) { 1153771Speter derror("%s constants cannot be signed", nameof(con.ctype)); 1154771Speter return FALSE; 1155771Speter } else if (negd) 1156771Speter con.crval = -con.crval; 1157771Speter } 1158771Speter return TRUE; 1159771Speter } 1160