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