1771Speter /* Copyright (c) 1979 Regents of the University of California */ 2771Speter 3*2056Speter static char sccsid[] = "@(#)rval.c 1.7 01/02/81"; 4771Speter 5771Speter #include "whoami.h" 6771Speter #include "0.h" 7771Speter #include "tree.h" 8771Speter #include "opcode.h" 9771Speter #include "objfmt.h" 10771Speter #ifdef PC 11771Speter # include "pc.h" 12771Speter # include "pcops.h" 13771Speter #endif PC 14771Speter 15771Speter extern char *opnames[]; 16771Speter 171627Speter /* line number of the last record comparison warning */ 181627Speter short reccompline = 0; 191627Speter 20771Speter #ifdef PC 21771Speter char *relts[] = { 22771Speter "_RELEQ" , "_RELNE" , 23771Speter "_RELTLT" , "_RELTGT" , 24771Speter "_RELTLE" , "_RELTGE" 25771Speter }; 26771Speter char *relss[] = { 27771Speter "_RELEQ" , "_RELNE" , 28771Speter "_RELSLT" , "_RELSGT" , 29771Speter "_RELSLE" , "_RELSGE" 30771Speter }; 31771Speter long relops[] = { 32771Speter P2EQ , P2NE , 33771Speter P2LT , P2GT , 34771Speter P2LE , P2GE 35771Speter }; 36771Speter long mathop[] = { P2MUL , P2PLUS , P2MINUS }; 37771Speter char *setop[] = { "_MULT" , "_ADDT" , "_SUBT" }; 38771Speter #endif PC 39771Speter /* 40771Speter * Rvalue - an expression. 41771Speter * 42771Speter * Contype is the type that the caller would prefer, nand is important 43771Speter * if constant sets or constant strings are involved, the latter 44771Speter * because of string padding. 45771Speter * required is a flag whether an lvalue or an rvalue is required. 46771Speter * only VARs and structured things can have gt their lvalue this way. 47771Speter */ 48771Speter struct nl * 49771Speter rvalue(r, contype , required ) 50771Speter int *r; 51771Speter struct nl *contype; 52771Speter int required; 53771Speter { 54771Speter register struct nl *p, *p1; 55771Speter register struct nl *q; 56771Speter int c, c1, *rt, w, g; 57771Speter char *cp, *cp1, *opname; 58771Speter long l; 59771Speter double f; 60771Speter extern int flagwas; 61771Speter struct csetstr csetd; 62771Speter # ifdef PC 63771Speter struct nl *rettype; 64771Speter long ctype; 65771Speter long tempoff; 66771Speter # endif PC 67771Speter 68771Speter if (r == NIL) 69771Speter return (NIL); 70771Speter if (nowexp(r)) 71771Speter return (NIL); 72771Speter /* 73771Speter * Pick up the name of the operation 74771Speter * for future error messages. 75771Speter */ 76771Speter if (r[0] <= T_IN) 77771Speter opname = opnames[r[0]]; 78771Speter 79771Speter /* 80771Speter * The root of the tree tells us what sort of expression we have. 81771Speter */ 82771Speter switch (r[0]) { 83771Speter 84771Speter /* 85771Speter * The constant nil 86771Speter */ 87771Speter case T_NIL: 88771Speter # ifdef OBJ 89771Speter put(2, O_CON2, 0); 90771Speter # endif OBJ 91771Speter # ifdef PC 921477Speter putleaf( P2ICON , 0 , 0 , P2PTR|P2UNDEF , 0 ); 93771Speter # endif PC 94771Speter return (nl+TNIL); 95771Speter 96771Speter /* 97771Speter * Function call with arguments. 98771Speter */ 99771Speter case T_FCALL: 100771Speter # ifdef OBJ 101771Speter return (funccod(r)); 102771Speter # endif OBJ 103771Speter # ifdef PC 104771Speter return (pcfunccod( r )); 105771Speter # endif PC 106771Speter 107771Speter case T_VAR: 108771Speter p = lookup(r[2]); 109771Speter if (p == NIL || p->class == BADUSE) 110771Speter return (NIL); 111771Speter switch (p->class) { 112771Speter case VAR: 113771Speter /* 114771Speter * If a variable is 115771Speter * qualified then get 116771Speter * the rvalue by a 117771Speter * lvalue and an ind. 118771Speter */ 119771Speter if (r[3] != NIL) 120771Speter goto ind; 121771Speter q = p->type; 122771Speter if (q == NIL) 123771Speter return (NIL); 124771Speter # ifdef OBJ 125771Speter w = width(q); 126771Speter switch (w) { 127771Speter case 8: 128771Speter put(2, O_RV8 | bn << 8+INDX, p->value[0]); 129771Speter break; 130771Speter case 4: 131771Speter put(2, O_RV4 | bn << 8+INDX, p->value[0]); 132771Speter break; 133771Speter case 2: 134771Speter put(2, O_RV2 | bn << 8+INDX, p->value[0]); 135771Speter break; 136771Speter case 1: 137771Speter put(2, O_RV1 | bn << 8+INDX, p->value[0]); 138771Speter break; 139771Speter default: 140771Speter put(3, O_RV | bn << 8+INDX, p->value[0], w); 141771Speter } 142771Speter # endif OBJ 143771Speter # ifdef PC 144771Speter if ( required == RREQ ) { 145771Speter putRV( p -> symbol , bn , p -> value[0] 146771Speter , p2type( q ) ); 147771Speter } else { 148771Speter putLV( p -> symbol , bn , p -> value[0] 149771Speter , p2type( q ) ); 150771Speter } 151771Speter # endif PC 152771Speter return (q); 153771Speter 154771Speter case WITHPTR: 155771Speter case REF: 156771Speter /* 157771Speter * A lvalue for these 158771Speter * is actually what one 159771Speter * might consider a rvalue. 160771Speter */ 161771Speter ind: 162771Speter q = lvalue(r, NOFLAGS , LREQ ); 163771Speter if (q == NIL) 164771Speter return (NIL); 165771Speter # ifdef OBJ 166771Speter w = width(q); 167771Speter switch (w) { 168771Speter case 8: 169771Speter put(1, O_IND8); 170771Speter break; 171771Speter case 4: 172771Speter put(1, O_IND4); 173771Speter break; 174771Speter case 2: 175771Speter put(1, O_IND2); 176771Speter break; 177771Speter case 1: 178771Speter put(1, O_IND1); 179771Speter break; 180771Speter default: 181771Speter put(2, O_IND, w); 182771Speter } 183771Speter # endif OBJ 184771Speter # ifdef PC 185771Speter if ( required == RREQ ) { 186771Speter putop( P2UNARY P2MUL , p2type( q ) ); 187771Speter } 188771Speter # endif PC 189771Speter return (q); 190771Speter 191771Speter case CONST: 192771Speter if (r[3] != NIL) { 193771Speter error("%s is a constant and cannot be qualified", r[2]); 194771Speter return (NIL); 195771Speter } 196771Speter q = p->type; 197771Speter if (q == NIL) 198771Speter return (NIL); 199771Speter if (q == nl+TSTR) { 200771Speter /* 201771Speter * Find the size of the string 202771Speter * constant if needed. 203771Speter */ 204771Speter cp = p->ptr[0]; 205771Speter cstrng: 206771Speter cp1 = cp; 207771Speter for (c = 0; *cp++; c++) 208771Speter continue; 209771Speter if (contype != NIL && !opt('s')) { 210771Speter if (width(contype) < c && classify(contype) == TSTR) { 211771Speter error("Constant string too long"); 212771Speter return (NIL); 213771Speter } 214771Speter c = width(contype); 215771Speter } 216771Speter # ifdef OBJ 217771Speter put( 2 + (sizeof(char *)/sizeof(short)) 218771Speter , O_CONG, c, cp1); 219771Speter # endif OBJ 220771Speter # ifdef PC 221771Speter putCONG( cp1 , c , required ); 222771Speter # endif PC 223771Speter /* 224771Speter * Define the string temporarily 225771Speter * so later people can know its 226771Speter * width. 227771Speter * cleaned out by stat. 228771Speter */ 229771Speter q = defnl(0, STR, 0, c); 230771Speter q->type = q; 231771Speter return (q); 232771Speter } 233771Speter if (q == nl+T1CHAR) { 234771Speter # ifdef OBJ 235771Speter put(2, O_CONC, p->value[0]); 236771Speter # endif OBJ 237771Speter # ifdef PC 238771Speter putleaf( P2ICON , p -> value[0] , 0 239771Speter , P2CHAR , 0 ); 240771Speter # endif PC 241771Speter return (q); 242771Speter } 243771Speter /* 244771Speter * Every other kind of constant here 245771Speter */ 246771Speter switch (width(q)) { 247771Speter case 8: 248771Speter #ifndef DEBUG 249771Speter # ifdef OBJ 250771Speter put(2, O_CON8, p->real); 251771Speter # endif OBJ 252771Speter # ifdef PC 253771Speter putCON8( p -> real ); 254771Speter # endif PC 255771Speter #else 256771Speter if (hp21mx) { 257771Speter f = p->real; 258771Speter conv(&f); 259771Speter l = f.plong; 260771Speter put(2, O_CON4, l); 261771Speter } else 262771Speter # ifdef OBJ 263771Speter put(2, O_CON8, p->real); 264771Speter # endif OBJ 265771Speter # ifdef PC 266771Speter putCON8( p -> real ); 267771Speter # endif PC 268771Speter #endif 269771Speter break; 270771Speter case 4: 271771Speter # ifdef OBJ 272771Speter put(2, O_CON4, p->range[0]); 273771Speter # endif OBJ 274771Speter # ifdef PC 275771Speter putleaf( P2ICON , p -> range[0] , 0 276771Speter , P2INT , 0 ); 277771Speter # endif PC 278771Speter break; 279771Speter case 2: 280771Speter # ifdef OBJ 281771Speter put(2, O_CON2, ( short ) p->range[0]); 282771Speter # endif OBJ 283771Speter # ifdef PC 284771Speter /* 285771Speter * make short constants ints 286771Speter */ 287771Speter putleaf( P2ICON , (short) p -> range[0] 288771Speter , 0 , P2INT , 0 ); 289771Speter # endif PC 290771Speter break; 291771Speter case 1: 292771Speter # ifdef OBJ 293771Speter put(2, O_CON1, p->value[0]); 294771Speter # endif OBJ 295771Speter # ifdef PC 296771Speter /* 297771Speter * make char constants ints 298771Speter */ 299771Speter putleaf( P2ICON , p -> value[0] , 0 300771Speter , P2INT , 0 ); 301771Speter # endif PC 302771Speter break; 303771Speter default: 304771Speter panic("rval"); 305771Speter } 306771Speter return (q); 307771Speter 308771Speter case FUNC: 3091200Speter case FFUNC: 310771Speter /* 311771Speter * Function call with no arguments. 312771Speter */ 313771Speter if (r[3]) { 314771Speter error("Can't qualify a function result value"); 315771Speter return (NIL); 316771Speter } 317771Speter # ifdef OBJ 318771Speter return (funccod((int *) r)); 319771Speter # endif OBJ 320771Speter # ifdef PC 321771Speter return (pcfunccod( r )); 322771Speter # endif PC 323771Speter 324771Speter case TYPE: 325771Speter error("Type names (e.g. %s) allowed only in declarations", p->symbol); 326771Speter return (NIL); 327771Speter 328771Speter case PROC: 3291200Speter case FPROC: 330771Speter error("Procedure %s found where expression required", p->symbol); 331771Speter return (NIL); 332771Speter default: 333771Speter panic("rvid"); 334771Speter } 335771Speter /* 336771Speter * Constant sets 337771Speter */ 338771Speter case T_CSET: 339771Speter # ifdef OBJ 340771Speter if ( precset( r , contype , &csetd ) ) { 341771Speter if ( csetd.csettype == NIL ) { 342771Speter return NIL; 343771Speter } 344771Speter postcset( r , &csetd ); 345771Speter } else { 346771Speter put( 2, O_PUSH, -width(csetd.csettype)); 347771Speter postcset( r , &csetd ); 348771Speter setran( ( csetd.csettype ) -> type ); 349771Speter put( 2, O_CON24, set.uprbp); 350771Speter put( 2, O_CON24, set.lwrb); 3511885Speter put( 2, O_CTTOT, 4 + csetd.singcnt + 2 * csetd.paircnt); 352771Speter } 353771Speter return csetd.csettype; 354771Speter # endif OBJ 355771Speter # ifdef PC 356771Speter if ( precset( r , contype , &csetd ) ) { 357771Speter if ( csetd.csettype == NIL ) { 358771Speter return NIL; 359771Speter } 360771Speter postcset( r , &csetd ); 361771Speter } else { 362771Speter putleaf( P2ICON , 0 , 0 363771Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 364771Speter , "_CTTOT" ); 365771Speter /* 366771Speter * allocate a temporary and use it 367771Speter */ 368771Speter sizes[ cbn ].om_off -= lwidth( csetd.csettype ); 369771Speter tempoff = sizes[ cbn ].om_off; 370771Speter putlbracket( ftnno , -tempoff ); 371771Speter if ( tempoff < sizes[ cbn ].om_max ) { 372771Speter sizes[ cbn ].om_max = tempoff; 373771Speter } 374771Speter putLV( 0 , cbn , tempoff , 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)); 401771Speter # endif OBJ 402771Speter # ifdef PC 403771Speter putop( P2UNARY P2MINUS , p2type( q ) ); 404771Speter # endif PC 405771Speter return (isa(q, "d") ? q : nl+T4INT); 406771Speter } 407771Speter return (q); 408771Speter 409771Speter case T_NOT: 410771Speter q = rvalue(r[2], NIL , RREQ ); 411771Speter if (q == NIL) 412771Speter return (NIL); 413771Speter if (isnta(q, "b")) { 414771Speter error("not must operate on a Boolean, not %s", nameof(q)); 415771Speter return (NIL); 416771Speter } 417771Speter # ifdef OBJ 418771Speter put(1, O_NOT); 419771Speter # endif OBJ 420771Speter # ifdef PC 421771Speter putop( P2NOT , P2INT ); 422771Speter # endif PC 423771Speter return (nl+T1BOOL); 424771Speter 425771Speter case T_AND: 426771Speter case T_OR: 427771Speter p = rvalue(r[2], NIL , RREQ ); 428771Speter p1 = rvalue(r[3], NIL , RREQ ); 429771Speter if (p == NIL || p1 == NIL) 430771Speter return (NIL); 431771Speter if (isnta(p, "b")) { 432771Speter error("Left operand of %s must be Boolean, not %s", opname, nameof(p)); 433771Speter return (NIL); 434771Speter } 435771Speter if (isnta(p1, "b")) { 436771Speter error("Right operand of %s must be Boolean, not %s", opname, nameof(p1)); 437771Speter return (NIL); 438771Speter } 439771Speter # ifdef OBJ 440771Speter put(1, r[0] == T_AND ? O_AND : O_OR); 441771Speter # endif OBJ 442771Speter # ifdef PC 443771Speter /* 444771Speter * note the use of & and | rather than && and || 445771Speter * to force evaluation of all the expressions. 446771Speter */ 447771Speter putop( r[ 0 ] == T_AND ? P2AND : P2OR , P2INT ); 448771Speter # endif PC 449771Speter return (nl+T1BOOL); 450771Speter 451771Speter case T_DIVD: 452771Speter # ifdef OBJ 453771Speter p = rvalue(r[2], NIL , RREQ ); 454771Speter p1 = rvalue(r[3], NIL , RREQ ); 455771Speter # endif OBJ 456771Speter # ifdef PC 457771Speter /* 458771Speter * force these to be doubles for the divide 459771Speter */ 460771Speter p = rvalue( r[ 2 ] , NIL , RREQ ); 461771Speter if ( isnta( p , "d" ) ) { 462771Speter putop( P2SCONV , P2DOUBLE ); 463771Speter } 464771Speter p1 = rvalue( r[ 3 ] , NIL , RREQ ); 465771Speter if ( isnta( p1 , "d" ) ) { 466771Speter putop( P2SCONV , P2DOUBLE ); 467771Speter } 468771Speter # endif PC 469771Speter if (p == NIL || p1 == NIL) 470771Speter return (NIL); 471771Speter if (isnta(p, "id")) { 472771Speter error("Left operand of / must be integer or real, not %s", nameof(p)); 473771Speter return (NIL); 474771Speter } 475771Speter if (isnta(p1, "id")) { 476771Speter error("Right operand of / must be integer or real, not %s", nameof(p1)); 477771Speter return (NIL); 478771Speter } 479771Speter # ifdef OBJ 480771Speter return gen(NIL, r[0], width(p), width(p1)); 481771Speter # endif OBJ 482771Speter # ifdef PC 483771Speter putop( P2DIV , P2DOUBLE ); 484771Speter return nl + TDOUBLE; 485771Speter # endif PC 486771Speter 487771Speter case T_MULT: 488771Speter case T_ADD: 489771Speter case T_SUB: 490771Speter # ifdef OBJ 491771Speter /* 4921555Speter * If the context hasn't told us the type 4931555Speter * and a constant set is present 4941555Speter * we need to infer the type 4951555Speter * before generating code. 496771Speter */ 4971555Speter if ( contype == NIL ) { 498771Speter codeoff(); 4991555Speter contype = rvalue( r[3] , NIL , RREQ ); 500771Speter codeon(); 5011555Speter if ( contype == lookup( intset ) -> type ) { 5021555Speter codeoff(); 5031555Speter contype = rvalue( r[2] , NIL , RREQ ); 5041555Speter codeon(); 5051555Speter } 506771Speter } 5071555Speter if ( contype == NIL ) { 5081555Speter return NIL; 5091555Speter } 5101555Speter p = rvalue( r[2] , contype , RREQ ); 5111555Speter p1 = rvalue( r[3] , p , RREQ ); 5121555Speter if ( p == NIL || p1 == NIL ) 5131555Speter return NIL; 514771Speter if (isa(p, "id") && isa(p1, "id")) 515771Speter return (gen(NIL, r[0], width(p), width(p1))); 516771Speter if (isa(p, "t") && isa(p1, "t")) { 517771Speter if (p != p1) { 518771Speter error("Set types of operands of %s must be identical", opname); 519771Speter return (NIL); 520771Speter } 521771Speter gen(TSET, r[0], width(p), 0); 522771Speter return (p); 523771Speter } 524771Speter # endif OBJ 525771Speter # ifdef PC 526771Speter /* 527771Speter * the second pass can't do 528771Speter * long op double or double op long 529771Speter * so we have to know the type of both operands 530771Speter * also, it gets tricky for sets, which are done 531771Speter * by function calls. 532771Speter */ 533771Speter codeoff(); 534771Speter p1 = rvalue( r[ 3 ] , contype , RREQ ); 535771Speter codeon(); 536771Speter if ( isa( p1 , "id" ) ) { 537771Speter p = rvalue( r[ 2 ] , contype , RREQ ); 538771Speter if ( ( p == NIL ) || ( p1 == NIL ) ) { 539771Speter return NIL; 540771Speter } 541771Speter if ( isa( p , "i" ) && isa( p1 , "d" ) ) { 542771Speter putop( P2SCONV , P2DOUBLE ); 543771Speter } 544771Speter p1 = rvalue( r[ 3 ] , contype , RREQ ); 545771Speter if ( isa( p , "d" ) && isa( p1 , "i" ) ) { 546771Speter putop( P2SCONV , P2DOUBLE ); 547771Speter } 548771Speter if ( isa( p , "id" ) ) { 549771Speter if ( isa( p , "d" ) || isa( p1 , "d" ) ) { 550771Speter ctype = P2DOUBLE; 551771Speter rettype = nl + TDOUBLE; 552771Speter } else { 553771Speter ctype = P2INT; 554771Speter rettype = nl + T4INT; 555771Speter } 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 */ 5791555Speter sizes[ cbn ].om_off -= lwidth( contype ); 580771Speter tempoff = sizes[ cbn ].om_off; 581771Speter putlbracket( ftnno , -tempoff ); 582771Speter if ( tempoff < sizes[ cbn ].om_max ) { 583771Speter sizes[ cbn ].om_max = tempoff; 584771Speter } 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; 764*2056Speter } 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 */ 770*2056Speter 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; 804771Speter if (p != p1) 805771Speter goto nonident; 806771Speter g = TSET; 807771Speter break; 808771Speter case TREC: 809771Speter if ( c1 != TREC ) { 810771Speter goto clash; 811771Speter } 812771Speter if ( p != p1 ) { 813771Speter goto nonident; 814771Speter } 815771Speter if (r[0] != T_EQ && r[0] != T_NE) { 816771Speter error("%s not allowed on records - only allow = and <>" , opname ); 817771Speter return (NIL); 818771Speter } 819771Speter g = TREC; 820771Speter break; 821771Speter case TPTR: 822771Speter case TNIL: 823771Speter if (c1 != TPTR && c1 != TNIL) 824771Speter goto clash; 825771Speter if (r[0] != T_EQ && r[0] != T_NE) { 826771Speter error("%s not allowed on pointers - only allow = and <>" , opname ); 827771Speter return (NIL); 828771Speter } 829771Speter break; 830771Speter case TSTR: 831771Speter if (c1 != TSTR) 832771Speter goto clash; 833771Speter if (width(p) != width(p1)) { 834771Speter error("Strings not same length in %s comparison", opname); 835771Speter return (NIL); 836771Speter } 837771Speter g = TSTR; 838771Speter break; 839771Speter default: 840771Speter panic("rval2"); 841771Speter } 842771Speter # ifdef OBJ 843771Speter return (gen(g, r[0], width(p), width(p1))); 844771Speter # endif OBJ 845771Speter # ifdef PC 846771Speter return nl + TBOOL; 847771Speter # endif PC 848771Speter clash: 849771Speter error("%ss and %ss cannot be compared - operator was %s", clnames[c], clnames[c1], opname); 850771Speter return (NIL); 851771Speter nonident: 852771Speter error("%s types must be identical in comparisons - operator was %s", clnames[c1], opname); 853771Speter return (NIL); 854771Speter 855771Speter case T_IN: 856771Speter rt = r[3]; 857771Speter # ifdef OBJ 858771Speter if (rt != NIL && rt[0] == T_CSET) { 859771Speter precset( rt , NIL , &csetd ); 860771Speter p1 = csetd.csettype; 861771Speter if (p1 == NIL) 862771Speter return NIL; 863771Speter postcset( rt, &csetd); 864771Speter } else { 865771Speter p1 = stkrval(r[3], NIL , RREQ ); 866771Speter rt = NIL; 867771Speter } 868771Speter # endif OBJ 869771Speter # ifdef PC 870771Speter if (rt != NIL && rt[0] == T_CSET) { 871771Speter if ( precset( rt , NIL , &csetd ) ) { 8721555Speter putleaf( P2ICON , 0 , 0 8731555Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 8741555Speter , "_IN" ); 875771Speter } else { 876771Speter putleaf( P2ICON , 0 , 0 877771Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 878771Speter , "_INCT" ); 879771Speter } 880771Speter p1 = csetd.csettype; 881771Speter if (p1 == NIL) 882771Speter return NIL; 883771Speter } else { 884771Speter putleaf( P2ICON , 0 , 0 885771Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 886771Speter , "_IN" ); 887771Speter codeoff(); 888771Speter p1 = rvalue(r[3], NIL , LREQ ); 889771Speter codeon(); 890771Speter } 891771Speter # endif PC 892771Speter p = stkrval(r[2], NIL , RREQ ); 893771Speter if (p == NIL || p1 == NIL) 894771Speter return (NIL); 895771Speter if (p1->class != SET) { 896771Speter error("Right operand of 'in' must be a set, not %s", nameof(p1)); 897771Speter return (NIL); 898771Speter } 899771Speter if (incompat(p, p1->type, r[2])) { 900771Speter cerror("Index type clashed with set component type for 'in'"); 901771Speter return (NIL); 902771Speter } 903771Speter setran(p1->type); 904771Speter # ifdef OBJ 905771Speter if (rt == NIL || csetd.comptime) 906771Speter put(4, O_IN, width(p1), set.lwrb, set.uprbp); 907771Speter else 908771Speter put(2, O_INCT, 3 + csetd.singcnt + 2*csetd.paircnt); 909771Speter # endif OBJ 910771Speter # ifdef PC 911771Speter if ( rt == NIL || rt[0] != T_CSET ) { 912771Speter putleaf( P2ICON , set.lwrb , 0 , P2INT , 0 ); 913771Speter putop( P2LISTOP , P2INT ); 914771Speter putleaf( P2ICON , set.uprbp , 0 , P2INT , 0 ); 915771Speter putop( P2LISTOP , P2INT ); 916771Speter p1 = rvalue( r[3] , NIL , LREQ ); 917771Speter putop( P2LISTOP , P2INT ); 918771Speter } else if ( csetd.comptime ) { 919771Speter putleaf( P2ICON , set.lwrb , 0 , P2INT , 0 ); 920771Speter putop( P2LISTOP , P2INT ); 921771Speter putleaf( P2ICON , set.uprbp , 0 , P2INT , 0 ); 922771Speter putop( P2LISTOP , P2INT ); 923771Speter postcset( r[3] , &csetd ); 924771Speter putop( P2LISTOP , P2INT ); 925771Speter } else { 926771Speter postcset( r[3] , &csetd ); 927771Speter } 928771Speter putop( P2CALL , P2INT ); 929771Speter # endif PC 930771Speter return (nl+T1BOOL); 931771Speter default: 932771Speter if (r[2] == NIL) 933771Speter return (NIL); 934771Speter switch (r[0]) { 935771Speter default: 936771Speter panic("rval3"); 937771Speter 938771Speter 939771Speter /* 940771Speter * An octal number 941771Speter */ 942771Speter case T_BINT: 943771Speter f = a8tol(r[2]); 944771Speter goto conint; 945771Speter 946771Speter /* 947771Speter * A decimal number 948771Speter */ 949771Speter case T_INT: 950771Speter f = atof(r[2]); 951771Speter conint: 952771Speter if (f > MAXINT || f < MININT) { 953771Speter error("Constant too large for this implementation"); 954771Speter return (NIL); 955771Speter } 956771Speter l = f; 957771Speter if (bytes(l, l) <= 2) { 958771Speter # ifdef OBJ 959771Speter put(2, O_CON2, ( short ) l); 960771Speter # endif OBJ 961771Speter # ifdef PC 962771Speter /* 963771Speter * short constants are ints 964771Speter */ 965771Speter putleaf( P2ICON , l , 0 , P2INT , 0 ); 966771Speter # endif PC 967771Speter return (nl+T2INT); 968771Speter } 969771Speter # ifdef OBJ 970771Speter put(2, O_CON4, l); 971771Speter # endif OBJ 972771Speter # ifdef PC 973771Speter putleaf( P2ICON , l , 0 , P2INT , 0 ); 974771Speter # endif PC 975771Speter return (nl+T4INT); 976771Speter 977771Speter /* 978771Speter * A floating point number 979771Speter */ 980771Speter case T_FINT: 981771Speter # ifdef OBJ 982771Speter put(2, O_CON8, atof(r[2])); 983771Speter # endif OBJ 984771Speter # ifdef PC 985771Speter putCON8( atof( r[2] ) ); 986771Speter # endif PC 987771Speter return (nl+TDOUBLE); 988771Speter 989771Speter /* 990771Speter * Constant strings. Note that constant characters 991771Speter * are constant strings of length one; there is 992771Speter * no constant string of length one. 993771Speter */ 994771Speter case T_STRNG: 995771Speter cp = r[2]; 996771Speter if (cp[1] == 0) { 997771Speter # ifdef OBJ 998771Speter put(2, O_CONC, cp[0]); 999771Speter # endif OBJ 1000771Speter # ifdef PC 1001771Speter putleaf( P2ICON , cp[0] , 0 , P2CHAR , 0 ); 1002771Speter # endif PC 1003771Speter return (nl+T1CHAR); 1004771Speter } 1005771Speter goto cstrng; 1006771Speter } 1007771Speter 1008771Speter } 1009771Speter } 1010771Speter 1011771Speter /* 1012771Speter * Can a class appear 1013771Speter * in a comparison ? 1014771Speter */ 1015771Speter nocomp(c) 1016771Speter int c; 1017771Speter { 1018771Speter 1019771Speter switch (c) { 1020771Speter case TREC: 10211627Speter if ( line != reccompline ) { 10221627Speter reccompline = line; 10231627Speter warning(); 10241627Speter if ( opt( 's' ) ) { 10251627Speter standard(); 10261627Speter } 1027771Speter error("record comparison is non-standard"); 1028771Speter } 1029771Speter break; 1030771Speter case TFILE: 1031771Speter case TARY: 1032771Speter error("%ss may not participate in comparisons", clnames[c]); 1033771Speter return (1); 1034771Speter } 1035771Speter return (NIL); 1036771Speter } 1037771Speter 1038771Speter /* 1039771Speter * this is sort of like gconst, except it works on expression trees 1040771Speter * rather than declaration trees, and doesn't give error messages for 1041771Speter * non-constant things. 1042771Speter * as a side effect this fills in the con structure that gconst uses. 1043771Speter * this returns TRUE or FALSE. 1044771Speter */ 1045771Speter constval(r) 1046771Speter register int *r; 1047771Speter { 1048771Speter register struct nl *np; 1049771Speter register *cn; 1050771Speter char *cp; 1051771Speter int negd, sgnd; 1052771Speter long ci; 1053771Speter 1054771Speter con.ctype = NIL; 1055771Speter cn = r; 1056771Speter negd = sgnd = 0; 1057771Speter loop: 1058771Speter /* 1059771Speter * cn[2] is nil if error recovery generated a T_STRNG 1060771Speter */ 1061771Speter if (cn == NIL || cn[2] == NIL) 1062771Speter return FALSE; 1063771Speter switch (cn[0]) { 1064771Speter default: 1065771Speter return FALSE; 1066771Speter case T_MINUS: 1067771Speter negd = 1 - negd; 1068771Speter /* and fall through */ 1069771Speter case T_PLUS: 1070771Speter sgnd++; 1071771Speter cn = cn[2]; 1072771Speter goto loop; 1073771Speter case T_NIL: 1074771Speter con.cpval = NIL; 1075771Speter con.cival = 0; 1076771Speter con.crval = con.cival; 1077771Speter con.ctype = nl + TNIL; 1078771Speter break; 1079771Speter case T_VAR: 1080771Speter np = lookup(cn[2]); 1081771Speter if (np == NIL || np->class != CONST) { 1082771Speter return FALSE; 1083771Speter } 1084771Speter if ( cn[3] != NIL ) { 1085771Speter return FALSE; 1086771Speter } 1087771Speter con.ctype = np->type; 1088771Speter switch (classify(np->type)) { 1089771Speter case TINT: 1090771Speter con.crval = np->range[0]; 1091771Speter break; 1092771Speter case TDOUBLE: 1093771Speter con.crval = np->real; 1094771Speter break; 1095771Speter case TBOOL: 1096771Speter case TCHAR: 1097771Speter case TSCAL: 1098771Speter con.cival = np->value[0]; 1099771Speter con.crval = con.cival; 1100771Speter break; 1101771Speter case TSTR: 1102771Speter con.cpval = np->ptr[0]; 1103771Speter break; 1104771Speter default: 1105771Speter con.ctype = NIL; 1106771Speter return FALSE; 1107771Speter } 1108771Speter break; 1109771Speter case T_BINT: 1110771Speter con.crval = a8tol(cn[2]); 1111771Speter goto restcon; 1112771Speter case T_INT: 1113771Speter con.crval = atof(cn[2]); 1114771Speter if (con.crval > MAXINT || con.crval < MININT) { 1115771Speter derror("Constant too large for this implementation"); 1116771Speter con.crval = 0; 1117771Speter } 1118771Speter restcon: 1119771Speter ci = con.crval; 1120771Speter #ifndef PI0 1121771Speter if (bytes(ci, ci) <= 2) 1122771Speter con.ctype = nl+T2INT; 1123771Speter else 1124771Speter #endif 1125771Speter con.ctype = nl+T4INT; 1126771Speter break; 1127771Speter case T_FINT: 1128771Speter con.ctype = nl+TDOUBLE; 1129771Speter con.crval = atof(cn[2]); 1130771Speter break; 1131771Speter case T_STRNG: 1132771Speter cp = cn[2]; 1133771Speter if (cp[1] == 0) { 1134771Speter con.ctype = nl+T1CHAR; 1135771Speter con.cival = cp[0]; 1136771Speter con.crval = con.cival; 1137771Speter break; 1138771Speter } 1139771Speter con.ctype = nl+TSTR; 1140771Speter con.cpval = cp; 1141771Speter break; 1142771Speter } 1143771Speter if (sgnd) { 1144771Speter if (isnta(con.ctype, "id")) { 1145771Speter derror("%s constants cannot be signed", nameof(con.ctype)); 1146771Speter return FALSE; 1147771Speter } else if (negd) 1148771Speter con.crval = -con.crval; 1149771Speter } 1150771Speter return TRUE; 1151771Speter } 1152