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