|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1980 Regents of the University of California. ! 3: * All rights reserved. The Berkeley software License Agreement ! 4: * specifies the terms and conditions for redistribution. ! 5: */ ! 6: ! 7: #ifndef lint ! 8: static char *sccsid[] = "@(#)expr.c 5.3 (Berkeley) 6/23/85"; ! 9: #endif not lint ! 10: ! 11: /* ! 12: * expr.c ! 13: * ! 14: * Routines for handling expressions, f77 compiler pass 1. ! 15: * ! 16: * University of Utah CS Dept modification history: ! 17: * ! 18: * $Log: expr.c,v $ ! 19: * Revision 1.3 86/02/26 17:13:37 rcs ! 20: * Correct COFR 411. ! 21: * P. Wong ! 22: * ! 23: * Revision 3.16 85/06/21 16:38:09 donn ! 24: * The fix to mkprim() didn't handle null substring parameters (sigh). ! 25: * ! 26: * Revision 3.15 85/06/04 04:37:03 donn ! 27: * Changed mkprim() to force substring parameters to be integral types. ! 28: * ! 29: * Revision 3.14 85/06/04 03:41:52 donn ! 30: * Change impldcl() to handle functions of type 'undefined'. ! 31: * ! 32: * Revision 3.13 85/05/06 23:14:55 donn ! 33: * Changed mkconv() so that it calls mkaltemp() instead of mktemp() to get ! 34: * a temporary when converting character strings to integers; previously we ! 35: * were having problems because mkconv() was called after tempalloc(). ! 36: * ! 37: * Revision 3.12 85/03/18 08:07:47 donn ! 38: * Fixes to help out with short integers -- if integers are by default short, ! 39: * then so are constants; and if addresses can't be stored in shorts, complain. ! 40: * ! 41: * Revision 3.11 85/03/16 22:31:27 donn ! 42: * Added hack to mkconv() to allow character values of length > 1 to be ! 43: * converted to numeric types, for Helge Skrivervik. Note that this does ! 44: * not affect use of the intrinsic ichar() conversion. ! 45: * ! 46: * Revision 3.10 85/01/15 21:06:47 donn ! 47: * Changed mkconv() to comment on implicit conversions; added intrconv() for ! 48: * use with explicit conversions by intrinsic functions. ! 49: * ! 50: * Revision 3.9 85/01/11 21:05:49 donn ! 51: * Added changes to implement SAVE statements. ! 52: * ! 53: * Revision 3.8 84/12/17 02:21:06 donn ! 54: * Added a test to prevent constant folding from being done on expressions ! 55: * whose type is not known at that point in mkexpr(). ! 56: * ! 57: * Revision 3.7 84/12/11 21:14:17 donn ! 58: * Removed obnoxious 'excess precision' warning. ! 59: * ! 60: * Revision 3.6 84/11/23 01:00:36 donn ! 61: * Added code to trim excess precision from single-precision constants, and ! 62: * to warn the user when this occurs. ! 63: * ! 64: * Revision 3.5 84/11/23 00:10:39 donn ! 65: * Changed stfcall() to remark on argument type clashes in 'calls' to ! 66: * statement functions. ! 67: * ! 68: * Revision 3.4 84/11/22 21:21:17 donn ! 69: * Fixed bug in fix to mkexpr() that caused IMPLICIT to affect intrinsics. ! 70: * ! 71: * Revision 3.3 84/11/12 18:26:14 donn ! 72: * Shuffled some code around so that the compiler remembers to free some vleng ! 73: * structures which used to just sit around. ! 74: * ! 75: * Revision 3.2 84/10/16 19:24:15 donn ! 76: * Fix for Peter Montgomery's bug with -C and invalid subscripts -- prevent ! 77: * core dumps by replacing bad subscripts with good ones. ! 78: * ! 79: * Revision 3.1 84/10/13 01:31:32 donn ! 80: * Merged Jerry Berkman's version into mine. ! 81: * ! 82: * Revision 2.7 84/09/27 15:42:52 donn ! 83: * The last fix for multiplying undeclared variables by 0 isn't sufficient, ! 84: * since the type of the 0 may not be the (implicit) type of the variable. ! 85: * I added a hack to check the implicit type of implicitly declared ! 86: * variables... ! 87: * ! 88: * Revision 2.6 84/09/14 19:34:03 donn ! 89: * Problem noted by Mike Vevea -- mkexpr will sometimes attempt to convert ! 90: * 0 to type UNKNOWN, which is illegal. Fix is to use native type instead. ! 91: * Not sure how correct (or important) this is... ! 92: * ! 93: * Revision 2.5 84/08/05 23:05:27 donn ! 94: * Added fixes to prevent fixexpr() from slicing and dicing complex conversions ! 95: * with two operands. ! 96: * ! 97: * Revision 2.4 84/08/05 17:34:48 donn ! 98: * Added an optimization to mklhs() to detect substrings of the form ch(i:i) ! 99: * and assign constant length 1 to them. ! 100: * ! 101: * Revision 2.3 84/07/19 19:38:33 donn ! 102: * Added a typecast to the last fix. Somehow I missed it the first time... ! 103: * ! 104: * Revision 2.2 84/07/19 17:19:57 donn ! 105: * Caused OPPAREN expressions to inherit the length of their operands, so ! 106: * that parenthesized character expressions work correctly. ! 107: * ! 108: * Revision 2.1 84/07/19 12:03:02 donn ! 109: * Changed comment headers for UofU. ! 110: * ! 111: * Revision 1.2 84/04/06 20:12:17 donn ! 112: * Fixed bug which caused programs with mixed-type multiplications involving ! 113: * the constant 0 to choke the compiler. ! 114: * ! 115: */ ! 116: ! 117: #include "defs.h" ! 118: ! 119: ! 120: /* little routines to create constant blocks */ ! 121: ! 122: Constp mkconst(t) ! 123: register int t; ! 124: { ! 125: register Constp p; ! 126: ! 127: p = ALLOC(Constblock); ! 128: p->tag = TCONST; ! 129: p->vtype = t; ! 130: return(p); ! 131: } ! 132: ! 133: ! 134: expptr mklogcon(l) ! 135: register int l; ! 136: { ! 137: register Constp p; ! 138: ! 139: p = mkconst(TYLOGICAL); ! 140: p->const.ci = l; ! 141: return( (expptr) p ); ! 142: } ! 143: ! 144: ! 145: ! 146: expptr mkintcon(l) ! 147: ftnint l; ! 148: { ! 149: register Constp p; ! 150: int usetype; ! 151: ! 152: if(tyint == TYSHORT) ! 153: { ! 154: short s = l; ! 155: if(l != s) ! 156: usetype = TYLONG; ! 157: else ! 158: usetype = TYSHORT; ! 159: } ! 160: else ! 161: usetype = tyint; ! 162: p = mkconst(usetype); ! 163: p->const.ci = l; ! 164: return( (expptr) p ); ! 165: } ! 166: ! 167: ! 168: ! 169: expptr mkaddcon(l) ! 170: register int l; ! 171: { ! 172: register Constp p; ! 173: ! 174: p = mkconst(TYADDR); ! 175: p->const.ci = l; ! 176: return( (expptr) p ); ! 177: } ! 178: ! 179: ! 180: ! 181: expptr mkrealcon(t, d) ! 182: register int t; ! 183: double d; ! 184: { ! 185: register Constp p; ! 186: ! 187: p = mkconst(t); ! 188: p->const.cd[0] = d; ! 189: return( (expptr) p ); ! 190: } ! 191: ! 192: expptr mkbitcon(shift, leng, s) ! 193: int shift; ! 194: register int leng; ! 195: register char *s; ! 196: { ! 197: Constp p; ! 198: register int i, j, k; ! 199: register char *bp; ! 200: int size; ! 201: ! 202: size = (shift*leng + BYTESIZE -1)/BYTESIZE; ! 203: bp = (char *) ckalloc(size); ! 204: ! 205: i = 0; ! 206: ! 207: #if (HERE == PDP11 || HERE == VAX) ! 208: j = 0; ! 209: #else ! 210: j = size; ! 211: #endif ! 212: ! 213: k = 0; ! 214: ! 215: while (leng > 0) ! 216: { ! 217: k |= (hextoi(s[--leng]) << i); ! 218: i += shift; ! 219: if (i >= BYTESIZE) ! 220: { ! 221: #if (HERE == PDP11 || HERE == VAX) ! 222: bp[j++] = k & MAXBYTE; ! 223: #else ! 224: bp[--j] = k & MAXBYTE; ! 225: #endif ! 226: k = k >> BYTESIZE; ! 227: i -= BYTESIZE; ! 228: } ! 229: } ! 230: ! 231: if (k != 0) ! 232: #if (HERE == PDP11 || HERE == VAX) ! 233: bp[j++] = k; ! 234: #else ! 235: bp[--j] = k; ! 236: #endif ! 237: ! 238: p = mkconst(TYBITSTR); ! 239: p->vleng = ICON(size); ! 240: p->const.ccp = bp; ! 241: ! 242: return ((expptr) p); ! 243: } ! 244: ! 245: ! 246: ! 247: expptr mkstrcon(l,v) ! 248: int l; ! 249: register char *v; ! 250: { ! 251: register Constp p; ! 252: register char *s; ! 253: ! 254: p = mkconst(TYCHAR); ! 255: p->vleng = ICON(l); ! 256: p->const.ccp = s = (char *) ckalloc(l); ! 257: while(--l >= 0) ! 258: *s++ = *v++; ! 259: return( (expptr) p ); ! 260: } ! 261: ! 262: ! 263: expptr mkcxcon(realp,imagp) ! 264: register expptr realp, imagp; ! 265: { ! 266: int rtype, itype; ! 267: register Constp p; ! 268: ! 269: rtype = realp->headblock.vtype; ! 270: itype = imagp->headblock.vtype; ! 271: ! 272: if( ISCONST(realp) && ISNUMERIC(rtype) && ISCONST(imagp) && ISNUMERIC(itype) ) ! 273: { ! 274: p = mkconst( (rtype==TYDREAL||itype==TYDREAL) ? TYDCOMPLEX : TYCOMPLEX); ! 275: if( ISINT(rtype) ) ! 276: p->const.cd[0] = realp->constblock.const.ci; ! 277: else p->const.cd[0] = realp->constblock.const.cd[0]; ! 278: if( ISINT(itype) ) ! 279: p->const.cd[1] = imagp->constblock.const.ci; ! 280: else p->const.cd[1] = imagp->constblock.const.cd[0]; ! 281: } ! 282: else ! 283: { ! 284: err("invalid complex constant"); ! 285: p = (Constp) errnode(); ! 286: } ! 287: ! 288: frexpr(realp); ! 289: frexpr(imagp); ! 290: return( (expptr) p ); ! 291: } ! 292: ! 293: ! 294: expptr errnode() ! 295: { ! 296: struct Errorblock *p; ! 297: p = ALLOC(Errorblock); ! 298: p->tag = TERROR; ! 299: p->vtype = TYERROR; ! 300: return( (expptr) p ); ! 301: } ! 302: ! 303: ! 304: ! 305: ! 306: ! 307: expptr mkconv(t, p) ! 308: register int t; ! 309: register expptr p; ! 310: { ! 311: register expptr q; ! 312: Addrp r, s; ! 313: register int pt; ! 314: expptr opconv(); ! 315: ! 316: if(t==TYUNKNOWN || t==TYERROR) ! 317: badtype("mkconv", t); ! 318: pt = p->headblock.vtype; ! 319: if(t == pt) ! 320: return(p); ! 321: ! 322: if( pt == TYCHAR && ISNUMERIC(t) ) ! 323: { ! 324: warn("implicit conversion of character to numeric type"); ! 325: ! 326: /* ! 327: * Ugly kluge to copy character values into numerics. ! 328: */ ! 329: s = mkaltemp(t, ENULL); ! 330: r = (Addrp) cpexpr(s); ! 331: r->vtype = TYCHAR; ! 332: r->varleng = typesize[t]; ! 333: r->vleng = mkintcon(r->varleng); ! 334: q = mkexpr(OPASSIGN, r, p); ! 335: q = mkexpr(OPCOMMA, q, s); ! 336: return(q); ! 337: } ! 338: ! 339: #if SZADDR > SZSHORT ! 340: if( pt == TYADDR && t == TYSHORT) ! 341: { ! 342: err("insufficient precision to hold address type"); ! 343: return( errnode() ); ! 344: } ! 345: #endif ! 346: if( pt == TYADDR && ISNUMERIC(t) ) ! 347: warn("implicit conversion of address to numeric type"); ! 348: ! 349: if( ISCONST(p) && pt!=TYADDR) ! 350: { ! 351: q = (expptr) mkconst(t); ! 352: consconv(t, &(q->constblock.const), ! 353: p->constblock.vtype, &(p->constblock.const) ); ! 354: frexpr(p); ! 355: } ! 356: #if TARGET == PDP11 ! 357: else if(ISINT(t) && pt==TYCHAR) ! 358: { ! 359: q = mkexpr(OPBITAND, opconv(p,TYSHORT), ICON(255)); ! 360: if(t == TYLONG) ! 361: q = opconv(q, TYLONG); ! 362: } ! 363: #endif ! 364: else ! 365: q = opconv(p, t); ! 366: ! 367: if(t == TYCHAR) ! 368: q->constblock.vleng = ICON(1); ! 369: return(q); ! 370: } ! 371: ! 372: ! 373: ! 374: /* intrinsic conversions */ ! 375: expptr intrconv(t, p) ! 376: register int t; ! 377: register expptr p; ! 378: { ! 379: register expptr q; ! 380: register int pt; ! 381: expptr opconv(); ! 382: ! 383: if(t==TYUNKNOWN || t==TYERROR) ! 384: badtype("intrconv", t); ! 385: pt = p->headblock.vtype; ! 386: if(t == pt) ! 387: return(p); ! 388: ! 389: else if( ISCONST(p) && pt!=TYADDR) ! 390: { ! 391: q = (expptr) mkconst(t); ! 392: consconv(t, &(q->constblock.const), ! 393: p->constblock.vtype, &(p->constblock.const) ); ! 394: frexpr(p); ! 395: } ! 396: #if TARGET == PDP11 ! 397: else if(ISINT(t) && pt==TYCHAR) ! 398: { ! 399: q = mkexpr(OPBITAND, opconv(p,TYSHORT), ICON(255)); ! 400: if(t == TYLONG) ! 401: q = opconv(q, TYLONG); ! 402: } ! 403: #endif ! 404: else ! 405: q = opconv(p, t); ! 406: ! 407: if(t == TYCHAR) ! 408: q->constblock.vleng = ICON(1); ! 409: return(q); ! 410: } ! 411: ! 412: ! 413: ! 414: expptr opconv(p, t) ! 415: expptr p; ! 416: int t; ! 417: { ! 418: register expptr q; ! 419: ! 420: q = mkexpr(OPCONV, p, PNULL); ! 421: q->headblock.vtype = t; ! 422: return(q); ! 423: } ! 424: ! 425: ! 426: ! 427: expptr addrof(p) ! 428: expptr p; ! 429: { ! 430: return( mkexpr(OPADDR, p, PNULL) ); ! 431: } ! 432: ! 433: ! 434: ! 435: tagptr cpexpr(p) ! 436: register tagptr p; ! 437: { ! 438: register tagptr e; ! 439: int tag; ! 440: register chainp ep, pp; ! 441: tagptr cpblock(); ! 442: ! 443: static int blksize[ ] = ! 444: { 0, ! 445: sizeof(struct Nameblock), ! 446: sizeof(struct Constblock), ! 447: sizeof(struct Exprblock), ! 448: sizeof(struct Addrblock), ! 449: sizeof(struct Tempblock), ! 450: sizeof(struct Primblock), ! 451: sizeof(struct Listblock), ! 452: sizeof(struct Errorblock) ! 453: }; ! 454: ! 455: if(p == NULL) ! 456: return(NULL); ! 457: ! 458: if( (tag = p->tag) == TNAME) ! 459: return(p); ! 460: ! 461: e = cpblock( blksize[p->tag] , p); ! 462: ! 463: switch(tag) ! 464: { ! 465: case TCONST: ! 466: if(e->constblock.vtype == TYCHAR) ! 467: { ! 468: e->constblock.const.ccp = ! 469: copyn(1+strlen(e->constblock.const.ccp), ! 470: e->constblock.const.ccp); ! 471: e->constblock.vleng = ! 472: (expptr) cpexpr(e->constblock.vleng); ! 473: } ! 474: case TERROR: ! 475: break; ! 476: ! 477: case TEXPR: ! 478: e->exprblock.leftp = (expptr) cpexpr(p->exprblock.leftp); ! 479: e->exprblock.rightp = (expptr) cpexpr(p->exprblock.rightp); ! 480: break; ! 481: ! 482: case TLIST: ! 483: if(pp = p->listblock.listp) ! 484: { ! 485: ep = e->listblock.listp = ! 486: mkchain( cpexpr(pp->datap), CHNULL); ! 487: for(pp = pp->nextp ; pp ; pp = pp->nextp) ! 488: ep = ep->nextp = ! 489: mkchain( cpexpr(pp->datap), CHNULL); ! 490: } ! 491: break; ! 492: ! 493: case TADDR: ! 494: e->addrblock.vleng = (expptr) cpexpr(e->addrblock.vleng); ! 495: e->addrblock.memoffset = (expptr)cpexpr(e->addrblock.memoffset); ! 496: e->addrblock.istemp = NO; ! 497: break; ! 498: ! 499: case TTEMP: ! 500: e->tempblock.vleng = (expptr) cpexpr(e->tempblock.vleng); ! 501: e->tempblock.istemp = NO; ! 502: break; ! 503: ! 504: case TPRIM: ! 505: e->primblock.argsp = (struct Listblock *) ! 506: cpexpr(e->primblock.argsp); ! 507: e->primblock.fcharp = (expptr) cpexpr(e->primblock.fcharp); ! 508: e->primblock.lcharp = (expptr) cpexpr(e->primblock.lcharp); ! 509: break; ! 510: ! 511: default: ! 512: badtag("cpexpr", tag); ! 513: } ! 514: ! 515: return(e); ! 516: } ! 517: ! 518: frexpr(p) ! 519: register tagptr p; ! 520: { ! 521: register chainp q; ! 522: ! 523: if(p == NULL) ! 524: return; ! 525: ! 526: switch(p->tag) ! 527: { ! 528: case TCONST: ! 529: switch (p->constblock.vtype) ! 530: { ! 531: case TYBITSTR: ! 532: case TYCHAR: ! 533: case TYHOLLERITH: ! 534: free( (charptr) (p->constblock.const.ccp) ); ! 535: frexpr(p->constblock.vleng); ! 536: } ! 537: break; ! 538: ! 539: case TADDR: ! 540: if (!optimflag && p->addrblock.istemp) ! 541: { ! 542: frtemp(p); ! 543: return; ! 544: } ! 545: frexpr(p->addrblock.vleng); ! 546: frexpr(p->addrblock.memoffset); ! 547: break; ! 548: ! 549: case TTEMP: ! 550: frexpr(p->tempblock.vleng); ! 551: break; ! 552: ! 553: case TERROR: ! 554: break; ! 555: ! 556: case TNAME: ! 557: return; ! 558: ! 559: case TPRIM: ! 560: frexpr(p->primblock.argsp); ! 561: frexpr(p->primblock.fcharp); ! 562: frexpr(p->primblock.lcharp); ! 563: break; ! 564: ! 565: case TEXPR: ! 566: frexpr(p->exprblock.leftp); ! 567: if(p->exprblock.rightp) ! 568: frexpr(p->exprblock.rightp); ! 569: break; ! 570: ! 571: case TLIST: ! 572: for(q = p->listblock.listp ; q ; q = q->nextp) ! 573: frexpr(q->datap); ! 574: frchain( &(p->listblock.listp) ); ! 575: break; ! 576: ! 577: default: ! 578: badtag("frexpr", p->tag); ! 579: } ! 580: ! 581: free( (charptr) p ); ! 582: } ! 583: ! 584: /* fix up types in expression; replace subtrees and convert ! 585: names to address blocks */ ! 586: ! 587: expptr fixtype(p) ! 588: register tagptr p; ! 589: { ! 590: ! 591: if(p == 0) ! 592: return(0); ! 593: ! 594: switch(p->tag) ! 595: { ! 596: case TCONST: ! 597: return( (expptr) p ); ! 598: ! 599: case TADDR: ! 600: p->addrblock.memoffset = fixtype(p->addrblock.memoffset); ! 601: return( (expptr) p); ! 602: ! 603: case TTEMP: ! 604: return( (expptr) p); ! 605: ! 606: case TERROR: ! 607: return( (expptr) p); ! 608: ! 609: default: ! 610: badtag("fixtype", p->tag); ! 611: ! 612: case TEXPR: ! 613: return( fixexpr(p) ); ! 614: ! 615: case TLIST: ! 616: return( (expptr) p ); ! 617: ! 618: case TPRIM: ! 619: if(p->primblock.argsp && p->primblock.namep->vclass!=CLVAR) ! 620: { ! 621: if(p->primblock.namep->vtype == TYSUBR) ! 622: { ! 623: err("function invocation of subroutine"); ! 624: return( errnode() ); ! 625: } ! 626: else ! 627: return( mkfunct(p) ); ! 628: } ! 629: else return( mklhs(p) ); ! 630: } ! 631: } ! 632: ! 633: ! 634: ! 635: ! 636: ! 637: /* special case tree transformations and cleanups of expression trees */ ! 638: ! 639: expptr fixexpr(p) ! 640: register Exprp p; ! 641: { ! 642: expptr lp; ! 643: register expptr rp; ! 644: register expptr q; ! 645: int opcode, ltype, rtype, ptype, mtype; ! 646: expptr lconst, rconst; ! 647: expptr mkpower(); ! 648: ! 649: if( ISERROR(p) ) ! 650: return( (expptr) p ); ! 651: else if(p->tag != TEXPR) ! 652: badtag("fixexpr", p->tag); ! 653: opcode = p->opcode; ! 654: if (ISCONST(p->leftp)) ! 655: lconst = (expptr) cpexpr(p->leftp); ! 656: else ! 657: lconst = NULL; ! 658: if (p->rightp && ISCONST(p->rightp)) ! 659: rconst = (expptr) cpexpr(p->rightp); ! 660: else ! 661: rconst = NULL; ! 662: lp = p->leftp = fixtype(p->leftp); ! 663: ltype = lp->headblock.vtype; ! 664: if(opcode==OPASSIGN && lp->tag!=TADDR && lp->tag!=TTEMP) ! 665: { ! 666: err("left side of assignment must be variable"); ! 667: frexpr(p); ! 668: return( errnode() ); ! 669: } ! 670: ! 671: if(p->rightp) ! 672: { ! 673: rp = p->rightp = fixtype(p->rightp); ! 674: rtype = rp->headblock.vtype; ! 675: } ! 676: else ! 677: { ! 678: rp = NULL; ! 679: rtype = 0; ! 680: } ! 681: ! 682: if(ltype==TYERROR || rtype==TYERROR) ! 683: { ! 684: frexpr(p); ! 685: frexpr(lconst); ! 686: frexpr(rconst); ! 687: return( errnode() ); ! 688: } ! 689: ! 690: /* force folding if possible */ ! 691: if( ISCONST(lp) && (rp==NULL || ISCONST(rp)) ) ! 692: { ! 693: q = mkexpr(opcode, lp, rp); ! 694: if( ISCONST(q) ) ! 695: { ! 696: frexpr(lconst); ! 697: frexpr(rconst); ! 698: return(q); ! 699: } ! 700: free( (charptr) q ); /* constants did not fold */ ! 701: } ! 702: ! 703: if( (ptype = cktype(opcode, ltype, rtype)) == TYERROR) ! 704: { ! 705: frexpr(p); ! 706: frexpr(lconst); ! 707: frexpr(rconst); ! 708: return( errnode() ); ! 709: } ! 710: ! 711: switch(opcode) ! 712: { ! 713: case OPCONCAT: ! 714: if(p->vleng == NULL) ! 715: p->vleng = mkexpr(OPPLUS, ! 716: cpexpr(lp->headblock.vleng), ! 717: cpexpr(rp->headblock.vleng) ); ! 718: break; ! 719: ! 720: case OPASSIGN: ! 721: case OPPLUSEQ: ! 722: case OPSTAREQ: ! 723: if(ltype == rtype) ! 724: break; ! 725: #if TARGET == VAX ! 726: if( ! rconst && ISREAL(ltype) && ISREAL(rtype) ) ! 727: break; ! 728: #endif ! 729: if( ISCOMPLEX(ltype) || ISCOMPLEX(rtype) ) ! 730: break; ! 731: if( ONEOF(ltype, MSKADDR|MSKINT) && ONEOF(rtype, MSKADDR|MSKINT) ! 732: #if FAMILY==PCC ! 733: && typesize[ltype]>=typesize[rtype] ) ! 734: #else ! 735: && typesize[ltype]==typesize[rtype] ) ! 736: #endif ! 737: break; ! 738: if (rconst) ! 739: { ! 740: p->rightp = fixtype( mkconv(ptype, cpexpr(rconst)) ); ! 741: frexpr(rp); ! 742: } ! 743: else ! 744: p->rightp = fixtype(mkconv(ptype, rp)); ! 745: break; ! 746: ! 747: case OPSLASH: ! 748: if( ISCOMPLEX(rtype) ) ! 749: { ! 750: p = (Exprp) call2(ptype, ! 751: ptype==TYCOMPLEX? "c_div" : "z_div", ! 752: mkconv(ptype, lp), mkconv(ptype, rp) ); ! 753: break; ! 754: } ! 755: case OPPLUS: ! 756: case OPMINUS: ! 757: case OPSTAR: ! 758: case OPMOD: ! 759: #if TARGET == VAX ! 760: if(ptype==TYDREAL && ( (ltype==TYREAL && ! lconst ) || ! 761: (rtype==TYREAL && ! rconst ) )) ! 762: break; ! 763: #endif ! 764: if( ISCOMPLEX(ptype) ) ! 765: break; ! 766: if(ltype != ptype) ! 767: if (lconst) ! 768: { ! 769: p->leftp = fixtype(mkconv(ptype, ! 770: cpexpr(lconst))); ! 771: frexpr(lp); ! 772: } ! 773: else ! 774: p->leftp = fixtype(mkconv(ptype,lp)); ! 775: if(rtype != ptype) ! 776: if (rconst) ! 777: { ! 778: p->rightp = fixtype(mkconv(ptype, ! 779: cpexpr(rconst))); ! 780: frexpr(rp); ! 781: } ! 782: else ! 783: p->rightp = fixtype(mkconv(ptype,rp)); ! 784: break; ! 785: ! 786: case OPPOWER: ! 787: return( mkpower(p) ); ! 788: ! 789: case OPLT: ! 790: case OPLE: ! 791: case OPGT: ! 792: case OPGE: ! 793: case OPEQ: ! 794: case OPNE: ! 795: if(ltype == rtype) ! 796: break; ! 797: mtype = cktype(OPMINUS, ltype, rtype); ! 798: #if TARGET == VAX ! 799: if(mtype==TYDREAL && ( (ltype==TYREAL && ! lconst) || ! 800: (rtype==TYREAL && ! rconst) )) ! 801: break; ! 802: #endif ! 803: if( ISCOMPLEX(mtype) ) ! 804: break; ! 805: if(ltype != mtype) ! 806: if (lconst) ! 807: { ! 808: p->leftp = fixtype(mkconv(mtype, ! 809: cpexpr(lconst))); ! 810: frexpr(lp); ! 811: } ! 812: else ! 813: p->leftp = fixtype(mkconv(mtype,lp)); ! 814: if(rtype != mtype) ! 815: if (rconst) ! 816: { ! 817: p->rightp = fixtype(mkconv(mtype, ! 818: cpexpr(rconst))); ! 819: frexpr(rp); ! 820: } ! 821: else ! 822: p->rightp = fixtype(mkconv(mtype,rp)); ! 823: break; ! 824: ! 825: ! 826: case OPCONV: ! 827: if(ISCOMPLEX(p->vtype)) ! 828: { ! 829: ptype = cktype(OPCONV, p->vtype, ltype); ! 830: if(p->rightp) ! 831: ptype = cktype(OPCONV, ptype, rtype); ! 832: break; ! 833: } ! 834: ptype = cktype(OPCONV, p->vtype, ltype); ! 835: if(lp->tag==TEXPR && lp->exprblock.opcode==OPCOMMA) ! 836: { ! 837: lp->exprblock.rightp = ! 838: fixtype( mkconv(ptype, lp->exprblock.rightp) ); ! 839: free( (charptr) p ); ! 840: p = (Exprp) lp; ! 841: } ! 842: break; ! 843: ! 844: case OPADDR: ! 845: if(lp->tag==TEXPR && lp->exprblock.opcode==OPADDR) ! 846: fatal("addr of addr"); ! 847: break; ! 848: ! 849: case OPCOMMA: ! 850: case OPQUEST: ! 851: case OPCOLON: ! 852: break; ! 853: ! 854: case OPPAREN: ! 855: p->vleng = (expptr) cpexpr( lp->headblock.vleng ); ! 856: break; ! 857: ! 858: case OPMIN: ! 859: case OPMAX: ! 860: ptype = p->vtype; ! 861: break; ! 862: ! 863: default: ! 864: break; ! 865: } ! 866: ! 867: p->vtype = ptype; ! 868: frexpr(lconst); ! 869: frexpr(rconst); ! 870: return((expptr) p); ! 871: } ! 872: ! 873: #if SZINT < SZLONG ! 874: /* ! 875: for efficient subscripting, replace long ints by shorts ! 876: in easy places ! 877: */ ! 878: ! 879: expptr shorten(p) ! 880: register expptr p; ! 881: { ! 882: register expptr q; ! 883: ! 884: if(p->headblock.vtype != TYLONG) ! 885: return(p); ! 886: ! 887: switch(p->tag) ! 888: { ! 889: case TERROR: ! 890: case TLIST: ! 891: return(p); ! 892: ! 893: case TCONST: ! 894: case TADDR: ! 895: return( mkconv(TYINT,p) ); ! 896: ! 897: case TEXPR: ! 898: break; ! 899: ! 900: default: ! 901: badtag("shorten", p->tag); ! 902: } ! 903: ! 904: switch(p->exprblock.opcode) ! 905: { ! 906: case OPPLUS: ! 907: case OPMINUS: ! 908: case OPSTAR: ! 909: q = shorten( cpexpr(p->exprblock.rightp) ); ! 910: if(q->headblock.vtype == TYINT) ! 911: { ! 912: p->exprblock.leftp = shorten(p->exprblock.leftp); ! 913: if(p->exprblock.leftp->headblock.vtype == TYLONG) ! 914: frexpr(q); ! 915: else ! 916: { ! 917: frexpr(p->exprblock.rightp); ! 918: p->exprblock.rightp = q; ! 919: p->exprblock.vtype = TYINT; ! 920: } ! 921: } ! 922: break; ! 923: ! 924: case OPNEG: ! 925: case OPPAREN: ! 926: p->exprblock.leftp = shorten(p->exprblock.leftp); ! 927: if(p->exprblock.leftp->headblock.vtype == TYINT) ! 928: p->exprblock.vtype = TYINT; ! 929: break; ! 930: ! 931: case OPCALL: ! 932: case OPCCALL: ! 933: p = mkconv(TYINT,p); ! 934: break; ! 935: default: ! 936: break; ! 937: } ! 938: ! 939: return(p); ! 940: } ! 941: #endif ! 942: /* fix an argument list, taking due care for special first level cases */ ! 943: ! 944: fixargs(doput, p0) ! 945: int doput; /* doput is true if the function is not intrinsic; ! 946: was used to decide whether to do a putconst, ! 947: but this is no longer done here (Feb82)*/ ! 948: struct Listblock *p0; ! 949: { ! 950: register chainp p; ! 951: register tagptr q, t; ! 952: register int qtag; ! 953: int nargs; ! 954: Addrp mkscalar(); ! 955: ! 956: nargs = 0; ! 957: if(p0) ! 958: for(p = p0->listp ; p ; p = p->nextp) ! 959: { ! 960: ++nargs; ! 961: q = p->datap; ! 962: qtag = q->tag; ! 963: if(qtag == TCONST) ! 964: { ! 965: ! 966: /* ! 967: if(q->constblock.vtype == TYSHORT) ! 968: q = (tagptr) mkconv(tyint, q); ! 969: */ ! 970: p->datap = q ; ! 971: } ! 972: else if(qtag==TPRIM && q->primblock.argsp==0 && ! 973: q->primblock.namep->vclass==CLPROC) ! 974: p->datap = (tagptr) mkaddr(q->primblock.namep); ! 975: else if(qtag==TPRIM && q->primblock.argsp==0 && ! 976: q->primblock.namep->vdim!=NULL) ! 977: p->datap = (tagptr) mkscalar(q->primblock.namep); ! 978: else if(qtag==TPRIM && q->primblock.argsp==0 && ! 979: q->primblock.namep->vdovar && ! 980: (t = (tagptr) memversion(q->primblock.namep)) ) ! 981: p->datap = (tagptr) fixtype(t); ! 982: else ! 983: p->datap = (tagptr) fixtype(q); ! 984: } ! 985: return(nargs); ! 986: } ! 987: ! 988: ! 989: Addrp mkscalar(np) ! 990: register Namep np; ! 991: { ! 992: register Addrp ap; ! 993: ! 994: vardcl(np); ! 995: ap = mkaddr(np); ! 996: ! 997: #if TARGET == VAX || TARGET == TAHOE ! 998: /* on the VAX, prolog causes array arguments ! 999: to point at the (0,...,0) element, except when ! 1000: subscript checking is on ! 1001: */ ! 1002: #ifdef SDB ! 1003: if( !checksubs && !sdbflag && np->vstg==STGARG) ! 1004: #else ! 1005: if( !checksubs && np->vstg==STGARG) ! 1006: #endif ! 1007: { ! 1008: register struct Dimblock *dp; ! 1009: dp = np->vdim; ! 1010: frexpr(ap->memoffset); ! 1011: ap->memoffset = mkexpr(OPSTAR, ! 1012: (np->vtype==TYCHAR ? ! 1013: cpexpr(np->vleng) : ! 1014: (tagptr)ICON(typesize[np->vtype]) ), ! 1015: cpexpr(dp->baseoffset) ); ! 1016: } ! 1017: #endif ! 1018: return(ap); ! 1019: } ! 1020: ! 1021: ! 1022: ! 1023: ! 1024: ! 1025: expptr mkfunct(p) ! 1026: register struct Primblock *p; ! 1027: { ! 1028: struct Entrypoint *ep; ! 1029: Addrp ap; ! 1030: struct Extsym *extp; ! 1031: register Namep np; ! 1032: register expptr q; ! 1033: expptr intrcall(), stfcall(); ! 1034: int k, nargs; ! 1035: int class; ! 1036: ! 1037: if(p->tag != TPRIM) ! 1038: return( errnode() ); ! 1039: ! 1040: np = p->namep; ! 1041: class = np->vclass; ! 1042: ! 1043: if(class == CLUNKNOWN) ! 1044: { ! 1045: np->vclass = class = CLPROC; ! 1046: if(np->vstg == STGUNKNOWN) ! 1047: { ! 1048: if(np->vtype!=TYSUBR && (k = intrfunct(np->varname)) ) ! 1049: { ! 1050: np->vstg = STGINTR; ! 1051: np->vardesc.varno = k; ! 1052: np->vprocclass = PINTRINSIC; ! 1053: } ! 1054: else ! 1055: { ! 1056: extp = mkext( varunder(VL,np->varname) ); ! 1057: if(extp->extstg == STGCOMMON) ! 1058: warn("conflicting declarations", np->varname); ! 1059: extp->extstg = STGEXT; ! 1060: np->vstg = STGEXT; ! 1061: np->vardesc.varno = extp - extsymtab; ! 1062: np->vprocclass = PEXTERNAL; ! 1063: } ! 1064: } ! 1065: else if(np->vstg==STGARG) ! 1066: { ! 1067: if(np->vtype!=TYCHAR && !ftn66flag) ! 1068: warn("Dummy procedure not declared EXTERNAL. Code may be wrong."); ! 1069: np->vprocclass = PEXTERNAL; ! 1070: } ! 1071: } ! 1072: ! 1073: if(class != CLPROC) ! 1074: fatali("invalid class code %d for function", class); ! 1075: if(p->fcharp || p->lcharp) ! 1076: { ! 1077: err("no substring of function call"); ! 1078: goto error; ! 1079: } ! 1080: impldcl(np); ! 1081: nargs = fixargs( np->vprocclass!=PINTRINSIC, p->argsp); ! 1082: ! 1083: switch(np->vprocclass) ! 1084: { ! 1085: case PEXTERNAL: ! 1086: ap = mkaddr(np); ! 1087: call: ! 1088: q = mkexpr(OPCALL, ap, p->argsp); ! 1089: if( (q->exprblock.vtype = np->vtype) == TYUNKNOWN) ! 1090: { ! 1091: err("attempt to use untyped function"); ! 1092: goto error; ! 1093: } ! 1094: if(np->vleng) ! 1095: q->exprblock.vleng = (expptr) cpexpr(np->vleng); ! 1096: break; ! 1097: ! 1098: case PINTRINSIC: ! 1099: q = intrcall(np, p->argsp, nargs); ! 1100: break; ! 1101: ! 1102: case PSTFUNCT: ! 1103: q = stfcall(np, p->argsp); ! 1104: break; ! 1105: ! 1106: case PTHISPROC: ! 1107: warn("recursive call"); ! 1108: for(ep = entries ; ep ; ep = ep->entnextp) ! 1109: if(ep->enamep == np) ! 1110: break; ! 1111: if(ep == NULL) ! 1112: fatal("mkfunct: impossible recursion"); ! 1113: ap = builtin(np->vtype, varstr(XL, ep->entryname->extname) ); ! 1114: goto call; ! 1115: ! 1116: default: ! 1117: fatali("mkfunct: impossible vprocclass %d", ! 1118: (int) (np->vprocclass) ); ! 1119: } ! 1120: free( (charptr) p ); ! 1121: return(q); ! 1122: ! 1123: error: ! 1124: frexpr(p); ! 1125: return( errnode() ); ! 1126: } ! 1127: ! 1128: ! 1129: ! 1130: LOCAL expptr stfcall(np, actlist) ! 1131: Namep np; ! 1132: struct Listblock *actlist; ! 1133: { ! 1134: register chainp actuals; ! 1135: int nargs; ! 1136: chainp oactp, formals; ! 1137: int type; ! 1138: expptr q, rhs, ap; ! 1139: Namep tnp; ! 1140: register struct Rplblock *rp; ! 1141: struct Rplblock *tlist; ! 1142: ! 1143: if(actlist) ! 1144: { ! 1145: actuals = actlist->listp; ! 1146: free( (charptr) actlist); ! 1147: } ! 1148: else ! 1149: actuals = NULL; ! 1150: oactp = actuals; ! 1151: ! 1152: nargs = 0; ! 1153: tlist = NULL; ! 1154: if( (type = np->vtype) == TYUNKNOWN) ! 1155: { ! 1156: err("attempt to use untyped statement function"); ! 1157: q = errnode(); ! 1158: goto ret; ! 1159: } ! 1160: formals = (chainp) (np->varxptr.vstfdesc->datap); ! 1161: rhs = (expptr) (np->varxptr.vstfdesc->nextp); ! 1162: ! 1163: /* copy actual arguments into temporaries */ ! 1164: while(actuals!=NULL && formals!=NULL) ! 1165: { ! 1166: rp = ALLOC(Rplblock); ! 1167: rp->rplnp = tnp = (Namep) (formals->datap); ! 1168: ap = fixtype(actuals->datap); ! 1169: if(tnp->vtype==ap->headblock.vtype && tnp->vtype!=TYCHAR ! 1170: && (ap->tag==TCONST || ap->tag==TADDR || ap->tag==TTEMP) ) ! 1171: { ! 1172: rp->rplvp = (expptr) ap; ! 1173: rp->rplxp = NULL; ! 1174: rp->rpltag = ap->tag; ! 1175: } ! 1176: else { ! 1177: rp->rplvp = (expptr) mktemp(tnp->vtype, tnp->vleng); ! 1178: rp->rplxp = fixtype( mkexpr(OPASSIGN, cpexpr(rp->rplvp), ap) ); ! 1179: if( (rp->rpltag = rp->rplxp->tag) == TERROR) ! 1180: err("disagreement of argument types in statement function call"); ! 1181: else if(tnp->vtype!=ap->headblock.vtype) ! 1182: warn("argument type mismatch in statement function"); ! 1183: } ! 1184: rp->rplnextp = tlist; ! 1185: tlist = rp; ! 1186: actuals = actuals->nextp; ! 1187: formals = formals->nextp; ! 1188: ++nargs; ! 1189: } ! 1190: ! 1191: if(actuals!=NULL || formals!=NULL) ! 1192: err("statement function definition and argument list differ"); ! 1193: ! 1194: /* ! 1195: now push down names involved in formal argument list, then ! 1196: evaluate rhs of statement function definition in this environment ! 1197: */ ! 1198: ! 1199: if(tlist) /* put tlist in front of the rpllist */ ! 1200: { ! 1201: for(rp = tlist; rp->rplnextp; rp = rp->rplnextp) ! 1202: ; ! 1203: rp->rplnextp = rpllist; ! 1204: rpllist = tlist; ! 1205: } ! 1206: ! 1207: q = (expptr) mkconv(type, fixtype(cpexpr(rhs)) ); ! 1208: ! 1209: /* now generate the tree ( t1=a1, (t2=a2,... , f))))) */ ! 1210: while(--nargs >= 0) ! 1211: { ! 1212: if(rpllist->rplxp) ! 1213: q = mkexpr(OPCOMMA, rpllist->rplxp, q); ! 1214: rp = rpllist->rplnextp; ! 1215: frexpr(rpllist->rplvp); ! 1216: free(rpllist); ! 1217: rpllist = rp; ! 1218: } ! 1219: ! 1220: ret: ! 1221: frchain( &oactp ); ! 1222: return(q); ! 1223: } ! 1224: ! 1225: ! 1226: ! 1227: ! 1228: Addrp mkplace(np) ! 1229: register Namep np; ! 1230: { ! 1231: register Addrp s; ! 1232: register struct Rplblock *rp; ! 1233: int regn; ! 1234: ! 1235: /* is name on the replace list? */ ! 1236: ! 1237: for(rp = rpllist ; rp ; rp = rp->rplnextp) ! 1238: { ! 1239: if(np == rp->rplnp) ! 1240: { ! 1241: if(rp->rpltag == TNAME) ! 1242: { ! 1243: np = (Namep) (rp->rplvp); ! 1244: break; ! 1245: } ! 1246: else return( (Addrp) cpexpr(rp->rplvp) ); ! 1247: } ! 1248: } ! 1249: ! 1250: /* is variable a DO index in a register ? */ ! 1251: ! 1252: if(np->vdovar && ( (regn = inregister(np)) >= 0) ) ! 1253: if(np->vtype == TYERROR) ! 1254: return( (Addrp) errnode() ); ! 1255: else ! 1256: { ! 1257: s = ALLOC(Addrblock); ! 1258: s->tag = TADDR; ! 1259: s->vstg = STGREG; ! 1260: s->vtype = TYIREG; ! 1261: s->issaved = np->vsave; ! 1262: s->memno = regn; ! 1263: s->memoffset = ICON(0); ! 1264: return(s); ! 1265: } ! 1266: ! 1267: vardcl(np); ! 1268: return(mkaddr(np)); ! 1269: } ! 1270: ! 1271: ! 1272: ! 1273: ! 1274: expptr mklhs(p) ! 1275: register struct Primblock *p; ! 1276: { ! 1277: expptr suboffset(); ! 1278: register Addrp s; ! 1279: Namep np; ! 1280: ! 1281: if(p->tag != TPRIM) ! 1282: return( (expptr) p ); ! 1283: np = p->namep; ! 1284: ! 1285: s = mkplace(np); ! 1286: if(s->tag!=TADDR || s->vstg==STGREG) ! 1287: { ! 1288: free( (charptr) p ); ! 1289: return( (expptr) s ); ! 1290: } ! 1291: ! 1292: /* compute the address modified by subscripts */ ! 1293: ! 1294: s->memoffset = mkexpr(OPPLUS, s->memoffset, suboffset(p) ); ! 1295: frexpr(p->argsp); ! 1296: p->argsp = NULL; ! 1297: ! 1298: /* now do substring part */ ! 1299: ! 1300: if(p->fcharp || p->lcharp) ! 1301: { ! 1302: if(np->vtype != TYCHAR) ! 1303: errstr("substring of noncharacter %s", varstr(VL,np->varname)); ! 1304: else { ! 1305: if(p->lcharp == NULL) ! 1306: p->lcharp = (expptr) cpexpr(s->vleng); ! 1307: frexpr(s->vleng); ! 1308: if(p->fcharp) ! 1309: { ! 1310: if(p->fcharp->tag == TPRIM && p->lcharp->tag == TPRIM ! 1311: && p->fcharp->primblock.namep == p->lcharp->primblock.namep) ! 1312: /* A trivial optimization -- upper == lower */ ! 1313: s->vleng = ICON(1); ! 1314: else ! 1315: s->vleng = mkexpr(OPMINUS, p->lcharp, ! 1316: mkexpr(OPMINUS, p->fcharp, ICON(1) )); ! 1317: } ! 1318: else ! 1319: s->vleng = p->lcharp; ! 1320: } ! 1321: } ! 1322: ! 1323: s->vleng = fixtype( s->vleng ); ! 1324: s->memoffset = fixtype( s->memoffset ); ! 1325: free( (charptr) p ); ! 1326: return( (expptr) s ); ! 1327: } ! 1328: ! 1329: ! 1330: ! 1331: ! 1332: ! 1333: deregister(np) ! 1334: Namep np; ! 1335: { ! 1336: if(nregvar>0 && regnamep[nregvar-1]==np) ! 1337: { ! 1338: --nregvar; ! 1339: #if FAMILY == DMR ! 1340: putnreg(); ! 1341: #endif ! 1342: } ! 1343: } ! 1344: ! 1345: ! 1346: ! 1347: ! 1348: Addrp memversion(np) ! 1349: register Namep np; ! 1350: { ! 1351: register Addrp s; ! 1352: ! 1353: if(np->vdovar==NO || (inregister(np)<0) ) ! 1354: return(NULL); ! 1355: np->vdovar = NO; ! 1356: s = mkplace(np); ! 1357: np->vdovar = YES; ! 1358: return(s); ! 1359: } ! 1360: ! 1361: ! 1362: ! 1363: inregister(np) ! 1364: register Namep np; ! 1365: { ! 1366: register int i; ! 1367: ! 1368: for(i = 0 ; i < nregvar ; ++i) ! 1369: if(regnamep[i] == np) ! 1370: return( regnum[i] ); ! 1371: return(-1); ! 1372: } ! 1373: ! 1374: ! 1375: ! 1376: ! 1377: enregister(np) ! 1378: Namep np; ! 1379: { ! 1380: if( inregister(np) >= 0) ! 1381: return(YES); ! 1382: if(nregvar >= maxregvar) ! 1383: return(NO); ! 1384: vardcl(np); ! 1385: if( ONEOF(np->vtype, MSKIREG) ) ! 1386: { ! 1387: regnamep[nregvar++] = np; ! 1388: if(nregvar > highregvar) ! 1389: highregvar = nregvar; ! 1390: #if FAMILY == DMR ! 1391: putnreg(); ! 1392: #endif ! 1393: return(YES); ! 1394: } ! 1395: else ! 1396: return(NO); ! 1397: } ! 1398: ! 1399: ! 1400: ! 1401: ! 1402: expptr suboffset(p) ! 1403: register struct Primblock *p; ! 1404: { ! 1405: int n; ! 1406: expptr size; ! 1407: expptr oftwo(); ! 1408: chainp cp; ! 1409: expptr offp, prod; ! 1410: expptr subcheck(); ! 1411: struct Dimblock *dimp; ! 1412: expptr sub[MAXDIM+1]; ! 1413: register Namep np; ! 1414: ! 1415: np = p->namep; ! 1416: offp = ICON(0); ! 1417: n = 0; ! 1418: if(p->argsp) ! 1419: for(cp = p->argsp->listp ; cp ; ++n, cp = cp->nextp) ! 1420: { ! 1421: sub[n] = fixtype(cpexpr(cp->datap)); ! 1422: if ( ! ISINT(sub[n]->headblock.vtype)) { ! 1423: errstr("%s: non-integer subscript expression", ! 1424: varstr(VL, np->varname) ); ! 1425: /* Provide a substitute -- go on to find more errors */ ! 1426: frexpr(sub[n]); ! 1427: sub[n] = ICON(1); ! 1428: } ! 1429: if(n > maxdim) ! 1430: { ! 1431: char str[28+VL]; ! 1432: sprintf(str, "%s: more than %d subscripts", ! 1433: varstr(VL, np->varname), maxdim ); ! 1434: err( str ); ! 1435: break; ! 1436: } ! 1437: } ! 1438: ! 1439: dimp = np->vdim; ! 1440: if(n>0 && dimp==NULL) ! 1441: errstr("%s: subscripts on scalar variable", ! 1442: varstr(VL, np->varname), maxdim ); ! 1443: else if(dimp && dimp->ndim!=n) ! 1444: errstr("wrong number of subscripts on %s", ! 1445: varstr(VL, np->varname) ); ! 1446: else if(n > 0) ! 1447: { ! 1448: prod = sub[--n]; ! 1449: while( --n >= 0) ! 1450: prod = mkexpr(OPPLUS, sub[n], ! 1451: mkexpr(OPSTAR, prod, cpexpr(dimp->dims[n].dimsize)) ); ! 1452: #if TARGET == VAX || TARGET == TAHOE ! 1453: #ifdef SDB ! 1454: if(checksubs || np->vstg!=STGARG || sdbflag) ! 1455: #else ! 1456: if(checksubs || np->vstg!=STGARG) ! 1457: #endif ! 1458: prod = mkexpr(OPMINUS, prod, cpexpr(dimp->baseoffset)); ! 1459: #else ! 1460: prod = mkexpr(OPMINUS, prod, cpexpr(dimp->baseoffset)); ! 1461: #endif ! 1462: if(checksubs) ! 1463: prod = subcheck(np, prod); ! 1464: size = np->vtype == TYCHAR ? ! 1465: (expptr) cpexpr(np->vleng) : ICON(typesize[np->vtype]); ! 1466: if (!oftwo(size)) ! 1467: prod = mkexpr(OPSTAR, prod, size); ! 1468: else ! 1469: prod = mkexpr(OPLSHIFT,prod,oftwo(size)); ! 1470: ! 1471: offp = mkexpr(OPPLUS, offp, prod); ! 1472: } ! 1473: ! 1474: if(p->fcharp && np->vtype==TYCHAR) ! 1475: offp = mkexpr(OPPLUS, offp, mkexpr(OPMINUS, cpexpr(p->fcharp), ICON(1) )); ! 1476: ! 1477: return(offp); ! 1478: } ! 1479: ! 1480: ! 1481: ! 1482: ! 1483: expptr subcheck(np, p) ! 1484: Namep np; ! 1485: register expptr p; ! 1486: { ! 1487: struct Dimblock *dimp; ! 1488: expptr t, checkvar, checkcond, badcall; ! 1489: ! 1490: dimp = np->vdim; ! 1491: if(dimp->nelt == NULL) ! 1492: return(p); /* don't check arrays with * bounds */ ! 1493: checkvar = NULL; ! 1494: checkcond = NULL; ! 1495: if( ISICON(p) ) ! 1496: { ! 1497: if(p->constblock.const.ci < 0) ! 1498: goto badsub; ! 1499: if( ISICON(dimp->nelt) ) ! 1500: if(p->constblock.const.ci < dimp->nelt->constblock.const.ci) ! 1501: return(p); ! 1502: else ! 1503: goto badsub; ! 1504: } ! 1505: if(p->tag==TADDR && p->addrblock.vstg==STGREG) ! 1506: { ! 1507: checkvar = (expptr) cpexpr(p); ! 1508: t = p; ! 1509: } ! 1510: else { ! 1511: checkvar = (expptr) mktemp(p->headblock.vtype, ENULL); ! 1512: t = mkexpr(OPASSIGN, cpexpr(checkvar), p); ! 1513: } ! 1514: checkcond = mkexpr(OPLT, t, cpexpr(dimp->nelt) ); ! 1515: if( ! ISICON(p) ) ! 1516: checkcond = mkexpr(OPAND, checkcond, ! 1517: mkexpr(OPLE, ICON(0), cpexpr(checkvar)) ); ! 1518: ! 1519: badcall = call4(p->headblock.vtype, "s_rnge", ! 1520: mkstrcon(VL, np->varname), ! 1521: mkconv(TYLONG, cpexpr(checkvar)), ! 1522: mkstrcon(XL, procname), ! 1523: ICON(lineno) ); ! 1524: badcall->exprblock.opcode = OPCCALL; ! 1525: p = mkexpr(OPQUEST, checkcond, ! 1526: mkexpr(OPCOLON, checkvar, badcall)); ! 1527: ! 1528: return(p); ! 1529: ! 1530: badsub: ! 1531: frexpr(p); ! 1532: errstr("subscript on variable %s out of range", varstr(VL,np->varname)); ! 1533: return ( ICON(0) ); ! 1534: } ! 1535: ! 1536: ! 1537: ! 1538: ! 1539: Addrp mkaddr(p) ! 1540: register Namep p; ! 1541: { ! 1542: struct Extsym *extp; ! 1543: register Addrp t; ! 1544: Addrp intraddr(); ! 1545: ! 1546: switch( p->vstg) ! 1547: { ! 1548: case STGUNKNOWN: ! 1549: if(p->vclass != CLPROC) ! 1550: break; ! 1551: extp = mkext( varunder(VL, p->varname) ); ! 1552: extp->extstg = STGEXT; ! 1553: p->vstg = STGEXT; ! 1554: p->vardesc.varno = extp - extsymtab; ! 1555: p->vprocclass = PEXTERNAL; ! 1556: ! 1557: case STGCOMMON: ! 1558: case STGEXT: ! 1559: case STGBSS: ! 1560: case STGINIT: ! 1561: case STGEQUIV: ! 1562: case STGARG: ! 1563: case STGLENG: ! 1564: case STGAUTO: ! 1565: t = ALLOC(Addrblock); ! 1566: t->tag = TADDR; ! 1567: if(p->vclass==CLPROC && p->vprocclass==PTHISPROC) ! 1568: t->vclass = CLVAR; ! 1569: else ! 1570: t->vclass = p->vclass; ! 1571: t->vtype = p->vtype; ! 1572: t->vstg = p->vstg; ! 1573: t->memno = p->vardesc.varno; ! 1574: t->issaved = p->vsave; ! 1575: if(p->vdim) t->isarray = YES; ! 1576: t->memoffset = ICON(p->voffset); ! 1577: if(p->vleng) ! 1578: { ! 1579: t->vleng = (expptr) cpexpr(p->vleng); ! 1580: if( ISICON(t->vleng) ) ! 1581: t->varleng = t->vleng->constblock.const.ci; ! 1582: } ! 1583: if (p->vstg == STGBSS) ! 1584: t->varsize = p->varsize; ! 1585: else if (p->vstg == STGEQUIV) ! 1586: t->varsize = eqvclass[t->memno].eqvleng; ! 1587: return(t); ! 1588: ! 1589: case STGINTR: ! 1590: return( intraddr(p) ); ! 1591: ! 1592: } ! 1593: /*debug*/fprintf(diagfile,"mkaddr. vtype=%d, vclass=%d\n", p->vtype, p->vclass); ! 1594: badstg("mkaddr", p->vstg); ! 1595: /* NOTREACHED */ ! 1596: } ! 1597: ! 1598: ! 1599: ! 1600: ! 1601: Addrp mkarg(type, argno) ! 1602: int type, argno; ! 1603: { ! 1604: register Addrp p; ! 1605: ! 1606: p = ALLOC(Addrblock); ! 1607: p->tag = TADDR; ! 1608: p->vtype = type; ! 1609: p->vclass = CLVAR; ! 1610: p->vstg = (type==TYLENG ? STGLENG : STGARG); ! 1611: p->memno = argno; ! 1612: return(p); ! 1613: } ! 1614: ! 1615: ! 1616: ! 1617: ! 1618: expptr mkprim(v, args, substr) ! 1619: register union ! 1620: { ! 1621: struct Paramblock paramblock; ! 1622: struct Nameblock nameblock; ! 1623: struct Headblock headblock; ! 1624: } *v; ! 1625: struct Listblock *args; ! 1626: chainp substr; ! 1627: { ! 1628: register struct Primblock *p; ! 1629: ! 1630: if(v->headblock.vclass == CLPARAM) ! 1631: { ! 1632: if(args || substr) ! 1633: { ! 1634: errstr("no qualifiers on parameter name %s", ! 1635: varstr(VL,v->paramblock.varname)); ! 1636: frexpr(args); ! 1637: if(substr) ! 1638: { ! 1639: frexpr(substr->datap); ! 1640: frexpr(substr->nextp->datap); ! 1641: frchain(&substr); ! 1642: } ! 1643: frexpr(v); ! 1644: return( errnode() ); ! 1645: } ! 1646: return( (expptr) cpexpr(v->paramblock.paramval) ); ! 1647: } ! 1648: ! 1649: p = ALLOC(Primblock); ! 1650: p->tag = TPRIM; ! 1651: p->vtype = v->nameblock.vtype; ! 1652: p->namep = (Namep) v; ! 1653: p->argsp = args; ! 1654: if(substr) ! 1655: { ! 1656: p->fcharp = (expptr) substr->datap; ! 1657: if (p->fcharp != ENULL && ! ISINT(p->fcharp->headblock.vtype)) ! 1658: p->fcharp = mkconv(TYINT, p->fcharp); ! 1659: p->lcharp = (expptr) substr->nextp->datap; ! 1660: if (p->lcharp != ENULL && ! ISINT(p->lcharp->headblock.vtype)) ! 1661: p->lcharp = mkconv(TYINT, p->lcharp); ! 1662: frchain(&substr); ! 1663: } ! 1664: return( (expptr) p); ! 1665: } ! 1666: ! 1667: ! 1668: ! 1669: vardcl(v) ! 1670: register Namep v; ! 1671: { ! 1672: int nelt; ! 1673: struct Dimblock *t; ! 1674: Addrp p; ! 1675: expptr neltp; ! 1676: int eltsize; ! 1677: int varsize; ! 1678: int tsize; ! 1679: int align; ! 1680: ! 1681: if(v->vdcldone) ! 1682: return; ! 1683: if(v->vclass == CLNAMELIST) ! 1684: return; ! 1685: ! 1686: if(v->vtype == TYUNKNOWN) ! 1687: impldcl(v); ! 1688: if(v->vclass == CLUNKNOWN) ! 1689: v->vclass = CLVAR; ! 1690: else if(v->vclass!=CLVAR && v->vprocclass!=PTHISPROC) ! 1691: { ! 1692: dclerr("used both as variable and non-variable", v); ! 1693: return; ! 1694: } ! 1695: if(v->vstg==STGUNKNOWN) ! 1696: v->vstg = implstg[ letter(v->varname[0]) ]; ! 1697: ! 1698: switch(v->vstg) ! 1699: { ! 1700: case STGBSS: ! 1701: v->vardesc.varno = ++lastvarno; ! 1702: if (v->vclass != CLVAR) ! 1703: break; ! 1704: nelt = 1; ! 1705: t = v->vdim; ! 1706: if (t) ! 1707: { ! 1708: neltp = t->nelt; ! 1709: if (neltp && ISICON(neltp)) ! 1710: nelt = neltp->constblock.const.ci; ! 1711: else ! 1712: dclerr("improperly dimensioned array", v); ! 1713: } ! 1714: ! 1715: if (v->vtype == TYCHAR) ! 1716: { ! 1717: v->vleng = fixtype(v->vleng); ! 1718: if (v->vleng == NULL) ! 1719: eltsize = typesize[TYCHAR]; ! 1720: else if (ISICON(v->vleng)) ! 1721: eltsize = typesize[TYCHAR] * ! 1722: v->vleng->constblock.const.ci; ! 1723: else if (v->vleng->tag != TERROR) ! 1724: { ! 1725: errstr("nonconstant string length on %s", ! 1726: varstr(VL, v->varname)); ! 1727: eltsize = 0; ! 1728: } ! 1729: } ! 1730: else ! 1731: eltsize = typesize[v->vtype]; ! 1732: ! 1733: v->varsize = nelt * eltsize; ! 1734: break; ! 1735: case STGAUTO: ! 1736: if(v->vclass==CLPROC && v->vprocclass==PTHISPROC) ! 1737: break; ! 1738: nelt = 1; ! 1739: if(t = v->vdim) ! 1740: if( (neltp = t->nelt) && ISCONST(neltp) ) ! 1741: nelt = neltp->constblock.const.ci; ! 1742: else ! 1743: dclerr("adjustable automatic array", v); ! 1744: p = autovar(nelt, v->vtype, v->vleng); ! 1745: v->vardesc.varno = p->memno; ! 1746: v->voffset = p->memoffset->constblock.const.ci; ! 1747: frexpr(p); ! 1748: break; ! 1749: ! 1750: default: ! 1751: break; ! 1752: } ! 1753: v->vdcldone = YES; ! 1754: } ! 1755: ! 1756: ! 1757: ! 1758: ! 1759: impldcl(p) ! 1760: register Namep p; ! 1761: { ! 1762: register int k; ! 1763: int type, leng; ! 1764: ! 1765: if(p->vdcldone || (p->vclass==CLPROC && p->vprocclass==PINTRINSIC) ) ! 1766: return; ! 1767: if(p->vtype == TYUNKNOWN) ! 1768: { ! 1769: k = letter(p->varname[0]); ! 1770: type = impltype[ k ]; ! 1771: leng = implleng[ k ]; ! 1772: if(type == TYUNKNOWN) ! 1773: { ! 1774: if(p->vclass == CLPROC) ! 1775: dclerr("attempt to use function of undefined type", p); ! 1776: else ! 1777: dclerr("attempt to use undefined variable", p); ! 1778: type = TYERROR; ! 1779: leng = 1; ! 1780: } ! 1781: settype(p, type, leng); ! 1782: } ! 1783: } ! 1784: ! 1785: ! 1786: ! 1787: ! 1788: LOCAL letter(c) ! 1789: register int c; ! 1790: { ! 1791: if( isupper(c) ) ! 1792: c = tolower(c); ! 1793: return(c - 'a'); ! 1794: } ! 1795: ! 1796: #define ICONEQ(z, c) (ISICON(z) && z->constblock.const.ci==c) ! 1797: #define COMMUTE { e = lp; lp = rp; rp = e; } ! 1798: ! 1799: ! 1800: expptr mkexpr(opcode, lp, rp) ! 1801: int opcode; ! 1802: register expptr lp, rp; ! 1803: { ! 1804: register expptr e, e1; ! 1805: int etype; ! 1806: int ltype, rtype; ! 1807: int ltag, rtag; ! 1808: expptr q, q1; ! 1809: expptr fold(); ! 1810: int k; ! 1811: ! 1812: ltype = lp->headblock.vtype; ! 1813: ltag = lp->tag; ! 1814: if(rp && opcode!=OPCALL && opcode!=OPCCALL) ! 1815: { ! 1816: rtype = rp->headblock.vtype; ! 1817: rtag = rp->tag; ! 1818: } ! 1819: else { ! 1820: rtype = 0; ! 1821: rtag = 0; ! 1822: } ! 1823: ! 1824: /* ! 1825: * Yuck. Why can't we fold constants AFTER ! 1826: * variables are implicitly declared??? ! 1827: */ ! 1828: if(ltype == TYUNKNOWN && ltag == TPRIM && lp->primblock.argsp == NULL) ! 1829: { ! 1830: k = letter(lp->primblock.namep->varname[0]); ! 1831: ltype = impltype[ k ]; ! 1832: } ! 1833: if(rtype == TYUNKNOWN && rtag == TPRIM && rp->primblock.argsp == NULL) ! 1834: { ! 1835: k = letter(rp->primblock.namep->varname[0]); ! 1836: rtype = impltype[ k ]; ! 1837: } ! 1838: ! 1839: etype = cktype(opcode, ltype, rtype); ! 1840: if(etype == TYERROR) ! 1841: goto error; ! 1842: ! 1843: if(etype != TYUNKNOWN) ! 1844: switch(opcode) ! 1845: { ! 1846: /* check for multiplication by 0 and 1 and addition to 0 */ ! 1847: ! 1848: case OPSTAR: ! 1849: if( ISCONST(lp) ) ! 1850: COMMUTE ! 1851: ! 1852: if( ISICON(rp) ) ! 1853: { ! 1854: if(rp->constblock.const.ci == 0) ! 1855: { ! 1856: if(etype == TYUNKNOWN) ! 1857: break; ! 1858: rp = mkconv(etype, rp); ! 1859: goto retright; ! 1860: } ! 1861: if ((lp->tag == TEXPR) && ! 1862: ((lp->exprblock.opcode == OPPLUS) || ! 1863: (lp->exprblock.opcode == OPMINUS)) && ! 1864: ISCONST(lp->exprblock.rightp) && ! 1865: ISINT(lp->exprblock.rightp->constblock.vtype)) ! 1866: { ! 1867: q1 = mkexpr(OPSTAR, lp->exprblock.rightp, ! 1868: cpexpr(rp)); ! 1869: q = mkexpr(OPSTAR, lp->exprblock.leftp, rp); ! 1870: q = mkexpr(lp->exprblock.opcode, q, q1); ! 1871: free ((char *) lp); ! 1872: return q; ! 1873: } ! 1874: else ! 1875: goto mulop; ! 1876: } ! 1877: break; ! 1878: ! 1879: case OPSLASH: ! 1880: case OPMOD: ! 1881: if( ICONEQ(rp, 0) ) ! 1882: { ! 1883: err("attempted division by zero"); ! 1884: rp = ICON(1); ! 1885: break; ! 1886: } ! 1887: if(opcode == OPMOD) ! 1888: break; ! 1889: ! 1890: ! 1891: mulop: ! 1892: if( ISICON(rp) ) ! 1893: { ! 1894: if(rp->constblock.const.ci == 1) ! 1895: goto retleft; ! 1896: ! 1897: if(rp->constblock.const.ci == -1) ! 1898: { ! 1899: frexpr(rp); ! 1900: return( mkexpr(OPNEG, lp, PNULL) ); ! 1901: } ! 1902: } ! 1903: ! 1904: if( ISSTAROP(lp) && ISICON(lp->exprblock.rightp) ) ! 1905: { ! 1906: if(opcode == OPSTAR) ! 1907: e = mkexpr(OPSTAR, lp->exprblock.rightp, rp); ! 1908: else if(ISICON(rp) && ! 1909: (lp->exprblock.rightp->constblock.const.ci % ! 1910: rp->constblock.const.ci) == 0) ! 1911: e = mkexpr(OPSLASH, lp->exprblock.rightp, rp); ! 1912: else break; ! 1913: ! 1914: e1 = lp->exprblock.leftp; ! 1915: free( (charptr) lp ); ! 1916: return( mkexpr(OPSTAR, e1, e) ); ! 1917: } ! 1918: break; ! 1919: ! 1920: ! 1921: case OPPLUS: ! 1922: if( ISCONST(lp) ) ! 1923: COMMUTE ! 1924: goto addop; ! 1925: ! 1926: case OPMINUS: ! 1927: if( ICONEQ(lp, 0) ) ! 1928: { ! 1929: frexpr(lp); ! 1930: return( mkexpr(OPNEG, rp, ENULL) ); ! 1931: } ! 1932: ! 1933: if( ISCONST(rp) ) ! 1934: { ! 1935: opcode = OPPLUS; ! 1936: consnegop(rp); ! 1937: } ! 1938: ! 1939: addop: ! 1940: if( ISICON(rp) ) ! 1941: { ! 1942: if(rp->constblock.const.ci == 0) ! 1943: goto retleft; ! 1944: if( ISPLUSOP(lp) && ISICON(lp->exprblock.rightp) ) ! 1945: { ! 1946: e = mkexpr(OPPLUS, lp->exprblock.rightp, rp); ! 1947: e1 = lp->exprblock.leftp; ! 1948: free( (charptr) lp ); ! 1949: return( mkexpr(OPPLUS, e1, e) ); ! 1950: } ! 1951: } ! 1952: break; ! 1953: ! 1954: ! 1955: case OPPOWER: ! 1956: break; ! 1957: ! 1958: case OPNEG: ! 1959: if(ltag==TEXPR && lp->exprblock.opcode==OPNEG) ! 1960: { ! 1961: e = lp->exprblock.leftp; ! 1962: free( (charptr) lp ); ! 1963: return(e); ! 1964: } ! 1965: break; ! 1966: ! 1967: case OPNOT: ! 1968: if(ltag==TEXPR && lp->exprblock.opcode==OPNOT) ! 1969: { ! 1970: e = lp->exprblock.leftp; ! 1971: free( (charptr) lp ); ! 1972: return(e); ! 1973: } ! 1974: break; ! 1975: ! 1976: case OPCALL: ! 1977: case OPCCALL: ! 1978: etype = ltype; ! 1979: if(rp!=NULL && rp->listblock.listp==NULL) ! 1980: { ! 1981: free( (charptr) rp ); ! 1982: rp = NULL; ! 1983: } ! 1984: break; ! 1985: ! 1986: case OPAND: ! 1987: case OPOR: ! 1988: if( ISCONST(lp) ) ! 1989: COMMUTE ! 1990: ! 1991: if( ISCONST(rp) ) ! 1992: { ! 1993: if(rp->constblock.const.ci == 0) ! 1994: if(opcode == OPOR) ! 1995: goto retleft; ! 1996: else ! 1997: goto retright; ! 1998: else if(opcode == OPOR) ! 1999: goto retright; ! 2000: else ! 2001: goto retleft; ! 2002: } ! 2003: case OPLSHIFT: ! 2004: if (ISICON(rp)) ! 2005: { ! 2006: if (rp->constblock.const.ci == 0) ! 2007: goto retleft; ! 2008: if ((lp->tag == TEXPR) && ! 2009: ((lp->exprblock.opcode == OPPLUS) || ! 2010: (lp->exprblock.opcode == OPMINUS)) && ! 2011: ISICON(lp->exprblock.rightp)) ! 2012: { ! 2013: q1 = mkexpr(OPLSHIFT, lp->exprblock.rightp, ! 2014: cpexpr(rp)); ! 2015: q = mkexpr(OPLSHIFT, lp->exprblock.leftp, rp); ! 2016: q = mkexpr(lp->exprblock.opcode, q, q1); ! 2017: free((char *) lp); ! 2018: return q; ! 2019: } ! 2020: } ! 2021: ! 2022: case OPEQV: ! 2023: case OPNEQV: ! 2024: ! 2025: case OPBITAND: ! 2026: case OPBITOR: ! 2027: case OPBITXOR: ! 2028: case OPBITNOT: ! 2029: case OPRSHIFT: ! 2030: ! 2031: case OPLT: ! 2032: case OPGT: ! 2033: case OPLE: ! 2034: case OPGE: ! 2035: case OPEQ: ! 2036: case OPNE: ! 2037: ! 2038: case OPCONCAT: ! 2039: break; ! 2040: case OPMIN: ! 2041: case OPMAX: ! 2042: ! 2043: case OPASSIGN: ! 2044: case OPPLUSEQ: ! 2045: case OPSTAREQ: ! 2046: ! 2047: case OPCONV: ! 2048: case OPADDR: ! 2049: ! 2050: case OPCOMMA: ! 2051: case OPQUEST: ! 2052: case OPCOLON: ! 2053: ! 2054: case OPPAREN: ! 2055: break; ! 2056: ! 2057: default: ! 2058: badop("mkexpr", opcode); ! 2059: } ! 2060: ! 2061: e = (expptr) ALLOC(Exprblock); ! 2062: e->exprblock.tag = TEXPR; ! 2063: e->exprblock.opcode = opcode; ! 2064: e->exprblock.vtype = etype; ! 2065: e->exprblock.leftp = lp; ! 2066: e->exprblock.rightp = rp; ! 2067: if(ltag==TCONST && (rp==0 || rtag==TCONST) ) ! 2068: e = fold(e); ! 2069: return(e); ! 2070: ! 2071: retleft: ! 2072: frexpr(rp); ! 2073: return(lp); ! 2074: ! 2075: retright: ! 2076: frexpr(lp); ! 2077: return(rp); ! 2078: ! 2079: error: ! 2080: frexpr(lp); ! 2081: if(rp && opcode!=OPCALL && opcode!=OPCCALL) ! 2082: frexpr(rp); ! 2083: return( errnode() ); ! 2084: } ! 2085: ! 2086: #define ERR(s) { errs = s; goto error; } ! 2087: ! 2088: cktype(op, lt, rt) ! 2089: register int op, lt, rt; ! 2090: { ! 2091: char *errs; ! 2092: ! 2093: if(lt==TYERROR || rt==TYERROR) ! 2094: goto error1; ! 2095: ! 2096: if(lt==TYUNKNOWN) ! 2097: return(TYUNKNOWN); ! 2098: if(rt==TYUNKNOWN) ! 2099: if (op!=OPNOT && op!=OPBITNOT && op!=OPNEG && op!=OPCALL && ! 2100: op!=OPCCALL && op!=OPADDR && op!=OPPAREN) ! 2101: return(TYUNKNOWN); ! 2102: ! 2103: switch(op) ! 2104: { ! 2105: case OPPLUS: ! 2106: case OPMINUS: ! 2107: case OPSTAR: ! 2108: case OPSLASH: ! 2109: case OPPOWER: ! 2110: case OPMOD: ! 2111: if( ISNUMERIC(lt) && ISNUMERIC(rt) ) ! 2112: return( maxtype(lt, rt) ); ! 2113: ERR("nonarithmetic operand of arithmetic operator") ! 2114: ! 2115: case OPNEG: ! 2116: if( ISNUMERIC(lt) ) ! 2117: return(lt); ! 2118: ERR("nonarithmetic operand of negation") ! 2119: ! 2120: case OPNOT: ! 2121: if(lt == TYLOGICAL) ! 2122: return(TYLOGICAL); ! 2123: ERR("NOT of nonlogical") ! 2124: ! 2125: case OPAND: ! 2126: case OPOR: ! 2127: case OPEQV: ! 2128: case OPNEQV: ! 2129: if(lt==TYLOGICAL && rt==TYLOGICAL) ! 2130: return(TYLOGICAL); ! 2131: ERR("nonlogical operand of logical operator") ! 2132: ! 2133: case OPLT: ! 2134: case OPGT: ! 2135: case OPLE: ! 2136: case OPGE: ! 2137: case OPEQ: ! 2138: case OPNE: ! 2139: if(lt==TYCHAR || rt==TYCHAR || lt==TYLOGICAL || rt==TYLOGICAL) ! 2140: { ! 2141: if(lt != rt) ! 2142: ERR("illegal comparison") ! 2143: } ! 2144: ! 2145: else if( ISCOMPLEX(lt) || ISCOMPLEX(rt) ) ! 2146: { ! 2147: if(op!=OPEQ && op!=OPNE) ! 2148: ERR("order comparison of complex data") ! 2149: } ! 2150: ! 2151: else if( ! ISNUMERIC(lt) || ! ISNUMERIC(rt) ) ! 2152: ERR("comparison of nonarithmetic data") ! 2153: return(TYLOGICAL); ! 2154: ! 2155: case OPCONCAT: ! 2156: if(lt==TYCHAR && rt==TYCHAR) ! 2157: return(TYCHAR); ! 2158: ERR("concatenation of nonchar data") ! 2159: ! 2160: case OPCALL: ! 2161: case OPCCALL: ! 2162: return(lt); ! 2163: ! 2164: case OPADDR: ! 2165: return(TYADDR); ! 2166: ! 2167: case OPCONV: ! 2168: if(ISCOMPLEX(lt)) ! 2169: { ! 2170: if(ISNUMERIC(rt)) ! 2171: return(lt); ! 2172: ERR("impossible conversion") ! 2173: } ! 2174: if(rt == 0) ! 2175: return(0); ! 2176: if(lt==TYCHAR && ISINT(rt) ) ! 2177: return(TYCHAR); ! 2178: case OPASSIGN: ! 2179: case OPPLUSEQ: ! 2180: case OPSTAREQ: ! 2181: if( ISINT(lt) && rt==TYCHAR) ! 2182: return(lt); ! 2183: if(lt==TYCHAR || rt==TYCHAR || lt==TYLOGICAL || rt==TYLOGICAL) ! 2184: if(op!=OPASSIGN || lt!=rt) ! 2185: { ! 2186: /* debug fprintf(diagfile, " lt=%d, rt=%d, op=%d\n", lt, rt, op); */ ! 2187: /* debug fatal("impossible conversion. possible compiler bug"); */ ! 2188: ERR("impossible conversion") ! 2189: } ! 2190: return(lt); ! 2191: ! 2192: case OPMIN: ! 2193: case OPMAX: ! 2194: case OPBITOR: ! 2195: case OPBITAND: ! 2196: case OPBITXOR: ! 2197: case OPBITNOT: ! 2198: case OPLSHIFT: ! 2199: case OPRSHIFT: ! 2200: case OPPAREN: ! 2201: return(lt); ! 2202: ! 2203: case OPCOMMA: ! 2204: case OPQUEST: ! 2205: case OPCOLON: ! 2206: return(rt); ! 2207: ! 2208: default: ! 2209: badop("cktype", op); ! 2210: } ! 2211: error: err(errs); ! 2212: error1: return(TYERROR); ! 2213: } ! 2214: ! 2215: LOCAL expptr fold(e) ! 2216: register expptr e; ! 2217: { ! 2218: Constp p; ! 2219: register expptr lp, rp; ! 2220: int etype, mtype, ltype, rtype, opcode; ! 2221: int i, ll, lr; ! 2222: char *q, *s; ! 2223: union Constant lcon, rcon; ! 2224: ! 2225: opcode = e->exprblock.opcode; ! 2226: etype = e->exprblock.vtype; ! 2227: ! 2228: lp = e->exprblock.leftp; ! 2229: ltype = lp->headblock.vtype; ! 2230: rp = e->exprblock.rightp; ! 2231: ! 2232: if(rp == 0) ! 2233: switch(opcode) ! 2234: { ! 2235: case OPNOT: ! 2236: lp->constblock.const.ci = ! lp->constblock.const.ci; ! 2237: return(lp); ! 2238: ! 2239: case OPBITNOT: ! 2240: lp->constblock.const.ci = ~ lp->constblock.const.ci; ! 2241: return(lp); ! 2242: ! 2243: case OPNEG: ! 2244: consnegop(lp); ! 2245: return(lp); ! 2246: ! 2247: case OPCONV: ! 2248: case OPADDR: ! 2249: case OPPAREN: ! 2250: return(e); ! 2251: ! 2252: default: ! 2253: badop("fold", opcode); ! 2254: } ! 2255: ! 2256: rtype = rp->headblock.vtype; ! 2257: ! 2258: p = ALLOC(Constblock); ! 2259: p->tag = TCONST; ! 2260: p->vtype = etype; ! 2261: p->vleng = e->exprblock.vleng; ! 2262: ! 2263: switch(opcode) ! 2264: { ! 2265: case OPCOMMA: ! 2266: case OPQUEST: ! 2267: case OPCOLON: ! 2268: return(e); ! 2269: ! 2270: case OPAND: ! 2271: p->const.ci = lp->constblock.const.ci && ! 2272: rp->constblock.const.ci; ! 2273: break; ! 2274: ! 2275: case OPOR: ! 2276: p->const.ci = lp->constblock.const.ci || ! 2277: rp->constblock.const.ci; ! 2278: break; ! 2279: ! 2280: case OPEQV: ! 2281: p->const.ci = lp->constblock.const.ci == ! 2282: rp->constblock.const.ci; ! 2283: break; ! 2284: ! 2285: case OPNEQV: ! 2286: p->const.ci = lp->constblock.const.ci != ! 2287: rp->constblock.const.ci; ! 2288: break; ! 2289: ! 2290: case OPBITAND: ! 2291: p->const.ci = lp->constblock.const.ci & ! 2292: rp->constblock.const.ci; ! 2293: break; ! 2294: ! 2295: case OPBITOR: ! 2296: p->const.ci = lp->constblock.const.ci | ! 2297: rp->constblock.const.ci; ! 2298: break; ! 2299: ! 2300: case OPBITXOR: ! 2301: p->const.ci = lp->constblock.const.ci ^ ! 2302: rp->constblock.const.ci; ! 2303: break; ! 2304: ! 2305: case OPLSHIFT: ! 2306: p->const.ci = lp->constblock.const.ci << ! 2307: rp->constblock.const.ci; ! 2308: break; ! 2309: ! 2310: case OPRSHIFT: ! 2311: p->const.ci = lp->constblock.const.ci >> ! 2312: rp->constblock.const.ci; ! 2313: break; ! 2314: ! 2315: case OPCONCAT: ! 2316: ll = lp->constblock.vleng->constblock.const.ci; ! 2317: lr = rp->constblock.vleng->constblock.const.ci; ! 2318: p->const.ccp = q = (char *) ckalloc(ll+lr); ! 2319: p->vleng = ICON(ll+lr); ! 2320: s = lp->constblock.const.ccp; ! 2321: for(i = 0 ; i < ll ; ++i) ! 2322: *q++ = *s++; ! 2323: s = rp->constblock.const.ccp; ! 2324: for(i = 0; i < lr; ++i) ! 2325: *q++ = *s++; ! 2326: break; ! 2327: ! 2328: ! 2329: case OPPOWER: ! 2330: if( ! ISINT(rtype) ) ! 2331: return(e); ! 2332: conspower(&(p->const), lp, rp->constblock.const.ci); ! 2333: break; ! 2334: ! 2335: ! 2336: default: ! 2337: if(ltype == TYCHAR) ! 2338: { ! 2339: lcon.ci = cmpstr(lp->constblock.const.ccp, ! 2340: rp->constblock.const.ccp, ! 2341: lp->constblock.vleng->constblock.const.ci, ! 2342: rp->constblock.vleng->constblock.const.ci); ! 2343: rcon.ci = 0; ! 2344: mtype = tyint; ! 2345: } ! 2346: else { ! 2347: mtype = maxtype(ltype, rtype); ! 2348: consconv(mtype, &lcon, ltype, &(lp->constblock.const) ); ! 2349: consconv(mtype, &rcon, rtype, &(rp->constblock.const) ); ! 2350: } ! 2351: consbinop(opcode, mtype, &(p->const), &lcon, &rcon); ! 2352: break; ! 2353: } ! 2354: ! 2355: frexpr(e); ! 2356: return( (expptr) p ); ! 2357: } ! 2358: ! 2359: ! 2360: ! 2361: /* assign constant l = r , doing coercion */ ! 2362: ! 2363: consconv(lt, lv, rt, rv) ! 2364: int lt, rt; ! 2365: register union Constant *lv, *rv; ! 2366: { ! 2367: switch(lt) ! 2368: { ! 2369: case TYCHAR: ! 2370: *(lv->ccp = (char *) ckalloc(1)) = rv->ci; ! 2371: break; ! 2372: ! 2373: case TYSHORT: ! 2374: case TYLONG: ! 2375: if(rt == TYCHAR) ! 2376: lv->ci = rv->ccp[0]; ! 2377: else if( ISINT(rt) ) ! 2378: lv->ci = rv->ci; ! 2379: else lv->ci = rv->cd[0]; ! 2380: break; ! 2381: ! 2382: case TYCOMPLEX: ! 2383: case TYDCOMPLEX: ! 2384: switch(rt) ! 2385: { ! 2386: case TYSHORT: ! 2387: case TYLONG: ! 2388: /* fall through and do real assignment of ! 2389: first element ! 2390: */ ! 2391: case TYREAL: ! 2392: case TYDREAL: ! 2393: lv->cd[1] = 0; break; ! 2394: case TYCOMPLEX: ! 2395: case TYDCOMPLEX: ! 2396: lv->cd[1] = rv->cd[1]; break; ! 2397: } ! 2398: ! 2399: case TYREAL: ! 2400: case TYDREAL: ! 2401: if( ISINT(rt) ) ! 2402: lv->cd[0] = rv->ci; ! 2403: else lv->cd[0] = rv->cd[0]; ! 2404: if( lt == TYREAL) ! 2405: { ! 2406: float f = lv->cd[0]; ! 2407: lv->cd[0] = f; ! 2408: } ! 2409: break; ! 2410: ! 2411: case TYLOGICAL: ! 2412: lv->ci = rv->ci; ! 2413: break; ! 2414: } ! 2415: } ! 2416: ! 2417: ! 2418: ! 2419: consnegop(p) ! 2420: register Constp p; ! 2421: { ! 2422: switch(p->vtype) ! 2423: { ! 2424: case TYSHORT: ! 2425: case TYLONG: ! 2426: p->const.ci = - p->const.ci; ! 2427: break; ! 2428: ! 2429: case TYCOMPLEX: ! 2430: case TYDCOMPLEX: ! 2431: p->const.cd[1] = - p->const.cd[1]; ! 2432: /* fall through and do the real parts */ ! 2433: case TYREAL: ! 2434: case TYDREAL: ! 2435: p->const.cd[0] = - p->const.cd[0]; ! 2436: break; ! 2437: default: ! 2438: badtype("consnegop", p->vtype); ! 2439: } ! 2440: } ! 2441: ! 2442: ! 2443: ! 2444: LOCAL conspower(powp, ap, n) ! 2445: register union Constant *powp; ! 2446: Constp ap; ! 2447: ftnint n; ! 2448: { ! 2449: register int type; ! 2450: union Constant x; ! 2451: ! 2452: switch(type = ap->vtype) /* pow = 1 */ ! 2453: { ! 2454: case TYSHORT: ! 2455: case TYLONG: ! 2456: powp->ci = 1; ! 2457: break; ! 2458: case TYCOMPLEX: ! 2459: case TYDCOMPLEX: ! 2460: powp->cd[1] = 0; ! 2461: case TYREAL: ! 2462: case TYDREAL: ! 2463: powp->cd[0] = 1; ! 2464: break; ! 2465: default: ! 2466: badtype("conspower", type); ! 2467: } ! 2468: ! 2469: if(n == 0) ! 2470: return; ! 2471: if(n < 0) ! 2472: { ! 2473: if( ISINT(type) ) ! 2474: { ! 2475: if (ap->const.ci == 0) ! 2476: err("zero raised to a negative power"); ! 2477: else if (ap->const.ci == 1) ! 2478: return; ! 2479: else if (ap->const.ci == -1) ! 2480: { ! 2481: if (n < -2) ! 2482: n = n + 2; ! 2483: n = -n; ! 2484: if (n % 2 == 1) ! 2485: powp->ci = -1; ! 2486: } ! 2487: else ! 2488: powp->ci = 0; ! 2489: return; ! 2490: } ! 2491: n = - n; ! 2492: consbinop(OPSLASH, type, &x, powp, &(ap->const)); ! 2493: } ! 2494: else ! 2495: consbinop(OPSTAR, type, &x, powp, &(ap->const)); ! 2496: ! 2497: for( ; ; ) ! 2498: { ! 2499: if(n & 01) ! 2500: consbinop(OPSTAR, type, powp, powp, &x); ! 2501: if(n >>= 1) ! 2502: consbinop(OPSTAR, type, &x, &x, &x); ! 2503: else ! 2504: break; ! 2505: } ! 2506: } ! 2507: ! 2508: ! 2509: ! 2510: /* do constant operation cp = a op b */ ! 2511: ! 2512: ! 2513: LOCAL consbinop(opcode, type, cp, ap, bp) ! 2514: int opcode, type; ! 2515: register union Constant *ap, *bp, *cp; ! 2516: { ! 2517: int k; ! 2518: double temp; ! 2519: ! 2520: switch(opcode) ! 2521: { ! 2522: case OPPLUS: ! 2523: switch(type) ! 2524: { ! 2525: case TYSHORT: ! 2526: case TYLONG: ! 2527: cp->ci = ap->ci + bp->ci; ! 2528: break; ! 2529: case TYCOMPLEX: ! 2530: case TYDCOMPLEX: ! 2531: cp->cd[1] = ap->cd[1] + bp->cd[1]; ! 2532: case TYREAL: ! 2533: case TYDREAL: ! 2534: cp->cd[0] = ap->cd[0] + bp->cd[0]; ! 2535: break; ! 2536: } ! 2537: break; ! 2538: ! 2539: case OPMINUS: ! 2540: switch(type) ! 2541: { ! 2542: case TYSHORT: ! 2543: case TYLONG: ! 2544: cp->ci = ap->ci - bp->ci; ! 2545: break; ! 2546: case TYCOMPLEX: ! 2547: case TYDCOMPLEX: ! 2548: cp->cd[1] = ap->cd[1] - bp->cd[1]; ! 2549: case TYREAL: ! 2550: case TYDREAL: ! 2551: cp->cd[0] = ap->cd[0] - bp->cd[0]; ! 2552: break; ! 2553: } ! 2554: break; ! 2555: ! 2556: case OPSTAR: ! 2557: switch(type) ! 2558: { ! 2559: case TYSHORT: ! 2560: case TYLONG: ! 2561: cp->ci = ap->ci * bp->ci; ! 2562: break; ! 2563: case TYREAL: ! 2564: case TYDREAL: ! 2565: cp->cd[0] = ap->cd[0] * bp->cd[0]; ! 2566: break; ! 2567: case TYCOMPLEX: ! 2568: case TYDCOMPLEX: ! 2569: temp = ap->cd[0] * bp->cd[0] - ! 2570: ap->cd[1] * bp->cd[1] ; ! 2571: cp->cd[1] = ap->cd[0] * bp->cd[1] + ! 2572: ap->cd[1] * bp->cd[0] ; ! 2573: cp->cd[0] = temp; ! 2574: break; ! 2575: } ! 2576: break; ! 2577: case OPSLASH: ! 2578: switch(type) ! 2579: { ! 2580: case TYSHORT: ! 2581: case TYLONG: ! 2582: cp->ci = ap->ci / bp->ci; ! 2583: break; ! 2584: case TYREAL: ! 2585: case TYDREAL: ! 2586: cp->cd[0] = ap->cd[0] / bp->cd[0]; ! 2587: break; ! 2588: case TYCOMPLEX: ! 2589: case TYDCOMPLEX: ! 2590: zdiv(cp,ap,bp); ! 2591: break; ! 2592: } ! 2593: break; ! 2594: ! 2595: case OPMOD: ! 2596: if( ISINT(type) ) ! 2597: { ! 2598: cp->ci = ap->ci % bp->ci; ! 2599: break; ! 2600: } ! 2601: else ! 2602: fatal("inline mod of noninteger"); ! 2603: ! 2604: default: /* relational ops */ ! 2605: switch(type) ! 2606: { ! 2607: case TYSHORT: ! 2608: case TYLONG: ! 2609: if(ap->ci < bp->ci) ! 2610: k = -1; ! 2611: else if(ap->ci == bp->ci) ! 2612: k = 0; ! 2613: else k = 1; ! 2614: break; ! 2615: case TYREAL: ! 2616: case TYDREAL: ! 2617: if(ap->cd[0] < bp->cd[0]) ! 2618: k = -1; ! 2619: else if(ap->cd[0] == bp->cd[0]) ! 2620: k = 0; ! 2621: else k = 1; ! 2622: break; ! 2623: case TYCOMPLEX: ! 2624: case TYDCOMPLEX: ! 2625: if(ap->cd[0] == bp->cd[0] && ! 2626: ap->cd[1] == bp->cd[1] ) ! 2627: k = 0; ! 2628: else k = 1; ! 2629: break; ! 2630: } ! 2631: ! 2632: switch(opcode) ! 2633: { ! 2634: case OPEQ: ! 2635: cp->ci = (k == 0); ! 2636: break; ! 2637: case OPNE: ! 2638: cp->ci = (k != 0); ! 2639: break; ! 2640: case OPGT: ! 2641: cp->ci = (k == 1); ! 2642: break; ! 2643: case OPLT: ! 2644: cp->ci = (k == -1); ! 2645: break; ! 2646: case OPGE: ! 2647: cp->ci = (k >= 0); ! 2648: break; ! 2649: case OPLE: ! 2650: cp->ci = (k <= 0); ! 2651: break; ! 2652: default: ! 2653: badop ("consbinop", opcode); ! 2654: } ! 2655: break; ! 2656: } ! 2657: } ! 2658: ! 2659: ! 2660: ! 2661: ! 2662: conssgn(p) ! 2663: register expptr p; ! 2664: { ! 2665: if( ! ISCONST(p) ) ! 2666: fatal( "sgn(nonconstant)" ); ! 2667: ! 2668: switch(p->headblock.vtype) ! 2669: { ! 2670: case TYSHORT: ! 2671: case TYLONG: ! 2672: if(p->constblock.const.ci > 0) return(1); ! 2673: if(p->constblock.const.ci < 0) return(-1); ! 2674: return(0); ! 2675: ! 2676: case TYREAL: ! 2677: case TYDREAL: ! 2678: if(p->constblock.const.cd[0] > 0) return(1); ! 2679: if(p->constblock.const.cd[0] < 0) return(-1); ! 2680: return(0); ! 2681: ! 2682: case TYCOMPLEX: ! 2683: case TYDCOMPLEX: ! 2684: return(p->constblock.const.cd[0]!=0 || p->constblock.const.cd[1]!=0); ! 2685: ! 2686: default: ! 2687: badtype( "conssgn", p->constblock.vtype); ! 2688: } ! 2689: /* NOTREACHED */ ! 2690: } ! 2691: ! 2692: char *powint[ ] = { "pow_ii", "pow_ri", "pow_di", "pow_ci", "pow_zi" }; ! 2693: ! 2694: ! 2695: LOCAL expptr mkpower(p) ! 2696: register expptr p; ! 2697: { ! 2698: register expptr q, lp, rp; ! 2699: int ltype, rtype, mtype; ! 2700: ! 2701: lp = p->exprblock.leftp; ! 2702: rp = p->exprblock.rightp; ! 2703: ltype = lp->headblock.vtype; ! 2704: rtype = rp->headblock.vtype; ! 2705: ! 2706: if(ISICON(rp)) ! 2707: { ! 2708: if(rp->constblock.const.ci == 0) ! 2709: { ! 2710: frexpr(p); ! 2711: if( ISINT(ltype) ) ! 2712: return( ICON(1) ); ! 2713: else ! 2714: { ! 2715: expptr pp; ! 2716: pp = mkconv(ltype, ICON(1)); ! 2717: return( pp ); ! 2718: } ! 2719: } ! 2720: if(rp->constblock.const.ci < 0) ! 2721: { ! 2722: if( ISINT(ltype) ) ! 2723: { ! 2724: frexpr(p); ! 2725: err("integer**negative"); ! 2726: return( errnode() ); ! 2727: } ! 2728: rp->constblock.const.ci = - rp->constblock.const.ci; ! 2729: p->exprblock.leftp = lp = fixexpr(mkexpr(OPSLASH, ICON(1), lp)); ! 2730: } ! 2731: if(rp->constblock.const.ci == 1) ! 2732: { ! 2733: frexpr(rp); ! 2734: free( (charptr) p ); ! 2735: return(lp); ! 2736: } ! 2737: ! 2738: if( ONEOF(ltype, MSKINT|MSKREAL) ) ! 2739: { ! 2740: p->exprblock.vtype = ltype; ! 2741: return(p); ! 2742: } ! 2743: } ! 2744: if( ISINT(rtype) ) ! 2745: { ! 2746: if(ltype==TYSHORT && rtype==TYSHORT && (!ISCONST(lp) || tyint==TYSHORT) ) ! 2747: q = call2(TYSHORT, "pow_hh", lp, rp); ! 2748: else { ! 2749: if(ltype == TYSHORT) ! 2750: { ! 2751: ltype = TYLONG; ! 2752: lp = mkconv(TYLONG,lp); ! 2753: } ! 2754: q = call2(ltype, powint[ltype-TYLONG], lp, mkconv(TYLONG, rp)); ! 2755: } ! 2756: } ! 2757: else if( ISREAL( (mtype = maxtype(ltype,rtype)) )) ! 2758: q = call2(mtype, "pow_dd", mkconv(TYDREAL,lp), mkconv(TYDREAL,rp)); ! 2759: else { ! 2760: q = call2(TYDCOMPLEX, "pow_zz", ! 2761: mkconv(TYDCOMPLEX,lp), mkconv(TYDCOMPLEX,rp)); ! 2762: if(mtype == TYCOMPLEX) ! 2763: q = mkconv(TYCOMPLEX, q); ! 2764: } ! 2765: free( (charptr) p ); ! 2766: return(q); ! 2767: } ! 2768: ! 2769: ! 2770: ! 2771: /* Complex Division. Same code as in Runtime Library ! 2772: */ ! 2773: ! 2774: struct dcomplex { double dreal, dimag; }; ! 2775: ! 2776: ! 2777: LOCAL zdiv(c, a, b) ! 2778: register struct dcomplex *a, *b, *c; ! 2779: { ! 2780: double ratio, den; ! 2781: double abr, abi; ! 2782: ! 2783: if( (abr = b->dreal) < 0.) ! 2784: abr = - abr; ! 2785: if( (abi = b->dimag) < 0.) ! 2786: abi = - abi; ! 2787: if( abr <= abi ) ! 2788: { ! 2789: if(abi == 0) ! 2790: fatal("complex division by zero"); ! 2791: ratio = b->dreal / b->dimag ; ! 2792: den = b->dimag * (1 + ratio*ratio); ! 2793: c->dreal = (a->dreal*ratio + a->dimag) / den; ! 2794: c->dimag = (a->dimag*ratio - a->dreal) / den; ! 2795: } ! 2796: ! 2797: else ! 2798: { ! 2799: ratio = b->dimag / b->dreal ; ! 2800: den = b->dreal * (1 + ratio*ratio); ! 2801: c->dreal = (a->dreal + a->dimag*ratio) / den; ! 2802: c->dimag = (a->dimag - a->dreal*ratio) / den; ! 2803: } ! 2804: ! 2805: } ! 2806: ! 2807: expptr oftwo(e) ! 2808: expptr e; ! 2809: { ! 2810: int val,res; ! 2811: ! 2812: if (! ISCONST (e)) ! 2813: return (0); ! 2814: ! 2815: val = e->constblock.const.ci; ! 2816: switch (val) ! 2817: { ! 2818: case 2: res = 1; break; ! 2819: case 4: res = 2; break; ! 2820: case 8: res = 3; break; ! 2821: case 16: res = 4; break; ! 2822: case 32: res = 5; break; ! 2823: case 64: res = 6; break; ! 2824: case 128: res = 7; break; ! 2825: case 256: res = 8; break; ! 2826: default: return (0); ! 2827: } ! 2828: return (ICON (res)); ! 2829: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.