1771Speter /* Copyright (c) 1979 Regents of the University of California */ 2771Speter 3*10670Speter static char sccsid[] = "@(#)rval.c 1.15 02/01/83"; 4771Speter 5771Speter #include "whoami.h" 6771Speter #include "0.h" 7771Speter #include "tree.h" 8771Speter #include "opcode.h" 9771Speter #include "objfmt.h" 10771Speter #ifdef PC 11771Speter # include "pc.h" 12771Speter # include "pcops.h" 13771Speter #endif PC 14771Speter 15771Speter extern char *opnames[]; 16771Speter 171627Speter /* line number of the last record comparison warning */ 181627Speter short reccompline = 0; 193397Speter /* line number of the last non-standard set comparison */ 203397Speter 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; 673834Speter struct nl *tempnlp; 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 ) { 1523834Speter putRV( p -> symbol , bn , p -> value[0] , 1533834Speter p -> extra_flags , p2type( q ) ); 154771Speter } else { 1553834Speter putLV( p -> symbol , bn , p -> value[0] , 1563834Speter p -> extra_flags , 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 putleaf( P2ICON , (short) p -> range[0] 29310364Smckusick , 0 , P2SHORT , 0 ); 294771Speter # endif PC 295771Speter break; 296771Speter case 1: 297771Speter # ifdef OBJ 298771Speter put(2, O_CON1, p->value[0]); 299771Speter # endif OBJ 300771Speter # ifdef PC 301771Speter putleaf( P2ICON , p -> value[0] , 0 30210364Smckusick , P2CHAR , 0 ); 303771Speter # endif PC 304771Speter break; 305771Speter default: 306771Speter panic("rval"); 307771Speter } 308771Speter return (q); 309771Speter 310771Speter case FUNC: 3111200Speter case FFUNC: 312771Speter /* 313771Speter * Function call with no arguments. 314771Speter */ 315771Speter if (r[3]) { 316771Speter error("Can't qualify a function result value"); 317771Speter return (NIL); 318771Speter } 319771Speter # ifdef OBJ 320771Speter return (funccod((int *) r)); 321771Speter # endif OBJ 322771Speter # ifdef PC 323771Speter return (pcfunccod( r )); 324771Speter # endif PC 325771Speter 326771Speter case TYPE: 327771Speter error("Type names (e.g. %s) allowed only in declarations", p->symbol); 328771Speter return (NIL); 329771Speter 330771Speter case PROC: 3311200Speter case FPROC: 332771Speter error("Procedure %s found where expression required", p->symbol); 333771Speter return (NIL); 334771Speter default: 335771Speter panic("rvid"); 336771Speter } 337771Speter /* 338771Speter * Constant sets 339771Speter */ 340771Speter case T_CSET: 341771Speter # ifdef OBJ 342771Speter if ( precset( r , contype , &csetd ) ) { 343771Speter if ( csetd.csettype == NIL ) { 344771Speter return NIL; 345771Speter } 346771Speter postcset( r , &csetd ); 347771Speter } else { 3483078Smckusic put( 2, O_PUSH, -lwidth(csetd.csettype)); 349771Speter postcset( r , &csetd ); 350771Speter setran( ( csetd.csettype ) -> type ); 351771Speter put( 2, O_CON24, set.uprbp); 352771Speter put( 2, O_CON24, set.lwrb); 3533078Smckusic put( 2, O_CTTOT, 3543078Smckusic (int)(4 + csetd.singcnt + 2 * csetd.paircnt)); 355771Speter } 356771Speter return csetd.csettype; 357771Speter # endif OBJ 358771Speter # ifdef PC 359771Speter if ( precset( r , contype , &csetd ) ) { 360771Speter if ( csetd.csettype == NIL ) { 361771Speter return NIL; 362771Speter } 363771Speter postcset( r , &csetd ); 364771Speter } else { 365771Speter putleaf( P2ICON , 0 , 0 366771Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 367771Speter , "_CTTOT" ); 368771Speter /* 369771Speter * allocate a temporary and use it 370771Speter */ 3713834Speter tempnlp = tmpalloc(lwidth(csetd.csettype), 3723227Smckusic csetd.csettype, NOREG); 3733834Speter putLV( 0 , cbn , tempnlp -> value[ NL_OFFS ] , 3743834Speter tempnlp -> extra_flags , P2PTR|P2STRTY ); 375771Speter setran( ( csetd.csettype ) -> type ); 376771Speter putleaf( P2ICON , set.lwrb , 0 , P2INT , 0 ); 377771Speter putop( P2LISTOP , P2INT ); 378771Speter putleaf( P2ICON , set.uprbp , 0 , P2INT , 0 ); 379771Speter putop( P2LISTOP , P2INT ); 380771Speter postcset( r , &csetd ); 381771Speter putop( P2CALL , P2INT ); 382771Speter } 383771Speter return csetd.csettype; 384771Speter # endif PC 385771Speter 386771Speter /* 387771Speter * Unary plus and minus 388771Speter */ 389771Speter case T_PLUS: 390771Speter case T_MINUS: 391771Speter q = rvalue(r[2], NIL , RREQ ); 392771Speter if (q == NIL) 393771Speter return (NIL); 394771Speter if (isnta(q, "id")) { 395771Speter error("Operand of %s must be integer or real, not %s", opname, nameof(q)); 396771Speter return (NIL); 397771Speter } 398771Speter if (r[0] == T_MINUS) { 399771Speter # ifdef OBJ 400771Speter put(1, O_NEG2 + (width(q) >> 2)); 401*10670Speter return (isa(q, "d") ? q : nl+T4INT); 402771Speter # endif OBJ 403771Speter # ifdef PC 404*10670Speter if (isa(q, "i")) { 405*10670Speter sconv(p2type(q), P2INT); 406*10670Speter putop( P2UNARY P2MINUS, P2INT); 407*10670Speter return nl+T4INT; 408*10670Speter } 409*10670Speter putop( P2UNARY P2MINUS, P2DOUBLE); 410*10670Speter return nl+TDOUBLE; 411771Speter # endif PC 412771Speter } 413771Speter return (q); 414771Speter 415771Speter case T_NOT: 416771Speter q = rvalue(r[2], NIL , RREQ ); 417771Speter if (q == NIL) 418771Speter return (NIL); 419771Speter if (isnta(q, "b")) { 420771Speter error("not must operate on a Boolean, not %s", nameof(q)); 421771Speter return (NIL); 422771Speter } 423771Speter # ifdef OBJ 424771Speter put(1, O_NOT); 425771Speter # endif OBJ 426771Speter # ifdef PC 42710364Smckusick sconv(p2type(q), P2INT); 42810364Smckusick putop( P2NOT , P2INT); 42910364Smckusick sconv(P2INT, p2type(q)); 430771Speter # endif PC 431771Speter return (nl+T1BOOL); 432771Speter 433771Speter case T_AND: 434771Speter case T_OR: 435771Speter p = rvalue(r[2], NIL , RREQ ); 43610364Smckusick # ifdef PC 43710364Smckusick sconv(p2type(p),P2INT); 43810364Smckusick # endif PC 439771Speter p1 = rvalue(r[3], NIL , RREQ ); 44010364Smckusick # ifdef PC 44110364Smckusick sconv(p2type(p1),P2INT); 44210364Smckusick # endif PC 443771Speter if (p == NIL || p1 == NIL) 444771Speter return (NIL); 445771Speter if (isnta(p, "b")) { 446771Speter error("Left operand of %s must be Boolean, not %s", opname, nameof(p)); 447771Speter return (NIL); 448771Speter } 449771Speter if (isnta(p1, "b")) { 450771Speter error("Right operand of %s must be Boolean, not %s", opname, nameof(p1)); 451771Speter return (NIL); 452771Speter } 453771Speter # ifdef OBJ 454771Speter put(1, r[0] == T_AND ? O_AND : O_OR); 455771Speter # endif OBJ 456771Speter # ifdef PC 457771Speter /* 458771Speter * note the use of & and | rather than && and || 459771Speter * to force evaluation of all the expressions. 460771Speter */ 461771Speter putop( r[ 0 ] == T_AND ? P2AND : P2OR , P2INT ); 46210364Smckusick sconv(P2INT, p2type(p)); 463771Speter # endif PC 464771Speter return (nl+T1BOOL); 465771Speter 466771Speter case T_DIVD: 467771Speter # ifdef OBJ 468771Speter p = rvalue(r[2], NIL , RREQ ); 469771Speter p1 = rvalue(r[3], NIL , RREQ ); 470771Speter # endif OBJ 471771Speter # ifdef PC 472771Speter /* 473771Speter * force these to be doubles for the divide 474771Speter */ 475771Speter p = rvalue( r[ 2 ] , NIL , RREQ ); 47610364Smckusick sconv(p2type(p), P2DOUBLE); 477771Speter p1 = rvalue( r[ 3 ] , NIL , RREQ ); 47810364Smckusick sconv(p2type(p1), P2DOUBLE); 479771Speter # endif PC 480771Speter if (p == NIL || p1 == NIL) 481771Speter return (NIL); 482771Speter if (isnta(p, "id")) { 483771Speter error("Left operand of / must be integer or real, not %s", nameof(p)); 484771Speter return (NIL); 485771Speter } 486771Speter if (isnta(p1, "id")) { 487771Speter error("Right operand of / must be integer or real, not %s", nameof(p1)); 488771Speter return (NIL); 489771Speter } 490771Speter # ifdef OBJ 491771Speter return gen(NIL, r[0], width(p), width(p1)); 492771Speter # endif OBJ 493771Speter # ifdef PC 494771Speter putop( P2DIV , P2DOUBLE ); 495771Speter return nl + TDOUBLE; 496771Speter # endif PC 497771Speter 498771Speter case T_MULT: 499771Speter case T_ADD: 500771Speter case T_SUB: 501771Speter # ifdef OBJ 502771Speter /* 5031555Speter * If the context hasn't told us the type 5041555Speter * and a constant set is present 5051555Speter * we need to infer the type 5061555Speter * before generating code. 507771Speter */ 5081555Speter if ( contype == NIL ) { 509771Speter codeoff(); 5101555Speter contype = rvalue( r[3] , NIL , RREQ ); 511771Speter codeon(); 5121555Speter if ( contype == lookup( intset ) -> type ) { 5131555Speter codeoff(); 5141555Speter contype = rvalue( r[2] , NIL , RREQ ); 5151555Speter codeon(); 5161555Speter } 517771Speter } 5181555Speter if ( contype == NIL ) { 5191555Speter return NIL; 5201555Speter } 5211555Speter p = rvalue( r[2] , contype , RREQ ); 5221555Speter p1 = rvalue( r[3] , p , RREQ ); 5231555Speter if ( p == NIL || p1 == NIL ) 5241555Speter return NIL; 525771Speter if (isa(p, "id") && isa(p1, "id")) 526771Speter return (gen(NIL, r[0], width(p), width(p1))); 527771Speter if (isa(p, "t") && isa(p1, "t")) { 528771Speter if (p != p1) { 529771Speter error("Set types of operands of %s must be identical", opname); 530771Speter return (NIL); 531771Speter } 532771Speter gen(TSET, r[0], width(p), 0); 533771Speter return (p); 534771Speter } 535771Speter # endif OBJ 536771Speter # ifdef PC 537771Speter /* 538771Speter * the second pass can't do 539771Speter * long op double or double op long 540771Speter * so we have to know the type of both operands 541771Speter * also, it gets tricky for sets, which are done 542771Speter * by function calls. 543771Speter */ 544771Speter codeoff(); 545771Speter p1 = rvalue( r[ 3 ] , contype , RREQ ); 546771Speter codeon(); 547771Speter if ( isa( p1 , "id" ) ) { 548771Speter p = rvalue( r[ 2 ] , contype , RREQ ); 549771Speter if ( ( p == NIL ) || ( p1 == NIL ) ) { 550771Speter return NIL; 551771Speter } 55210364Smckusick tuac(p, p1, &rettype, &ctype); 553771Speter p1 = rvalue( r[ 3 ] , contype , RREQ ); 55410364Smckusick tuac(p1, p, &rettype, &ctype); 555771Speter if ( isa( p , "id" ) ) { 556771Speter putop( mathop[ r[0] - T_MULT ] , ctype ); 557771Speter return rettype; 558771Speter } 559771Speter } 560771Speter if ( isa( p1 , "t" ) ) { 561771Speter putleaf( P2ICON , 0 , 0 562771Speter , ADDTYPE( ADDTYPE( P2PTR | P2STRTY , P2FTN ) 563771Speter , P2PTR ) 564771Speter , setop[ r[0] - T_MULT ] ); 5651555Speter if ( contype == NIL ) { 5661555Speter contype = p1; 5671555Speter if ( contype == lookup( intset ) -> type ) { 5681555Speter codeoff(); 5691555Speter contype = rvalue( r[2] , NIL , LREQ ); 5701555Speter codeon(); 5711555Speter } 5721555Speter } 5731555Speter if ( contype == NIL ) { 5741555Speter return NIL; 5751555Speter } 5761555Speter /* 5771555Speter * allocate a temporary and use it 5781555Speter */ 5793834Speter tempnlp = tmpalloc(lwidth(contype), contype, NOREG); 5803834Speter putLV( 0 , cbn , tempnlp -> value[ NL_OFFS ] , 5813834Speter tempnlp -> extra_flags , P2PTR|P2STRTY ); 5821555Speter p = rvalue( r[2] , contype , LREQ ); 583771Speter if ( isa( p , "t" ) ) { 584771Speter putop( P2LISTOP , P2INT ); 585771Speter if ( p == NIL || p1 == NIL ) { 586771Speter return NIL; 587771Speter } 588771Speter p1 = rvalue( r[3] , p , LREQ ); 589771Speter if ( p != p1 ) { 590771Speter error("Set types of operands of %s must be identical", opname); 591771Speter return NIL; 592771Speter } 593771Speter putop( P2LISTOP , P2INT ); 594771Speter putleaf( P2ICON , lwidth( p1 ) / sizeof( long ) , 0 595771Speter , P2INT , 0 ); 596771Speter putop( P2LISTOP , P2INT ); 597771Speter putop( P2CALL , P2PTR | P2STRTY ); 598771Speter return p; 599771Speter } 600771Speter } 601771Speter if ( isnta( p1 , "idt" ) ) { 602771Speter /* 603771Speter * find type of left operand for error message. 604771Speter */ 605771Speter p = rvalue( r[2] , contype , RREQ ); 606771Speter } 607771Speter /* 608771Speter * don't give spurious error messages. 609771Speter */ 610771Speter if ( p == NIL || p1 == NIL ) { 611771Speter return NIL; 612771Speter } 613771Speter # endif PC 614771Speter if (isnta(p, "idt")) { 615771Speter error("Left operand of %s must be integer, real or set, not %s", opname, nameof(p)); 616771Speter return (NIL); 617771Speter } 618771Speter if (isnta(p1, "idt")) { 619771Speter error("Right operand of %s must be integer, real or set, not %s", opname, nameof(p1)); 620771Speter return (NIL); 621771Speter } 622771Speter error("Cannot mix sets with integers and reals as operands of %s", opname); 623771Speter return (NIL); 624771Speter 625771Speter case T_MOD: 626771Speter case T_DIV: 627771Speter p = rvalue(r[2], NIL , RREQ ); 62810364Smckusick # ifdef PC 62910364Smckusick sconv(p2type(p), P2INT); 63010364Smckusick # endif PC 631771Speter p1 = rvalue(r[3], NIL , RREQ ); 63210364Smckusick # ifdef PC 63310364Smckusick sconv(p2type(p1), P2INT); 63410364Smckusick # endif PC 635771Speter if (p == NIL || p1 == NIL) 636771Speter return (NIL); 637771Speter if (isnta(p, "i")) { 638771Speter error("Left operand of %s must be integer, not %s", opname, nameof(p)); 639771Speter return (NIL); 640771Speter } 641771Speter if (isnta(p1, "i")) { 642771Speter error("Right operand of %s must be integer, not %s", opname, nameof(p1)); 643771Speter return (NIL); 644771Speter } 645771Speter # ifdef OBJ 646771Speter return (gen(NIL, r[0], width(p), width(p1))); 647771Speter # endif OBJ 648771Speter # ifdef PC 649771Speter putop( r[ 0 ] == T_DIV ? P2DIV : P2MOD , P2INT ); 650771Speter return ( nl + T4INT ); 651771Speter # endif PC 652771Speter 653771Speter case T_EQ: 654771Speter case T_NE: 655771Speter case T_LT: 656771Speter case T_GT: 657771Speter case T_LE: 658771Speter case T_GE: 659771Speter /* 660771Speter * Since there can be no, a priori, knowledge 661771Speter * of the context type should a constant string 662771Speter * or set arise, we must poke around to find such 663771Speter * a type if possible. Since constant strings can 664771Speter * always masquerade as identifiers, this is always 665771Speter * necessary. 666771Speter */ 667771Speter codeoff(); 668771Speter p1 = rvalue(r[3], NIL , RREQ ); 669771Speter codeon(); 670771Speter if (p1 == NIL) 671771Speter return (NIL); 672771Speter contype = p1; 673771Speter # ifdef OBJ 6741555Speter if (p1->class == STR) { 675771Speter /* 676771Speter * For constant strings we want 677771Speter * the longest type so as to be 678771Speter * able to do padding (more importantly 679771Speter * avoiding truncation). For clarity, 680771Speter * we get this length here. 681771Speter */ 682771Speter codeoff(); 683771Speter p = rvalue(r[2], NIL , RREQ ); 684771Speter codeon(); 685771Speter if (p == NIL) 686771Speter return (NIL); 6871555Speter if (width(p) > width(p1)) 688771Speter contype = p; 6891555Speter } else if ( isa( p1 , "t" ) ) { 6901555Speter if ( contype == lookup( intset ) -> type ) { 6911555Speter codeoff(); 6921555Speter contype = rvalue( r[2] , NIL , RREQ ); 6931555Speter codeon(); 6941555Speter if ( contype == NIL ) { 6951555Speter return NIL; 6961555Speter } 6971555Speter } 698771Speter } 699771Speter /* 700771Speter * Now we generate code for 701771Speter * the operands of the relational 702771Speter * operation. 703771Speter */ 704771Speter p = rvalue(r[2], contype , RREQ ); 705771Speter if (p == NIL) 706771Speter return (NIL); 707771Speter p1 = rvalue(r[3], p , RREQ ); 708771Speter if (p1 == NIL) 709771Speter return (NIL); 710771Speter # endif OBJ 711771Speter # ifdef PC 712771Speter c1 = classify( p1 ); 713771Speter if ( c1 == TSET || c1 == TSTR || c1 == TREC ) { 714771Speter putleaf( P2ICON , 0 , 0 715771Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 716771Speter , c1 == TSET ? relts[ r[0] - T_EQ ] 717771Speter : relss[ r[0] - T_EQ ] ); 718771Speter /* 719771Speter * for [] and strings, comparisons are done on 720771Speter * the maximum width of the two sides. 721771Speter * for other sets, we have to ask the left side 722771Speter * what type it is based on the type of the right. 723771Speter * (this matters for intsets). 724771Speter */ 7251555Speter if ( c1 == TSTR ) { 726771Speter codeoff(); 727771Speter p = rvalue( r[ 2 ] , NIL , LREQ ); 728771Speter codeon(); 7291555Speter if ( p == NIL ) { 7301555Speter return NIL; 7311555Speter } 7321555Speter if ( lwidth( p ) > lwidth( p1 ) ) { 733771Speter contype = p; 734771Speter } 7351555Speter } else if ( c1 == TSET ) { 7361555Speter if ( contype == lookup( intset ) -> type ) { 7371555Speter codeoff(); 7381555Speter p = rvalue( r[ 2 ] , NIL , LREQ ); 7391555Speter codeon(); 7401555Speter if ( p == NIL ) { 7411555Speter return NIL; 7421555Speter } 7431555Speter contype = p; 7441555Speter } 7451627Speter } 746771Speter /* 747771Speter * put out the width of the comparison. 748771Speter */ 749771Speter putleaf( P2ICON , lwidth( contype ) , 0 , P2INT , 0 ); 750771Speter /* 751771Speter * and the left hand side, 752771Speter * for sets, strings, records 753771Speter */ 754771Speter p = rvalue( r[ 2 ] , contype , LREQ ); 7555413Speter if ( p == NIL ) { 7565413Speter return NIL; 7575413Speter } 758771Speter putop( P2LISTOP , P2INT ); 759771Speter p1 = rvalue( r[ 3 ] , p , LREQ ); 7605413Speter if ( p1 == NIL ) { 7615413Speter return NIL; 7625413Speter } 763771Speter putop( P2LISTOP , P2INT ); 764771Speter putop( P2CALL , P2INT ); 765771Speter } else { 766771Speter /* 767771Speter * the easy (scalar or error) case 768771Speter */ 769771Speter p = rvalue( r[ 2 ] , contype , RREQ ); 770771Speter if ( p == NIL ) { 771771Speter return NIL; 7722056Speter } 773771Speter /* 774771Speter * since the second pass can't do 775771Speter * long op double or double op long 776771Speter * we may have to do some coercing. 777771Speter */ 77810364Smckusick tuac(p, p1, &rettype, &ctype); 779771Speter p1 = rvalue( r[ 3 ] , p , RREQ ); 7805413Speter if ( p1 == NIL ) { 7815413Speter return NIL; 7825413Speter } 78310364Smckusick tuac(p1, p, &rettype, &ctype); 784771Speter putop( relops[ r[0] - T_EQ ] , P2INT ); 78510364Smckusick sconv(P2INT, P2CHAR); 786771Speter } 787771Speter # endif PC 788771Speter c = classify(p); 789771Speter c1 = classify(p1); 790771Speter if (nocomp(c) || nocomp(c1)) 791771Speter return (NIL); 792771Speter g = NIL; 793771Speter switch (c) { 794771Speter case TBOOL: 795771Speter case TCHAR: 796771Speter if (c != c1) 797771Speter goto clash; 798771Speter break; 799771Speter case TINT: 800771Speter case TDOUBLE: 801771Speter if (c1 != TINT && c1 != TDOUBLE) 802771Speter goto clash; 803771Speter break; 804771Speter case TSCAL: 805771Speter if (c1 != TSCAL) 806771Speter goto clash; 807771Speter if (scalar(p) != scalar(p1)) 808771Speter goto nonident; 809771Speter break; 810771Speter case TSET: 811771Speter if (c1 != TSET) 812771Speter goto clash; 8133397Speter if ( opt( 's' ) && 8143397Speter ( ( r[0] == T_LT ) || ( r[0] == T_GT ) ) && 8153397Speter ( line != nssetline ) ) { 8163397Speter nssetline = line; 8173397Speter standard(); 8183397Speter error("%s comparison on sets is non-standard" , opname ); 8193397Speter } 820771Speter if (p != p1) 821771Speter goto nonident; 822771Speter g = TSET; 823771Speter break; 824771Speter case TREC: 825771Speter if ( c1 != TREC ) { 826771Speter goto clash; 827771Speter } 828771Speter if ( p != p1 ) { 829771Speter goto nonident; 830771Speter } 831771Speter if (r[0] != T_EQ && r[0] != T_NE) { 832771Speter error("%s not allowed on records - only allow = and <>" , opname ); 833771Speter return (NIL); 834771Speter } 835771Speter g = TREC; 836771Speter break; 837771Speter case TPTR: 838771Speter case TNIL: 839771Speter if (c1 != TPTR && c1 != TNIL) 840771Speter goto clash; 841771Speter if (r[0] != T_EQ && r[0] != T_NE) { 842771Speter error("%s not allowed on pointers - only allow = and <>" , opname ); 843771Speter return (NIL); 844771Speter } 845771Speter break; 846771Speter case TSTR: 847771Speter if (c1 != TSTR) 848771Speter goto clash; 849771Speter if (width(p) != width(p1)) { 850771Speter error("Strings not same length in %s comparison", opname); 851771Speter return (NIL); 852771Speter } 853771Speter g = TSTR; 854771Speter break; 855771Speter default: 856771Speter panic("rval2"); 857771Speter } 858771Speter # ifdef OBJ 859771Speter return (gen(g, r[0], width(p), width(p1))); 860771Speter # endif OBJ 861771Speter # ifdef PC 862771Speter return nl + TBOOL; 863771Speter # endif PC 864771Speter clash: 865771Speter error("%ss and %ss cannot be compared - operator was %s", clnames[c], clnames[c1], opname); 866771Speter return (NIL); 867771Speter nonident: 868771Speter error("%s types must be identical in comparisons - operator was %s", clnames[c1], opname); 869771Speter return (NIL); 870771Speter 871771Speter case T_IN: 872771Speter rt = r[3]; 873771Speter # ifdef OBJ 874771Speter if (rt != NIL && rt[0] == T_CSET) { 875771Speter precset( rt , NIL , &csetd ); 876771Speter p1 = csetd.csettype; 877771Speter if (p1 == NIL) 878771Speter return NIL; 879771Speter postcset( rt, &csetd); 880771Speter } else { 881771Speter p1 = stkrval(r[3], NIL , RREQ ); 882771Speter rt = NIL; 883771Speter } 884771Speter # endif OBJ 885771Speter # ifdef PC 886771Speter if (rt != NIL && rt[0] == T_CSET) { 887771Speter if ( precset( rt , NIL , &csetd ) ) { 8881555Speter putleaf( P2ICON , 0 , 0 8891555Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 8901555Speter , "_IN" ); 891771Speter } else { 892771Speter putleaf( P2ICON , 0 , 0 893771Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 894771Speter , "_INCT" ); 895771Speter } 896771Speter p1 = csetd.csettype; 897771Speter if (p1 == NIL) 898771Speter return NIL; 899771Speter } else { 900771Speter putleaf( P2ICON , 0 , 0 901771Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 902771Speter , "_IN" ); 903771Speter codeoff(); 904771Speter p1 = rvalue(r[3], NIL , LREQ ); 905771Speter codeon(); 906771Speter } 907771Speter # endif PC 908771Speter p = stkrval(r[2], NIL , RREQ ); 909771Speter if (p == NIL || p1 == NIL) 910771Speter return (NIL); 911771Speter if (p1->class != SET) { 912771Speter error("Right operand of 'in' must be a set, not %s", nameof(p1)); 913771Speter return (NIL); 914771Speter } 915771Speter if (incompat(p, p1->type, r[2])) { 916771Speter cerror("Index type clashed with set component type for 'in'"); 917771Speter return (NIL); 918771Speter } 919771Speter setran(p1->type); 920771Speter # ifdef OBJ 921771Speter if (rt == NIL || csetd.comptime) 922771Speter put(4, O_IN, width(p1), set.lwrb, set.uprbp); 923771Speter else 9243078Smckusic put(2, O_INCT, 9253078Smckusic (int)(3 + csetd.singcnt + 2*csetd.paircnt)); 926771Speter # endif OBJ 927771Speter # ifdef PC 928771Speter if ( rt == NIL || rt[0] != T_CSET ) { 929771Speter putleaf( P2ICON , set.lwrb , 0 , P2INT , 0 ); 930771Speter putop( P2LISTOP , P2INT ); 931771Speter putleaf( P2ICON , set.uprbp , 0 , P2INT , 0 ); 932771Speter putop( P2LISTOP , P2INT ); 933771Speter p1 = rvalue( r[3] , NIL , LREQ ); 9345413Speter if ( p1 == NIL ) { 9355413Speter return NIL; 9365413Speter } 937771Speter putop( P2LISTOP , P2INT ); 938771Speter } else if ( csetd.comptime ) { 939771Speter putleaf( P2ICON , set.lwrb , 0 , P2INT , 0 ); 940771Speter putop( P2LISTOP , P2INT ); 941771Speter putleaf( P2ICON , set.uprbp , 0 , P2INT , 0 ); 942771Speter putop( P2LISTOP , P2INT ); 943771Speter postcset( r[3] , &csetd ); 944771Speter putop( P2LISTOP , P2INT ); 945771Speter } else { 946771Speter postcset( r[3] , &csetd ); 947771Speter } 948771Speter putop( P2CALL , P2INT ); 94910364Smckusick sconv(P2INT, P2CHAR); 950771Speter # endif PC 951771Speter return (nl+T1BOOL); 952771Speter default: 953771Speter if (r[2] == NIL) 954771Speter return (NIL); 955771Speter switch (r[0]) { 956771Speter default: 957771Speter panic("rval3"); 958771Speter 959771Speter 960771Speter /* 961771Speter * An octal number 962771Speter */ 963771Speter case T_BINT: 964771Speter f = a8tol(r[2]); 965771Speter goto conint; 966771Speter 967771Speter /* 968771Speter * A decimal number 969771Speter */ 970771Speter case T_INT: 971771Speter f = atof(r[2]); 972771Speter conint: 973771Speter if (f > MAXINT || f < MININT) { 974771Speter error("Constant too large for this implementation"); 975771Speter return (NIL); 976771Speter } 977771Speter l = f; 97810364Smckusick # ifdef OBJ 97910364Smckusick if (bytes(l, l) <= 2) { 980771Speter put(2, O_CON2, ( short ) l); 98110364Smckusick return (nl+T2INT); 98210364Smckusick } 983771Speter put(2, O_CON4, l); 98410364Smckusick return (nl+T4INT); 985771Speter # endif OBJ 986771Speter # ifdef PC 98710364Smckusick switch (bytes(l, l)) { 98810364Smckusick case 1: 98910364Smckusick putleaf(P2ICON, l, 0, P2CHAR, 0); 99010364Smckusick return nl+T1INT; 99110364Smckusick case 2: 99210364Smckusick putleaf(P2ICON, l, 0, P2SHORT, 0); 99310364Smckusick return nl+T2INT; 99410364Smckusick case 4: 99510364Smckusick putleaf(P2ICON, l, 0, P2INT, 0); 99610364Smckusick return nl+T4INT; 99710364Smckusick } 998771Speter # endif PC 999771Speter 1000771Speter /* 1001771Speter * A floating point number 1002771Speter */ 1003771Speter case T_FINT: 1004771Speter # ifdef OBJ 1005771Speter put(2, O_CON8, atof(r[2])); 1006771Speter # endif OBJ 1007771Speter # ifdef PC 1008771Speter putCON8( atof( r[2] ) ); 1009771Speter # endif PC 1010771Speter return (nl+TDOUBLE); 1011771Speter 1012771Speter /* 1013771Speter * Constant strings. Note that constant characters 1014771Speter * are constant strings of length one; there is 1015771Speter * no constant string of length one. 1016771Speter */ 1017771Speter case T_STRNG: 1018771Speter cp = r[2]; 1019771Speter if (cp[1] == 0) { 1020771Speter # ifdef OBJ 1021771Speter put(2, O_CONC, cp[0]); 1022771Speter # endif OBJ 1023771Speter # ifdef PC 1024771Speter putleaf( P2ICON , cp[0] , 0 , P2CHAR , 0 ); 1025771Speter # endif PC 1026771Speter return (nl+T1CHAR); 1027771Speter } 1028771Speter goto cstrng; 1029771Speter } 1030771Speter 1031771Speter } 1032771Speter } 1033771Speter 1034771Speter /* 1035771Speter * Can a class appear 1036771Speter * in a comparison ? 1037771Speter */ 1038771Speter nocomp(c) 1039771Speter int c; 1040771Speter { 1041771Speter 1042771Speter switch (c) { 1043771Speter case TREC: 10441627Speter if ( line != reccompline ) { 10451627Speter reccompline = line; 10461627Speter warning(); 10471627Speter if ( opt( 's' ) ) { 10481627Speter standard(); 10491627Speter } 1050771Speter error("record comparison is non-standard"); 1051771Speter } 1052771Speter break; 1053771Speter case TFILE: 1054771Speter case TARY: 1055771Speter error("%ss may not participate in comparisons", clnames[c]); 1056771Speter return (1); 1057771Speter } 1058771Speter return (NIL); 1059771Speter } 1060771Speter 1061771Speter /* 1062771Speter * this is sort of like gconst, except it works on expression trees 1063771Speter * rather than declaration trees, and doesn't give error messages for 1064771Speter * non-constant things. 1065771Speter * as a side effect this fills in the con structure that gconst uses. 1066771Speter * this returns TRUE or FALSE. 1067771Speter */ 1068771Speter constval(r) 1069771Speter register int *r; 1070771Speter { 1071771Speter register struct nl *np; 1072771Speter register *cn; 1073771Speter char *cp; 1074771Speter int negd, sgnd; 1075771Speter long ci; 1076771Speter 1077771Speter con.ctype = NIL; 1078771Speter cn = r; 1079771Speter negd = sgnd = 0; 1080771Speter loop: 1081771Speter /* 1082771Speter * cn[2] is nil if error recovery generated a T_STRNG 1083771Speter */ 1084771Speter if (cn == NIL || cn[2] == NIL) 1085771Speter return FALSE; 1086771Speter switch (cn[0]) { 1087771Speter default: 1088771Speter return FALSE; 1089771Speter case T_MINUS: 1090771Speter negd = 1 - negd; 1091771Speter /* and fall through */ 1092771Speter case T_PLUS: 1093771Speter sgnd++; 1094771Speter cn = cn[2]; 1095771Speter goto loop; 1096771Speter case T_NIL: 1097771Speter con.cpval = NIL; 1098771Speter con.cival = 0; 1099771Speter con.crval = con.cival; 1100771Speter con.ctype = nl + TNIL; 1101771Speter break; 1102771Speter case T_VAR: 1103771Speter np = lookup(cn[2]); 1104771Speter if (np == NIL || np->class != CONST) { 1105771Speter return FALSE; 1106771Speter } 1107771Speter if ( cn[3] != NIL ) { 1108771Speter return FALSE; 1109771Speter } 1110771Speter con.ctype = np->type; 1111771Speter switch (classify(np->type)) { 1112771Speter case TINT: 1113771Speter con.crval = np->range[0]; 1114771Speter break; 1115771Speter case TDOUBLE: 1116771Speter con.crval = np->real; 1117771Speter break; 1118771Speter case TBOOL: 1119771Speter case TCHAR: 1120771Speter case TSCAL: 1121771Speter con.cival = np->value[0]; 1122771Speter con.crval = con.cival; 1123771Speter break; 1124771Speter case TSTR: 1125771Speter con.cpval = np->ptr[0]; 1126771Speter break; 1127771Speter default: 1128771Speter con.ctype = NIL; 1129771Speter return FALSE; 1130771Speter } 1131771Speter break; 1132771Speter case T_BINT: 1133771Speter con.crval = a8tol(cn[2]); 1134771Speter goto restcon; 1135771Speter case T_INT: 1136771Speter con.crval = atof(cn[2]); 1137771Speter if (con.crval > MAXINT || con.crval < MININT) { 1138771Speter derror("Constant too large for this implementation"); 1139771Speter con.crval = 0; 1140771Speter } 1141771Speter restcon: 1142771Speter ci = con.crval; 1143771Speter #ifndef PI0 1144771Speter if (bytes(ci, ci) <= 2) 1145771Speter con.ctype = nl+T2INT; 1146771Speter else 1147771Speter #endif 1148771Speter con.ctype = nl+T4INT; 1149771Speter break; 1150771Speter case T_FINT: 1151771Speter con.ctype = nl+TDOUBLE; 1152771Speter con.crval = atof(cn[2]); 1153771Speter break; 1154771Speter case T_STRNG: 1155771Speter cp = cn[2]; 1156771Speter if (cp[1] == 0) { 1157771Speter con.ctype = nl+T1CHAR; 1158771Speter con.cival = cp[0]; 1159771Speter con.crval = con.cival; 1160771Speter break; 1161771Speter } 1162771Speter con.ctype = nl+TSTR; 1163771Speter con.cpval = cp; 1164771Speter break; 1165771Speter } 1166771Speter if (sgnd) { 1167771Speter if (isnta(con.ctype, "id")) { 1168771Speter derror("%s constants cannot be signed", nameof(con.ctype)); 1169771Speter return FALSE; 1170771Speter } else if (negd) 1171771Speter con.crval = -con.crval; 1172771Speter } 1173771Speter return TRUE; 1174771Speter } 1175