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