1771Speter /* Copyright (c) 1979 Regents of the University of California */ 2771Speter 3*3397Speter static char sccsid[] = "@(#)rval.c 1.11 03/30/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; 19*3397Speter /* line number of the last non-standard set comparison */ 20*3397Speter short nssetline = 0; 211627Speter 22771Speter #ifdef PC 23771Speter char *relts[] = { 24771Speter "_RELEQ" , "_RELNE" , 25771Speter "_RELTLT" , "_RELTGT" , 26771Speter "_RELTLE" , "_RELTGE" 27771Speter }; 28771Speter char *relss[] = { 29771Speter "_RELEQ" , "_RELNE" , 30771Speter "_RELSLT" , "_RELSGT" , 31771Speter "_RELSLE" , "_RELSGE" 32771Speter }; 33771Speter long relops[] = { 34771Speter P2EQ , P2NE , 35771Speter P2LT , P2GT , 36771Speter P2LE , P2GE 37771Speter }; 38771Speter long mathop[] = { P2MUL , P2PLUS , P2MINUS }; 39771Speter char *setop[] = { "_MULT" , "_ADDT" , "_SUBT" }; 40771Speter #endif PC 41771Speter /* 42771Speter * Rvalue - an expression. 43771Speter * 44771Speter * Contype is the type that the caller would prefer, nand is important 45771Speter * if constant sets or constant strings are involved, the latter 46771Speter * because of string padding. 47771Speter * required is a flag whether an lvalue or an rvalue is required. 48771Speter * only VARs and structured things can have gt their lvalue this way. 49771Speter */ 50771Speter struct nl * 51771Speter rvalue(r, contype , required ) 52771Speter int *r; 53771Speter struct nl *contype; 54771Speter int required; 55771Speter { 56771Speter register struct nl *p, *p1; 57771Speter register struct nl *q; 58771Speter int c, c1, *rt, w, g; 59771Speter char *cp, *cp1, *opname; 60771Speter long l; 61771Speter double f; 62771Speter extern int flagwas; 63771Speter struct csetstr csetd; 64771Speter # ifdef PC 65771Speter struct nl *rettype; 66771Speter long ctype; 67771Speter long tempoff; 68771Speter # endif PC 69771Speter 70771Speter if (r == NIL) 71771Speter return (NIL); 72771Speter if (nowexp(r)) 73771Speter return (NIL); 74771Speter /* 75771Speter * Pick up the name of the operation 76771Speter * for future error messages. 77771Speter */ 78771Speter if (r[0] <= T_IN) 79771Speter opname = opnames[r[0]]; 80771Speter 81771Speter /* 82771Speter * The root of the tree tells us what sort of expression we have. 83771Speter */ 84771Speter switch (r[0]) { 85771Speter 86771Speter /* 87771Speter * The constant nil 88771Speter */ 89771Speter case T_NIL: 90771Speter # ifdef OBJ 91771Speter put(2, O_CON2, 0); 92771Speter # endif OBJ 93771Speter # ifdef PC 941477Speter putleaf( P2ICON , 0 , 0 , P2PTR|P2UNDEF , 0 ); 95771Speter # endif PC 96771Speter return (nl+TNIL); 97771Speter 98771Speter /* 99771Speter * Function call with arguments. 100771Speter */ 101771Speter case T_FCALL: 102771Speter # ifdef OBJ 103771Speter return (funccod(r)); 104771Speter # endif OBJ 105771Speter # ifdef PC 106771Speter return (pcfunccod( r )); 107771Speter # endif PC 108771Speter 109771Speter case T_VAR: 110771Speter p = lookup(r[2]); 111771Speter if (p == NIL || p->class == BADUSE) 112771Speter return (NIL); 113771Speter switch (p->class) { 114771Speter case VAR: 115771Speter /* 116771Speter * If a variable is 117771Speter * qualified then get 118771Speter * the rvalue by a 119771Speter * lvalue and an ind. 120771Speter */ 121771Speter if (r[3] != NIL) 122771Speter goto ind; 123771Speter q = p->type; 124771Speter if (q == NIL) 125771Speter return (NIL); 126771Speter # ifdef OBJ 127771Speter w = width(q); 128771Speter switch (w) { 129771Speter case 8: 1303078Smckusic put(2, O_RV8 | bn << 8+INDX, 1313078Smckusic (int)p->value[0]); 132771Speter break; 133771Speter case 4: 1343078Smckusic put(2, O_RV4 | bn << 8+INDX, 1353078Smckusic (int)p->value[0]); 136771Speter break; 137771Speter case 2: 1383078Smckusic put(2, O_RV2 | bn << 8+INDX, 1393078Smckusic (int)p->value[0]); 140771Speter break; 141771Speter case 1: 1423078Smckusic put(2, O_RV1 | bn << 8+INDX, 1433078Smckusic (int)p->value[0]); 144771Speter break; 145771Speter default: 1463078Smckusic put(3, O_RV | bn << 8+INDX, 1473078Smckusic (int)p->value[0], w); 148771Speter } 149771Speter # endif OBJ 150771Speter # ifdef PC 151771Speter if ( required == RREQ ) { 152771Speter putRV( p -> symbol , bn , p -> value[0] 153771Speter , p2type( q ) ); 154771Speter } else { 155771Speter putLV( p -> symbol , bn , p -> value[0] 156771Speter , p2type( q ) ); 157771Speter } 158771Speter # endif PC 159771Speter return (q); 160771Speter 161771Speter case WITHPTR: 162771Speter case REF: 163771Speter /* 164771Speter * A lvalue for these 165771Speter * is actually what one 166771Speter * might consider a rvalue. 167771Speter */ 168771Speter ind: 169771Speter q = lvalue(r, NOFLAGS , LREQ ); 170771Speter if (q == NIL) 171771Speter return (NIL); 172771Speter # ifdef OBJ 173771Speter w = width(q); 174771Speter switch (w) { 175771Speter case 8: 176771Speter put(1, O_IND8); 177771Speter break; 178771Speter case 4: 179771Speter put(1, O_IND4); 180771Speter break; 181771Speter case 2: 182771Speter put(1, O_IND2); 183771Speter break; 184771Speter case 1: 185771Speter put(1, O_IND1); 186771Speter break; 187771Speter default: 188771Speter put(2, O_IND, w); 189771Speter } 190771Speter # endif OBJ 191771Speter # ifdef PC 192771Speter if ( required == RREQ ) { 193771Speter putop( P2UNARY P2MUL , p2type( q ) ); 194771Speter } 195771Speter # endif PC 196771Speter return (q); 197771Speter 198771Speter case CONST: 199771Speter if (r[3] != NIL) { 200771Speter error("%s is a constant and cannot be qualified", r[2]); 201771Speter return (NIL); 202771Speter } 203771Speter q = p->type; 204771Speter if (q == NIL) 205771Speter return (NIL); 206771Speter if (q == nl+TSTR) { 207771Speter /* 208771Speter * Find the size of the string 209771Speter * constant if needed. 210771Speter */ 211771Speter cp = p->ptr[0]; 212771Speter cstrng: 213771Speter cp1 = cp; 214771Speter for (c = 0; *cp++; c++) 215771Speter continue; 2163078Smckusic w = c; 217771Speter if (contype != NIL && !opt('s')) { 218771Speter if (width(contype) < c && classify(contype) == TSTR) { 219771Speter error("Constant string too long"); 220771Speter return (NIL); 221771Speter } 2223078Smckusic w = width(contype); 223771Speter } 224771Speter # ifdef OBJ 2253078Smckusic put(2, O_CONG, w); 2263078Smckusic putstr(cp1, w - c); 227771Speter # endif OBJ 228771Speter # ifdef PC 2293155Smckusic putCONG( cp1 , w , required ); 230771Speter # endif PC 231771Speter /* 232771Speter * Define the string temporarily 233771Speter * so later people can know its 234771Speter * width. 235771Speter * cleaned out by stat. 236771Speter */ 2373078Smckusic q = defnl(0, STR, 0, w); 238771Speter q->type = q; 239771Speter return (q); 240771Speter } 241771Speter if (q == nl+T1CHAR) { 242771Speter # ifdef OBJ 2433078Smckusic put(2, O_CONC, (int)p->value[0]); 244771Speter # endif OBJ 245771Speter # ifdef PC 246771Speter putleaf( P2ICON , p -> value[0] , 0 247771Speter , P2CHAR , 0 ); 248771Speter # endif PC 249771Speter return (q); 250771Speter } 251771Speter /* 252771Speter * Every other kind of constant here 253771Speter */ 254771Speter switch (width(q)) { 255771Speter case 8: 256771Speter #ifndef DEBUG 257771Speter # ifdef OBJ 258771Speter put(2, O_CON8, p->real); 259771Speter # endif OBJ 260771Speter # ifdef PC 261771Speter putCON8( p -> real ); 262771Speter # endif PC 263771Speter #else 264771Speter if (hp21mx) { 265771Speter f = p->real; 266771Speter conv(&f); 267771Speter l = f.plong; 268771Speter put(2, O_CON4, l); 269771Speter } else 270771Speter # ifdef OBJ 271771Speter put(2, O_CON8, p->real); 272771Speter # endif OBJ 273771Speter # ifdef PC 274771Speter putCON8( p -> real ); 275771Speter # endif PC 276771Speter #endif 277771Speter break; 278771Speter case 4: 279771Speter # ifdef OBJ 280771Speter put(2, O_CON4, p->range[0]); 281771Speter # endif OBJ 282771Speter # ifdef PC 283771Speter putleaf( P2ICON , p -> range[0] , 0 284771Speter , P2INT , 0 ); 285771Speter # endif PC 286771Speter break; 287771Speter case 2: 288771Speter # ifdef OBJ 2893078Smckusic put(2, O_CON2, (short)p->range[0]); 290771Speter # endif OBJ 291771Speter # ifdef PC 292771Speter /* 293771Speter * make short constants ints 294771Speter */ 295771Speter putleaf( P2ICON , (short) p -> range[0] 296771Speter , 0 , P2INT , 0 ); 297771Speter # endif PC 298771Speter break; 299771Speter case 1: 300771Speter # ifdef OBJ 301771Speter put(2, O_CON1, p->value[0]); 302771Speter # endif OBJ 303771Speter # ifdef PC 304771Speter /* 305771Speter * make char constants ints 306771Speter */ 307771Speter putleaf( P2ICON , p -> value[0] , 0 308771Speter , P2INT , 0 ); 309771Speter # endif PC 310771Speter break; 311771Speter default: 312771Speter panic("rval"); 313771Speter } 314771Speter return (q); 315771Speter 316771Speter case FUNC: 3171200Speter case FFUNC: 318771Speter /* 319771Speter * Function call with no arguments. 320771Speter */ 321771Speter if (r[3]) { 322771Speter error("Can't qualify a function result value"); 323771Speter return (NIL); 324771Speter } 325771Speter # ifdef OBJ 326771Speter return (funccod((int *) r)); 327771Speter # endif OBJ 328771Speter # ifdef PC 329771Speter return (pcfunccod( r )); 330771Speter # endif PC 331771Speter 332771Speter case TYPE: 333771Speter error("Type names (e.g. %s) allowed only in declarations", p->symbol); 334771Speter return (NIL); 335771Speter 336771Speter case PROC: 3371200Speter case FPROC: 338771Speter error("Procedure %s found where expression required", p->symbol); 339771Speter return (NIL); 340771Speter default: 341771Speter panic("rvid"); 342771Speter } 343771Speter /* 344771Speter * Constant sets 345771Speter */ 346771Speter case T_CSET: 347771Speter # ifdef OBJ 348771Speter if ( precset( r , contype , &csetd ) ) { 349771Speter if ( csetd.csettype == NIL ) { 350771Speter return NIL; 351771Speter } 352771Speter postcset( r , &csetd ); 353771Speter } else { 3543078Smckusic put( 2, O_PUSH, -lwidth(csetd.csettype)); 355771Speter postcset( r , &csetd ); 356771Speter setran( ( csetd.csettype ) -> type ); 357771Speter put( 2, O_CON24, set.uprbp); 358771Speter put( 2, O_CON24, set.lwrb); 3593078Smckusic put( 2, O_CTTOT, 3603078Smckusic (int)(4 + csetd.singcnt + 2 * csetd.paircnt)); 361771Speter } 362771Speter return csetd.csettype; 363771Speter # endif OBJ 364771Speter # ifdef PC 365771Speter if ( precset( r , contype , &csetd ) ) { 366771Speter if ( csetd.csettype == NIL ) { 367771Speter return NIL; 368771Speter } 369771Speter postcset( r , &csetd ); 370771Speter } else { 371771Speter putleaf( P2ICON , 0 , 0 372771Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 373771Speter , "_CTTOT" ); 374771Speter /* 375771Speter * allocate a temporary and use it 376771Speter */ 3773227Smckusic tempoff = tmpalloc(lwidth(csetd.csettype), 3783227Smckusic csetd.csettype, NOREG); 379771Speter putLV( 0 , cbn , tempoff , P2PTR|P2STRTY ); 380771Speter setran( ( csetd.csettype ) -> type ); 381771Speter putleaf( P2ICON , set.lwrb , 0 , P2INT , 0 ); 382771Speter putop( P2LISTOP , P2INT ); 383771Speter putleaf( P2ICON , set.uprbp , 0 , P2INT , 0 ); 384771Speter putop( P2LISTOP , P2INT ); 385771Speter postcset( r , &csetd ); 386771Speter putop( P2CALL , P2INT ); 387771Speter } 388771Speter return csetd.csettype; 389771Speter # endif PC 390771Speter 391771Speter /* 392771Speter * Unary plus and minus 393771Speter */ 394771Speter case T_PLUS: 395771Speter case T_MINUS: 396771Speter q = rvalue(r[2], NIL , RREQ ); 397771Speter if (q == NIL) 398771Speter return (NIL); 399771Speter if (isnta(q, "id")) { 400771Speter error("Operand of %s must be integer or real, not %s", opname, nameof(q)); 401771Speter return (NIL); 402771Speter } 403771Speter if (r[0] == T_MINUS) { 404771Speter # ifdef OBJ 405771Speter put(1, O_NEG2 + (width(q) >> 2)); 406771Speter # endif OBJ 407771Speter # ifdef PC 408771Speter putop( P2UNARY P2MINUS , p2type( q ) ); 409771Speter # endif PC 410771Speter return (isa(q, "d") ? q : nl+T4INT); 411771Speter } 412771Speter return (q); 413771Speter 414771Speter case T_NOT: 415771Speter q = rvalue(r[2], NIL , RREQ ); 416771Speter if (q == NIL) 417771Speter return (NIL); 418771Speter if (isnta(q, "b")) { 419771Speter error("not must operate on a Boolean, not %s", nameof(q)); 420771Speter return (NIL); 421771Speter } 422771Speter # ifdef OBJ 423771Speter put(1, O_NOT); 424771Speter # endif OBJ 425771Speter # ifdef PC 426771Speter putop( P2NOT , P2INT ); 427771Speter # endif PC 428771Speter return (nl+T1BOOL); 429771Speter 430771Speter case T_AND: 431771Speter case T_OR: 432771Speter p = rvalue(r[2], NIL , RREQ ); 433771Speter p1 = rvalue(r[3], NIL , RREQ ); 434771Speter if (p == NIL || p1 == NIL) 435771Speter return (NIL); 436771Speter if (isnta(p, "b")) { 437771Speter error("Left operand of %s must be Boolean, not %s", opname, nameof(p)); 438771Speter return (NIL); 439771Speter } 440771Speter if (isnta(p1, "b")) { 441771Speter error("Right operand of %s must be Boolean, not %s", opname, nameof(p1)); 442771Speter return (NIL); 443771Speter } 444771Speter # ifdef OBJ 445771Speter put(1, r[0] == T_AND ? O_AND : O_OR); 446771Speter # endif OBJ 447771Speter # ifdef PC 448771Speter /* 449771Speter * note the use of & and | rather than && and || 450771Speter * to force evaluation of all the expressions. 451771Speter */ 452771Speter putop( r[ 0 ] == T_AND ? P2AND : P2OR , P2INT ); 453771Speter # endif PC 454771Speter return (nl+T1BOOL); 455771Speter 456771Speter case T_DIVD: 457771Speter # ifdef OBJ 458771Speter p = rvalue(r[2], NIL , RREQ ); 459771Speter p1 = rvalue(r[3], NIL , RREQ ); 460771Speter # endif OBJ 461771Speter # ifdef PC 462771Speter /* 463771Speter * force these to be doubles for the divide 464771Speter */ 465771Speter p = rvalue( r[ 2 ] , NIL , RREQ ); 466771Speter if ( isnta( p , "d" ) ) { 467771Speter putop( P2SCONV , P2DOUBLE ); 468771Speter } 469771Speter p1 = rvalue( r[ 3 ] , NIL , RREQ ); 470771Speter if ( isnta( p1 , "d" ) ) { 471771Speter putop( P2SCONV , P2DOUBLE ); 472771Speter } 473771Speter # endif PC 474771Speter if (p == NIL || p1 == NIL) 475771Speter return (NIL); 476771Speter if (isnta(p, "id")) { 477771Speter error("Left operand of / must be integer or real, not %s", nameof(p)); 478771Speter return (NIL); 479771Speter } 480771Speter if (isnta(p1, "id")) { 481771Speter error("Right operand of / must be integer or real, not %s", nameof(p1)); 482771Speter return (NIL); 483771Speter } 484771Speter # ifdef OBJ 485771Speter return gen(NIL, r[0], width(p), width(p1)); 486771Speter # endif OBJ 487771Speter # ifdef PC 488771Speter putop( P2DIV , P2DOUBLE ); 489771Speter return nl + TDOUBLE; 490771Speter # endif PC 491771Speter 492771Speter case T_MULT: 493771Speter case T_ADD: 494771Speter case T_SUB: 495771Speter # ifdef OBJ 496771Speter /* 4971555Speter * If the context hasn't told us the type 4981555Speter * and a constant set is present 4991555Speter * we need to infer the type 5001555Speter * before generating code. 501771Speter */ 5021555Speter if ( contype == NIL ) { 503771Speter codeoff(); 5041555Speter contype = rvalue( r[3] , NIL , RREQ ); 505771Speter codeon(); 5061555Speter if ( contype == lookup( intset ) -> type ) { 5071555Speter codeoff(); 5081555Speter contype = rvalue( r[2] , NIL , RREQ ); 5091555Speter codeon(); 5101555Speter } 511771Speter } 5121555Speter if ( contype == NIL ) { 5131555Speter return NIL; 5141555Speter } 5151555Speter p = rvalue( r[2] , contype , RREQ ); 5161555Speter p1 = rvalue( r[3] , p , RREQ ); 5171555Speter if ( p == NIL || p1 == NIL ) 5181555Speter return NIL; 519771Speter if (isa(p, "id") && isa(p1, "id")) 520771Speter return (gen(NIL, r[0], width(p), width(p1))); 521771Speter if (isa(p, "t") && isa(p1, "t")) { 522771Speter if (p != p1) { 523771Speter error("Set types of operands of %s must be identical", opname); 524771Speter return (NIL); 525771Speter } 526771Speter gen(TSET, r[0], width(p), 0); 527771Speter return (p); 528771Speter } 529771Speter # endif OBJ 530771Speter # ifdef PC 531771Speter /* 532771Speter * the second pass can't do 533771Speter * long op double or double op long 534771Speter * so we have to know the type of both operands 535771Speter * also, it gets tricky for sets, which are done 536771Speter * by function calls. 537771Speter */ 538771Speter codeoff(); 539771Speter p1 = rvalue( r[ 3 ] , contype , RREQ ); 540771Speter codeon(); 541771Speter if ( isa( p1 , "id" ) ) { 542771Speter p = rvalue( r[ 2 ] , contype , RREQ ); 543771Speter if ( ( p == NIL ) || ( p1 == NIL ) ) { 544771Speter return NIL; 545771Speter } 546771Speter if ( isa( p , "i" ) && isa( p1 , "d" ) ) { 547771Speter putop( P2SCONV , P2DOUBLE ); 548771Speter } 549771Speter p1 = rvalue( r[ 3 ] , contype , RREQ ); 550771Speter if ( isa( p , "d" ) && isa( p1 , "i" ) ) { 551771Speter putop( P2SCONV , P2DOUBLE ); 552771Speter } 553771Speter if ( isa( p , "id" ) ) { 554771Speter if ( isa( p , "d" ) || isa( p1 , "d" ) ) { 555771Speter ctype = P2DOUBLE; 556771Speter rettype = nl + TDOUBLE; 557771Speter } else { 558771Speter ctype = P2INT; 559771Speter rettype = nl + T4INT; 560771Speter } 561771Speter putop( mathop[ r[0] - T_MULT ] , ctype ); 562771Speter return rettype; 563771Speter } 564771Speter } 565771Speter if ( isa( p1 , "t" ) ) { 566771Speter putleaf( P2ICON , 0 , 0 567771Speter , ADDTYPE( ADDTYPE( P2PTR | P2STRTY , P2FTN ) 568771Speter , P2PTR ) 569771Speter , setop[ r[0] - T_MULT ] ); 5701555Speter if ( contype == NIL ) { 5711555Speter contype = p1; 5721555Speter if ( contype == lookup( intset ) -> type ) { 5731555Speter codeoff(); 5741555Speter contype = rvalue( r[2] , NIL , LREQ ); 5751555Speter codeon(); 5761555Speter } 5771555Speter } 5781555Speter if ( contype == NIL ) { 5791555Speter return NIL; 5801555Speter } 5811555Speter /* 5821555Speter * allocate a temporary and use it 5831555Speter */ 5843227Smckusic tempoff = tmpalloc(lwidth(contype), contype, NOREG); 585771Speter putLV( 0 , cbn , tempoff , P2PTR|P2STRTY ); 5861555Speter p = rvalue( r[2] , contype , LREQ ); 587771Speter if ( isa( p , "t" ) ) { 588771Speter putop( P2LISTOP , P2INT ); 589771Speter if ( p == NIL || p1 == NIL ) { 590771Speter return NIL; 591771Speter } 592771Speter p1 = rvalue( r[3] , p , LREQ ); 593771Speter if ( p != p1 ) { 594771Speter error("Set types of operands of %s must be identical", opname); 595771Speter return NIL; 596771Speter } 597771Speter putop( P2LISTOP , P2INT ); 598771Speter putleaf( P2ICON , lwidth( p1 ) / sizeof( long ) , 0 599771Speter , P2INT , 0 ); 600771Speter putop( P2LISTOP , P2INT ); 601771Speter putop( P2CALL , P2PTR | P2STRTY ); 602771Speter return p; 603771Speter } 604771Speter } 605771Speter if ( isnta( p1 , "idt" ) ) { 606771Speter /* 607771Speter * find type of left operand for error message. 608771Speter */ 609771Speter p = rvalue( r[2] , contype , RREQ ); 610771Speter } 611771Speter /* 612771Speter * don't give spurious error messages. 613771Speter */ 614771Speter if ( p == NIL || p1 == NIL ) { 615771Speter return NIL; 616771Speter } 617771Speter # endif PC 618771Speter if (isnta(p, "idt")) { 619771Speter error("Left operand of %s must be integer, real or set, not %s", opname, nameof(p)); 620771Speter return (NIL); 621771Speter } 622771Speter if (isnta(p1, "idt")) { 623771Speter error("Right operand of %s must be integer, real or set, not %s", opname, nameof(p1)); 624771Speter return (NIL); 625771Speter } 626771Speter error("Cannot mix sets with integers and reals as operands of %s", opname); 627771Speter return (NIL); 628771Speter 629771Speter case T_MOD: 630771Speter case T_DIV: 631771Speter p = rvalue(r[2], NIL , RREQ ); 632771Speter p1 = rvalue(r[3], NIL , RREQ ); 633771Speter if (p == NIL || p1 == NIL) 634771Speter return (NIL); 635771Speter if (isnta(p, "i")) { 636771Speter error("Left operand of %s must be integer, not %s", opname, nameof(p)); 637771Speter return (NIL); 638771Speter } 639771Speter if (isnta(p1, "i")) { 640771Speter error("Right operand of %s must be integer, not %s", opname, nameof(p1)); 641771Speter return (NIL); 642771Speter } 643771Speter # ifdef OBJ 644771Speter return (gen(NIL, r[0], width(p), width(p1))); 645771Speter # endif OBJ 646771Speter # ifdef PC 647771Speter putop( r[ 0 ] == T_DIV ? P2DIV : P2MOD , P2INT ); 648771Speter return ( nl + T4INT ); 649771Speter # endif PC 650771Speter 651771Speter case T_EQ: 652771Speter case T_NE: 653771Speter case T_LT: 654771Speter case T_GT: 655771Speter case T_LE: 656771Speter case T_GE: 657771Speter /* 658771Speter * Since there can be no, a priori, knowledge 659771Speter * of the context type should a constant string 660771Speter * or set arise, we must poke around to find such 661771Speter * a type if possible. Since constant strings can 662771Speter * always masquerade as identifiers, this is always 663771Speter * necessary. 664771Speter */ 665771Speter codeoff(); 666771Speter p1 = rvalue(r[3], NIL , RREQ ); 667771Speter codeon(); 668771Speter if (p1 == NIL) 669771Speter return (NIL); 670771Speter contype = p1; 671771Speter # ifdef OBJ 6721555Speter if (p1->class == STR) { 673771Speter /* 674771Speter * For constant strings we want 675771Speter * the longest type so as to be 676771Speter * able to do padding (more importantly 677771Speter * avoiding truncation). For clarity, 678771Speter * we get this length here. 679771Speter */ 680771Speter codeoff(); 681771Speter p = rvalue(r[2], NIL , RREQ ); 682771Speter codeon(); 683771Speter if (p == NIL) 684771Speter return (NIL); 6851555Speter if (width(p) > width(p1)) 686771Speter contype = p; 6871555Speter } else if ( isa( p1 , "t" ) ) { 6881555Speter if ( contype == lookup( intset ) -> type ) { 6891555Speter codeoff(); 6901555Speter contype = rvalue( r[2] , NIL , RREQ ); 6911555Speter codeon(); 6921555Speter if ( contype == NIL ) { 6931555Speter return NIL; 6941555Speter } 6951555Speter } 696771Speter } 697771Speter /* 698771Speter * Now we generate code for 699771Speter * the operands of the relational 700771Speter * operation. 701771Speter */ 702771Speter p = rvalue(r[2], contype , RREQ ); 703771Speter if (p == NIL) 704771Speter return (NIL); 705771Speter p1 = rvalue(r[3], p , RREQ ); 706771Speter if (p1 == NIL) 707771Speter return (NIL); 708771Speter # endif OBJ 709771Speter # ifdef PC 710771Speter c1 = classify( p1 ); 711771Speter if ( c1 == TSET || c1 == TSTR || c1 == TREC ) { 712771Speter putleaf( P2ICON , 0 , 0 713771Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 714771Speter , c1 == TSET ? relts[ r[0] - T_EQ ] 715771Speter : relss[ r[0] - T_EQ ] ); 716771Speter /* 717771Speter * for [] and strings, comparisons are done on 718771Speter * the maximum width of the two sides. 719771Speter * for other sets, we have to ask the left side 720771Speter * what type it is based on the type of the right. 721771Speter * (this matters for intsets). 722771Speter */ 7231555Speter if ( c1 == TSTR ) { 724771Speter codeoff(); 725771Speter p = rvalue( r[ 2 ] , NIL , LREQ ); 726771Speter codeon(); 7271555Speter if ( p == NIL ) { 7281555Speter return NIL; 7291555Speter } 7301555Speter if ( lwidth( p ) > lwidth( p1 ) ) { 731771Speter contype = p; 732771Speter } 7331555Speter } else if ( c1 == TSET ) { 7341555Speter if ( contype == lookup( intset ) -> type ) { 7351555Speter codeoff(); 7361555Speter p = rvalue( r[ 2 ] , NIL , LREQ ); 7371555Speter codeon(); 7381555Speter if ( p == NIL ) { 7391555Speter return NIL; 7401555Speter } 7411555Speter contype = p; 7421555Speter } 7431627Speter } 744771Speter /* 745771Speter * put out the width of the comparison. 746771Speter */ 747771Speter putleaf( P2ICON , lwidth( contype ) , 0 , P2INT , 0 ); 748771Speter /* 749771Speter * and the left hand side, 750771Speter * for sets, strings, records 751771Speter */ 752771Speter p = rvalue( r[ 2 ] , contype , LREQ ); 753771Speter putop( P2LISTOP , P2INT ); 754771Speter p1 = rvalue( r[ 3 ] , p , LREQ ); 755771Speter putop( P2LISTOP , P2INT ); 756771Speter putop( P2CALL , P2INT ); 757771Speter } else { 758771Speter /* 759771Speter * the easy (scalar or error) case 760771Speter */ 761771Speter p = rvalue( r[ 2 ] , contype , RREQ ); 762771Speter if ( p == NIL ) { 763771Speter return NIL; 7642056Speter } 765771Speter /* 766771Speter * since the second pass can't do 767771Speter * long op double or double op long 768771Speter * we may have to do some coercing. 769771Speter */ 7702056Speter if ( isa( p , "i" ) && isa( p1 , "d" ) ) { 771771Speter putop( P2SCONV , P2DOUBLE ); 772771Speter } 773771Speter p1 = rvalue( r[ 3 ] , p , RREQ ); 774771Speter if ( isa( p , "d" ) && isa( p1 , "i" ) ) 775771Speter putop( P2SCONV , P2DOUBLE ); 776771Speter putop( relops[ r[0] - T_EQ ] , P2INT ); 777771Speter } 778771Speter # endif PC 779771Speter c = classify(p); 780771Speter c1 = classify(p1); 781771Speter if (nocomp(c) || nocomp(c1)) 782771Speter return (NIL); 783771Speter g = NIL; 784771Speter switch (c) { 785771Speter case TBOOL: 786771Speter case TCHAR: 787771Speter if (c != c1) 788771Speter goto clash; 789771Speter break; 790771Speter case TINT: 791771Speter case TDOUBLE: 792771Speter if (c1 != TINT && c1 != TDOUBLE) 793771Speter goto clash; 794771Speter break; 795771Speter case TSCAL: 796771Speter if (c1 != TSCAL) 797771Speter goto clash; 798771Speter if (scalar(p) != scalar(p1)) 799771Speter goto nonident; 800771Speter break; 801771Speter case TSET: 802771Speter if (c1 != TSET) 803771Speter goto clash; 804*3397Speter if ( opt( 's' ) && 805*3397Speter ( ( r[0] == T_LT ) || ( r[0] == T_GT ) ) && 806*3397Speter ( line != nssetline ) ) { 807*3397Speter nssetline = line; 808*3397Speter standard(); 809*3397Speter error("%s comparison on sets is non-standard" , opname ); 810*3397Speter } 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