1 /****************************************************************
2 Copyright 1990, 1991 by AT&T Bell Laboratories and Bellcore.
4 Permission to use, copy, modify, and distribute this software
5 and its documentation for any purpose and without fee is hereby
6 granted, provided that the above copyright notice appear in all
7 copies and that both that the copyright notice and this
8 permission notice and warranty disclaimer appear in supporting
9 documentation, and that the names of AT&T Bell Laboratories or
10 Bellcore or any of their entities not be used in advertising or
11 publicity pertaining to distribution of the software without
12 specific, written prior permission.
14 AT&T and Bellcore disclaim all warranties with regard to this
15 software, including all implied warranties of merchantability
16 and fitness. In no event shall AT&T or Bellcore be liable for
17 any special, indirect or consequential damages or any damages
18 whatsoever resulting from loss of use, data or profits, whether
19 in an action of contract, negligence or other tortious action,
20 arising out of or in connection with the use or performance of
22 ****************************************************************/
24 /* INTERMEDIATE CODE GENERATION FOR S. C. JOHNSON C COMPILERS */
25 /* NEW VERSION USING BINARY POLISH POSTFIX INTERMEDIATE */
29 #include "output.h" /* for nice_printf */
34 LOCAL Addrp intdouble(), putcx1(), putcxeq (), putch1 ();
38 LOCAL expptr putcall (), putmnmx (), putcheq(), putcat ();
39 LOCAL expptr putaddr(), putchcmp (), putpower(), putop();
40 LOCAL expptr putcxcmp ();
47 extern int proc_argchanges, proc_protochanges;
52 /* Puthead -- output the header information about subroutines, functions
59 if (headerdone == NO) {
76 p1put(P1_ELSEIFSTART);
77 where = ftell(pass1_file);
79 if( ( k = (p = fixtype(p))->headblock.vtype) != TYLOGICAL)
82 err("non-logical expression in IF statement");
86 if (ei_next >= ei_last)
88 k = ei_last - ei_first;
91 ei_last = ei_first + n;
93 memcpy(ei_next, ei_first, k);
96 ei_last = ei_first + n;
99 if (*ei_next++ = ftell(pass1_file) > where) {
126 /* Used to make temporaries in holdtemps available here, but they */
127 /* may be reused too soon (e.g. when multiple **'s are involved). */
132 putcmgo(index, nlab, labs)
135 struct Labelblock *labs[];
137 if(! ISINT(index->headblock.vtype) )
139 execerr("computed goto index must be integer", CNULL);
143 p1comp_goto (index, nlab, labs);
150 register expptr e, e1;
151 register unsigned op;
152 int t = krparens == 2 ? TYDREAL : p->exprblock.vtype;
154 op = p->exprblock.opcode;
155 e = p->exprblock.leftp;
156 if (e->tag == TEXPR && e->exprblock.opcode == op) {
157 e1 = (expptr)mktmp(t, ENULL);
158 putout(putassign(cpexpr(e1), e));
159 p->exprblock.leftp = e1;
162 p->exprblock.leftp = putx(e);
164 e = p->exprblock.rightp;
165 if (e->tag == TEXPR && e->exprblock.opcode == op) {
166 e1 = (expptr)mktmp(t, ENULL);
167 putout(putassign(cpexpr(e1), e));
168 p->exprblock.rightp = e1;
171 p->exprblock.rightp = putx(e);
188 switch(p->constblock.vtype)
200 /* Don't write it out to the p2 file, since you'd need to call putconst,
201 which is just what we need to avoid in the translator */
205 p = putx( (expptr)putconst((Constp)p) );
211 switch(opc = p->exprblock.opcode)
215 if( ISCOMPLEX(p->exprblock.vtype) )
217 else p = putcall(p, (Addrp *)NULL);
227 if(ISCOMPLEX(p->exprblock.leftp->headblock.vtype)
228 || ISCOMPLEX(p->exprblock.rightp->headblock.vtype)) {
231 } else if( ISCHAR(p) )
239 if( ISCOMPLEX(p->exprblock.leftp->headblock.vtype) ||
240 ISCOMPLEX(p->exprblock.rightp->headblock.vtype) )
249 if(ISCHAR(p->exprblock.leftp))
261 /* m * (2**k) -> m<<k */
262 if(INT(p->exprblock.leftp->headblock.vtype) &&
263 ISICON(p->exprblock.rightp) &&
264 ( (k = log_2(p->exprblock.rightp->constblock.Const.ci))>0) )
266 p->exprblock.opcode = OPLSHIFT;
267 frexpr(p->exprblock.rightp);
268 p->exprblock.rightp = ICON(k);
271 if (krparens && ISREAL(p->exprblock.vtype))
277 if (krparens && ISREAL(p->exprblock.vtype))
285 if( ISCOMPLEX(p->exprblock.vtype) )
291 if( ISCOMPLEX(p->exprblock.vtype) )
293 else if( ISCOMPLEX(p->exprblock.leftp->headblock.vtype) )
295 p = putx( mkconv(p->exprblock.vtype,
296 (expptr)realpart(putcx1(p->exprblock.leftp))));
340 badtag("putx", p->tag);
349 LOCAL expptr putop(p)
356 switch(p->exprblock.opcode) /* check for special cases and rewrite */
359 pt = p->exprblock.vtype;
360 lp = p->exprblock.leftp;
361 lt = lp->headblock.vtype;
363 /* Simplify nested type casts */
365 while(p->tag==TEXPR && p->exprblock.opcode==OPCONV &&
366 ( (ISREAL(pt)&&ONEOF(lt,MSKREAL|MSKCOMPLEX)) ||
367 (INT(pt)&&(ONEOF(lt,MSKINT|MSKADDR|MSKCHAR|M(TYSUBR)))) ))
369 if(pt==TYDREAL && lt==TYREAL)
372 && lp->exprblock.opcode == OPCONV) {
373 lt1 = lp->exprblock.leftp->headblock.vtype;
374 if (lt1 == TYDREAL) {
375 lp->exprblock.leftp =
376 putx(lp->exprblock.leftp);
379 if (lt1 == TYDCOMPLEX) {
380 lp->exprblock.leftp = putx(
382 putcx1(lp->exprblock.leftp)));
388 else if (ISREAL(pt) && ISCOMPLEX(lt)) {
389 p->exprblock.leftp = putx(mkconv(pt,
391 putcx1(p->exprblock.leftp))));
394 if(lt==TYCHAR && lp->tag==TEXPR &&
395 lp->exprblock.opcode==OPCALL)
398 /* May want to make a comma expression here instead. I had one, but took
399 it out for my convenience, not for the convenience of the end user */
401 putout (putcall (lp, (Addrp *) &(p ->
406 p->exprblock.leftp = putx(p->exprblock.leftp);
409 frexpr(p->exprblock.vleng);
415 lp = p->exprblock.leftp;
416 lt = lp->headblock.vtype;
418 if(p->tag==TEXPR && p->exprblock.opcode==OPCONV)
425 lp = p->exprblock.leftp;
430 mktmp(lp->headblock.vtype,lp->headblock.vleng);
431 p = putx( mkexpr(OPASSIGN, cpexpr(tp), lp) );
436 p = mkexpr(OPCOMMA, p, putaddr(lp));
438 p = (expptr)putaddr(lp);
452 if( ops2[p->exprblock.opcode] <= 0)
453 badop("putop", p->exprblock.opcode);
454 p -> exprblock.leftp = putx (p -> exprblock.leftp);
455 if (p -> exprblock.rightp)
456 p -> exprblock.rightp = putx (p -> exprblock.rightp);
460 LOCAL expptr putpower(p)
467 char buf[80]; /* buffer for text of comment */
469 if(!ISICON(p->exprblock.rightp) ||
470 (k = p->exprblock.rightp->constblock.Const.ci)<2)
471 Fatal("putpower: bad call");
472 base = p->exprblock.leftp;
473 type = base->headblock.vtype;
474 t1 = mktmp(type, ENULL);
478 p = putassign (cpexpr((expptr) t1), base);
480 sprintf (buf, "Computing %ld%s power", k,
481 k == 2 ? "nd" : k == 3 ? "rd" : "th");
484 for( ; (k&1)==0 && k>2 ; k>>=1 )
486 p = mkexpr (OPCOMMA, p, putsteq(t1, t1));
491 /* Write the power computation out immediately */
493 p = putx( mkexpr(OPSTAR, cpexpr((expptr)t1), cpexpr((expptr)t1)));
495 t2 = mktmp(type, ENULL);
496 p = mkexpr (OPCOMMA, p, putassign(cpexpr((expptr)t2),
497 cpexpr((expptr)t1)));
499 for(k>>=1 ; k>1 ; k>>=1)
501 p = mkexpr (OPCOMMA, p, putsteq(t1, t1));
504 p = mkexpr (OPCOMMA, p, putsteq(t2, t1));
507 /* Write the power computation out immediately */
509 p = putx( mkexpr(OPSTAR, cpexpr((expptr)t2),
510 mkexpr(OPSTAR, cpexpr((expptr)t1), cpexpr((expptr)t1))));
521 LOCAL Addrp intdouble(p)
526 t = mktmp(TYDREAL, ENULL);
527 putout (putassign(cpexpr((expptr)t), (expptr)p));
535 /* Complex-type variable assignment */
537 LOCAL Addrp putcxeq(p)
540 register Addrp lp, rp;
544 badtag("putcxeq", p->tag);
546 lp = putcx1(p->exprblock.leftp);
547 rp = putcx1(p->exprblock.rightp);
548 code = putassign ( (expptr)realpart(lp), (expptr)realpart(rp));
550 if( ISCOMPLEX(p->exprblock.vtype) )
552 code = mkexpr (OPCOMMA, code, putassign
553 (imagpart(lp), imagpart(rp)));
563 /* putcxop -- used to write out embedded calls to complex functions, and
564 complex arguments to procedures */
569 return (expptr)putaddr((expptr)putcx1(p));
572 #define PAIR(x,y) mkexpr (OPCOMMA, (x), (y))
574 LOCAL Addrp putcx1(p)
591 if( ISCOMPLEX(p->constblock.vtype) )
592 p = (expptr) putconst((Constp)p);
596 resp = &p->addrblock;
599 if ((q = resp->memoffset) && resp->isarray
600 && resp->vtype != TYCHAR) {
601 if (ONEOF(resp->vstg, M(STGCOMMON)|M(STGEQUIV))
602 && resp->uname_tag == UNAM_NAME)
603 q = mkexpr(OPMINUS, q,
604 mkintcon(resp->user.name->voffset));
605 ts = typesize[resp->vtype]
606 * (resp->Field ? 2 : 1);
607 q = resp->memoffset = mkexpr(OPSLASH, q, ICON(ts));
611 resp = mktmp(tyint, ENULL);
612 putout(putassign(cpexpr((expptr)resp), q));
613 p->addrblock.memoffset = (expptr)resp;
615 resp = &p->addrblock;
616 q = mkexpr(OPSTAR, resp->memoffset, ICON(ts));
617 if (ONEOF(resp->vstg, M(STGCOMMON)|M(STGEQUIV))
618 && resp->uname_tag == UNAM_NAME)
619 q = mkexpr(OPPLUS, q,
620 mkintcon(resp->user.name->voffset));
626 if( ISCOMPLEX(p->exprblock.vtype) )
628 resp = mktmp(TYDREAL, ENULL);
629 putout (putassign( cpexpr((expptr)resp), p));
633 badtag("putcx1", p->tag);
636 opcode = p->exprblock.opcode;
637 if(opcode==OPCALL || opcode==OPCCALL)
644 else if(opcode == OPASSIGN)
649 /* BUG (inefficient) Generates too many temporary variables */
651 resp = mktmp(p->exprblock.vtype, ENULL);
652 if(lp = putcx1(p->exprblock.leftp) )
654 if(rp = putcx1(p->exprblock.rightp) )
660 frexpr((expptr)resp);
668 putassign( (expptr)realpart(resp),
669 mkexpr(OPNEG, (expptr)realpart(lp), ENULL)),
670 putassign( imagpart(resp),
671 mkexpr(OPNEG, imagpart(lp), ENULL))));
675 case OPMINUS: { expptr r;
676 r = putassign( (expptr)realpart(resp),
677 mkexpr(opcode, (expptr)realpart(lp), (expptr)realpart(rp) ));
678 if(rtype < TYCOMPLEX)
679 q = putassign( imagpart(resp), imagpart(lp) );
680 else if(ltype < TYCOMPLEX)
683 q = putassign( imagpart(resp), imagpart(rp) );
685 q = putassign( imagpart(resp),
686 mkexpr(OPNEG, imagpart(rp), ENULL) );
689 q = putassign( imagpart(resp),
690 mkexpr(opcode, imagpart(lp), imagpart(rp) ));
694 } /* case OPPLUS, OPMINUS: */
696 if(ltype < TYCOMPLEX)
701 putassign( (expptr)realpart(resp),
702 mkexpr(OPSTAR, cpexpr((expptr)lp),
703 (expptr)realpart(rp))),
704 putassign( imagpart(resp),
705 mkexpr(OPSTAR, cpexpr((expptr)lp), imagpart(rp)))));
707 else if(rtype < TYCOMPLEX)
712 putassign( (expptr)realpart(resp),
713 mkexpr(OPSTAR, cpexpr((expptr)rp),
714 (expptr)realpart(lp))),
715 putassign( imagpart(resp),
716 mkexpr(OPSTAR, cpexpr((expptr)rp), imagpart(lp)))));
720 putassign( (expptr)realpart(resp), mkexpr(OPMINUS,
721 mkexpr(OPSTAR, (expptr)realpart(lp),
722 (expptr)realpart(rp)),
723 mkexpr(OPSTAR, imagpart(lp), imagpart(rp)))),
724 putassign( imagpart(resp), mkexpr(OPPLUS,
725 mkexpr(OPSTAR, (expptr)realpart(lp), imagpart(rp)),
726 mkexpr(OPSTAR, imagpart(lp),
727 (expptr)realpart(rp))))));
732 /* fixexpr has already replaced all divisions
733 * by a complex by a function call
738 putassign( (expptr)realpart(resp),
739 mkexpr(OPSLASH, (expptr)realpart(lp), cpexpr((expptr)rp))),
740 putassign( imagpart(resp),
741 mkexpr(OPSLASH, imagpart(lp), cpexpr((expptr)rp)))));
745 if( ISCOMPLEX(lp->vtype) )
748 q = (expptr) realpart(rp);
750 q = mkrealcon(TYDREAL, "0");
752 putassign( (expptr)realpart(resp), (expptr)realpart(lp)),
753 putassign( imagpart(resp), q)));
757 badop("putcx1", opcode);
769 /* Only .EQ. and .NE. may be performed on COMPLEX data, other relations
772 LOCAL expptr putcxcmp(p)
776 register Addrp lp, rp;
780 badtag("putcxcmp", p->tag);
782 opcode = p->exprblock.opcode;
783 lp = putcx1(p->exprblock.leftp);
784 rp = putcx1(p->exprblock.rightp);
786 q = mkexpr( opcode==OPEQ ? OPAND : OPOR ,
787 mkexpr(opcode, (expptr)realpart(lp), (expptr)realpart(rp)),
788 mkexpr(opcode, imagpart(lp), imagpart(rp)) );
793 return putx( fixexpr((Exprp)q) );
796 /* putch1 -- Forces constants into the literal pool, among other things */
798 LOCAL Addrp putch1(p)
807 return( putconst((Constp)p) );
813 switch(p->exprblock.opcode)
825 t = mktmp(TYCHAR, ICON(lencat(p)));
826 q = (expptr) cpexpr(p->headblock.vleng);
827 p = putcat( cpexpr((expptr)t), p );
828 /* put the correct length on the block */
835 if(!ISICON(p->exprblock.vleng)
836 || p->exprblock.vleng->constblock.Const.ci!=1
837 || ! INT(p->exprblock.leftp->headblock.vtype) )
838 Fatal("putch1: bad character conversion");
839 t = mktmp(TYCHAR, ICON(1));
840 e = mkexpr(OPCONV, (expptr)t, ENULL);
841 e->headblock.vtype = tyint;
842 p = putop( mkexpr(OPASSIGN, cpexpr(e), p));
846 badop("putch1", p->exprblock.opcode);
851 badtag("putch1", p->tag);
853 /* NOT REACHED */ return 0;
857 /* putchop -- Write out a character actual parameter; that is, this is
858 part of a procedure invocation */
863 p = putaddr((expptr)putch1(p));
870 LOCAL expptr putcheq(p)
876 badtag("putcheq", p->tag);
878 lp = p->exprblock.leftp;
879 rp = p->exprblock.rightp;
880 frexpr(p->exprblock.vleng);
883 /* If s = t // u, don't bother copying the result, write it directly into
886 if( rp->tag==TEXPR && rp->exprblock.opcode==OPCONCAT )
888 else if( ISONE(lp->headblock.vleng) && ISONE(rp->headblock.vleng) ) {
889 lp = mkexpr(OPCONV, lp, ENULL);
890 rp = mkexpr(OPCONV, rp, ENULL);
891 lp->headblock.vtype = rp->headblock.vtype = tyint;
892 p = putop(mkexpr(OPASSIGN, lp, rp));
895 p = putx( call2(TYSUBR, "s_copy", lp, rp) );
902 LOCAL expptr putchcmp(p)
908 badtag("putchcmp", p->tag);
910 lp = p->exprblock.leftp;
911 rp = p->exprblock.rightp;
913 if(ISONE(lp->headblock.vleng) && ISONE(rp->headblock.vleng) ) {
914 lp = mkexpr(OPCONV, lp, ENULL);
915 rp = mkexpr(OPCONV, rp, ENULL);
916 lp->headblock.vtype = rp->headblock.vtype = tyint;
919 lp = call2(TYINT,"s_cmp", lp, rp);
922 p->exprblock.leftp = lp;
923 p->exprblock.rightp = rp;
932 /* putcat -- Writes out a concatenation operation. Two temporary arrays
933 are allocated, putct1() is called to initialize them, and then a
934 call to runtime library routine s_cat() is inserted.
936 This routine generates code which will perform an (nconc lhs rhs)
937 at runtime. The runtime funciton does not return a value, the routine
938 that calls this putcat must remember the name of lhs.
942 LOCAL expptr putcat(lhs0, rhs)
946 register Addrp lhs = (Addrp)lhs0;
948 Addrp length_var, string_var;
950 static char Writing_concatenation[] = "Writing concatenation";
952 /* Create the temporary arrays */
955 length_var = mktmpn(n, tyioint, ENULL);
956 string_var = mktmpn(n, TYADDR, ENULL);
957 frtemp((Addrp)cpexpr((expptr)length_var));
958 frtemp((Addrp)cpexpr((expptr)string_var));
960 /* Initialize the arrays */
963 /* p1_comment scribbles on its argument, so we
964 * cannot safely pass a string literal here. */
965 p1_comment(Writing_concatenation);
966 putct1(rhs, length_var, string_var, &n);
968 /* Create the invocation */
971 tyint = tyioint; /* for -I2 */
972 p = putx (call4 (TYSUBR, "s_cat",
976 (expptr)putconst((Constp)ICON(n))));
986 LOCAL putct1(q, length_var, string_var, ip)
988 register Addrp length_var, string_var;
992 Addrp length_copy, string_copy;
996 if(q->tag==TEXPR && q->exprblock.opcode==OPCONCAT)
998 putct1(q->exprblock.leftp, length_var, string_var,
1000 putct1(q->exprblock.rightp, length_var, string_var,
1002 frexpr (q -> exprblock.vleng);
1008 length_copy = (Addrp) cpexpr((expptr)length_var);
1009 length_copy->memoffset =
1010 mkexpr(OPPLUS,length_copy->memoffset, ICON(i*szleng));
1011 string_copy = (Addrp) cpexpr((expptr)string_var);
1012 string_copy->memoffset =
1013 mkexpr(OPPLUS, string_copy->memoffset,
1014 ICON(i*typesize[TYLONG]));
1015 e = cpexpr(q->headblock.vleng);
1016 putout (PAIR (putassign((expptr)length_copy, e),
1017 putassign((expptr)string_copy, addrof((expptr)putch1(q)))));
1021 /* putaddr -- seems to write out function invocation actual parameters */
1023 LOCAL expptr putaddr(p0)
1028 if (!(p = (Addrp)p0))
1031 if( p->tag==TERROR || (p->memoffset!=NULL && ISERROR(p->memoffset)) )
1036 if (p->isarray && p->memoffset)
1037 p->memoffset = putx(p->memoffset);
1042 addrfix(e) /* fudge character string length if it's a TADDR */
1045 return e->tag == TADDR ? mkexpr(OPIDENTITY, e, ENULL) : e;
1049 typekludge(ccall, q, at, j)
1053 int j; /* alternate type */
1056 extern int iocalladdr;
1059 /* Return value classes:
1060 * < 100 ==> Fortran arg (pointer to type)
1062 * < 300 ==> procedure arg
1063 * < 400 ==> external, no explicit type
1064 * < 500 ==> arg that may turn out to be
1065 * either a variable or a procedure
1068 k = q->headblock.vtype;
1071 k = TYDREAL; /* force double for library routines */
1077 if ((i == TEXPR && q->exprblock.opcode != OPCOMMA_ARG)
1078 || (i == TADDR && q->addrblock.charleng)
1081 else if (i == TADDR)
1082 switch(q->addrblock.vclass) {
1084 if (q->addrblock.uname_tag != UNAM_NAME)
1086 else if ((np = q->addrblock.user.name)->vprocclass
1088 if (k && !np->vimpltype)
1091 if (j > 200 && infertypes && j < 300) {
1093 inferdcl(np, j-200);
1095 else k = (np->vstg == STGEXT
1096 ? extsymtab[np->vardesc.varno].extype
1098 at->cp = mkchain((char *)np, at->cp);
1101 else if (k == TYSUBR)
1106 if (q->addrblock.vstg == STGARG
1107 && q->addrblock.uname_tag == UNAM_NAME) {
1109 at->cp = mkchain((char *)q->addrblock.user.name,
1113 else if (i == TNAME && q->nameblock.vstg == STGARG) {
1115 switch(np->vclass) {
1119 else if (j <= 200 || !infertypes || j >= 300)
1123 inferdcl(np, j-200);
1128 /* argument may be a scalar variable or a function */
1129 if (np->vimpltype && j && infertypes
1131 inferdcl(np, j % 100);
1137 /* to handle procedure args only so far known to be
1138 * external, save a pointer to the symbol table entry...
1141 at->cp = mkchain((char *)np, at->cp);
1153 sprintf(buf, "%s variable", ftn_types[k]);
1158 return ftn_types[k];
1163 return ftn_types[TYSUBR];
1164 sprintf(buf, "%s function", ftn_types[k]);
1168 return "external argument";
1170 sprintf(buf, "%s argument", ftn_types[k]);
1175 atype_squawk(at, msg)
1179 register Atype *a, *ae;
1181 for(a = at->atypes, ae = a + at->nargs; a < ae; a++)
1184 if (at->changes & 2)
1185 proc_protochanges++;
1188 static char inconsist[] = "inconsistent calling sequences for ";
1191 bad_atypes(at, fname, i, j, k, here, prev)
1193 char *fname, *here, *prev;
1196 char buf[208], buf1[32], buf2[32];
1198 sprintf(buf, "%s%.90s,\n\targ %d: %s%s%s %s.",
1199 inconsist, fname, i, here, Argtype(k, buf1),
1200 prev, Argtype(j, buf2));
1201 atype_squawk(at, buf);
1210 register struct Entrypoint *ep;
1213 for(ep = entries; ep; ep = ep->entnextp)
1214 if (at == ep->entryname->arginfo) {
1216 return proc_argchanges = 1;
1223 save_argtypes(arglist, at0, at1, ccall, fname, stg, nchargs, type, zap)
1225 Argtypes **at0, **at1;
1226 int ccall, stg, nchargs, type, zap;
1231 int i, i0, j, k, nargs, *t, *te;
1235 static int initargs[4] = {TYCOMPLEX, TYDCOMPLEX, TYCHAR, TYFTNLEN+100};
1236 static int *init_ap[TYSUBR+1] = {0,0,0,0,0,0,
1237 initargs, initargs+1,0,initargs+2};
1238 extern int init_ac[TYSUBR+1];
1246 if (nargs < 0) { /* inconsistent usage seen */
1248 if (at->changes & 2)
1249 --proc_protochanges;
1254 atypes = at->atypes;
1256 for(; t < te; atypes++) {
1260 for(cp = arglist; cp; cp = cp->nextp)
1264 "%s%.90s:\n\there %d, previously %d args and string lengths.",
1265 inconsist, fname, i, nargs);
1266 atype_squawk(at, buf);
1277 for(cp = arglist; cp; atypes++, cp = cp->nextp) {
1281 if (!(q = (expptr)cp->datap))
1283 k = typekludge(ccall, q, atypes, j);
1284 if (k >= 300 || k == j)
1288 if (k == TYUNKNOWN + 200)
1290 if (j % 100 != k - 200
1291 && k != TYSUBR + 200
1292 && j != TYUNKNOWN + 300
1293 && !type_fixup(at,atypes,k))
1296 else if (j % 100 % TYSUBR != k % TYSUBR
1297 && !type_fixup(at,atypes,k))
1300 else if (k < 200 || j < 200)
1303 else ; /* fall through to update */
1304 else if (k == TYUNKNOWN+200)
1306 else if (j != TYUNKNOWN+200)
1309 bad_atypes(at, fname, i, j, k, "here ",
1312 /* we're defining the procedure */
1315 proc_argchanges = 1;
1320 /* We've subsequently learned the right type,
1321 as in the call on zoo below...
1323 subroutine foo(x, zap)
1335 if (zap && (at->changes & 5) != 5)
1341 for(cp = arglist; cp; cp = cp->nextp)
1343 k = sizeof(Argtypes) + (i-1)*sizeof(Atype);
1344 *at0 = *at1 = at = stg == STGEXT ? (Argtypes *)gmem(k,1)
1345 : (Argtypes *) mem(k,1);
1347 at->changes = type ? 0 : 4;
1348 atypes = at->atypes;
1349 for(; t < te; atypes++) {
1350 atypes->type = *t++;
1353 for(cp = arglist; cp; atypes++, cp = cp->nextp) {
1355 atypes->type = (q = (expptr)cp->datap)
1356 ? typekludge(ccall, q, atypes, 0)
1359 for(; --nchargs >= 0; atypes++) {
1360 atypes->type = TYFTNLEN + 100;
1366 saveargtypes(p) /* for writing prototypes */
1370 Argtypes **at0, **at1;
1377 a = (Addrp)p->leftp;
1380 switch(a->uname_tag) {
1381 case UNAM_EXTERN: /* e.g., sqrt() */
1382 e = extsymtab + a->memno;
1383 at0 = at1 = &e->arginfo;
1384 fname = e->fextname;
1388 at0 = &extsymtab[np->vardesc.varno].arginfo;
1390 fname = np->fvarname;
1397 if (a->uname_tag != UNAM_NAME)
1400 at0 = at1 = &np->arginfo;
1401 fname = np->fvarname;
1405 Fatal("Confusion in saveargtypes");
1408 arglist = rp && rp->tag == TLIST ? rp->listblock.listp : 0;
1409 save_argtypes(arglist, at0, at1, p->opcode == OPCCALL,
1410 fname, a->vstg, 0, 0, 0);
1413 /* putcall - fix up the argument list, and write out the invocation. p
1414 is expected to be initialized and point to an OPCALL or OPCCALL
1415 expression. The return value is a pointer to a temporary holding the
1416 result of a COMPLEX or CHARACTER operation, or NULL. */
1418 LOCAL expptr putcall(p0, temp)
1422 register Exprp p = (Exprp)p0;
1423 chainp arglist; /* Pointer to actual arguments, if any */
1424 chainp charsp; /* List of copies of the variables which
1425 hold the lengths of character
1426 parameters (other than procedure
1428 chainp cp; /* Iterator over argument lists */
1429 register expptr q; /* Pointer to the current argument */
1430 Addrp fval; /* Function return value */
1431 int type; /* type of the call - presumably this was
1433 int byvalue; /* True iff we don't want to massage the
1434 parameter list, since we're calling a C
1436 extern int Castargs;
1438 extern struct Listblock *mklist();
1442 byvalue = (p->opcode == OPCCALL);
1444 /* Verify the actual parameters */
1446 if (p == (Exprp) NULL)
1447 err ("putcall: NULL call expression");
1448 else if (p -> tag != TEXPR)
1449 erri ("putcall: expected TEXPR, got '%d'", p -> tag);
1451 /* Find the argument list */
1453 if(p->rightp && p -> rightp -> tag == TLIST)
1454 arglist = p->rightp->listblock.listp;
1458 /* Count the number of explicit arguments, including lengths of character
1461 for(cp = arglist ; cp ; cp = cp->nextp)
1463 q = (expptr) cp->datap;
1467 /* Even constants are passed by reference, so we need to put them in the
1470 q = (expptr) putconst((Constp)q);
1471 cp->datap = (char *) q;
1474 /* Save the length expression of character variables (NOT character
1475 procedures) for the end of the argument list */
1478 (q->headblock.vclass != CLPROC
1479 || q->headblock.vstg == STGARG
1481 && q->addrblock.uname_tag == UNAM_NAME
1482 && q->addrblock.user.name->vprocclass == PTHISPROC))
1484 p0 = cpexpr(q->headblock.vleng);
1485 charsp = mkchain((char *)p0, charsp);
1486 if (q->headblock.vclass == CLUNKNOWN
1487 && q->headblock.vstg == STGARG)
1488 q->addrblock.user.name->vpassed = 1;
1489 else if (q->tag == TADDR
1490 && q->addrblock.uname_tag == UNAM_CONST)
1491 p0->constblock.Const.ci
1492 += q->addrblock.user.Const.ccp1.blanks;
1495 charsp = revchain(charsp);
1497 /* If the routine is a CHARACTER function ... */
1501 if( ISICON(p->vleng) )
1504 /* Allocate a temporary to hold the return value of the function */
1506 fval = mktmp(TYCHAR, p->vleng);
1509 err("adjustable character function");
1516 /* If the routine is a COMPLEX function ... */
1518 else if( ISCOMPLEX(type) )
1519 fval = mktmp(type, ENULL);
1523 /* Write the function name, without taking its address */
1525 p -> leftp = putx(fixtype(putaddr(p->leftp)));
1531 /* Prepend a copy of the function return value buffer out as the first
1534 prepend = mkchain((char *)putx(putaddr(cpexpr((expptr)fval))), arglist);
1536 /* If it's a character function, also prepend the length of the result */
1541 prepend->nextp = mkchain((char *)putx(mkconv(TYLENG,
1542 p->vleng)), arglist);
1544 if (!(q = p->rightp))
1545 p->rightp = q = (expptr)mklist(CHNULL);
1546 q->listblock.listp = prepend;
1549 /* Scan through the fortran argument list */
1551 for(cp = arglist ; cp ; cp = cp->nextp)
1553 q = (expptr) (cp->datap);
1555 err ("putcall: NULL argument");
1557 /* call putaddr only when we've got a parameter for a C routine or a
1558 memory resident parameter */
1560 if (q -> tag == TCONST && !byvalue)
1561 q = (expptr) putconst ((Constp)q);
1563 if(q->tag==TADDR && (byvalue || q->addrblock.vstg!=STGREG) )
1564 cp->datap = (char *)putaddr(q);
1565 else if( ISCOMPLEX(q->headblock.vtype) )
1566 cp -> datap = (char *) putx (fixtype(putcxop(q)));
1567 else if (ISCHAR(q) )
1568 cp -> datap = (char *) putx (fixtype((expptr)putchop(q)));
1569 else if( ! ISERROR(q) )
1572 || q->tag == TEXPR && q->exprblock.opcode == OPCHARCAST)
1573 cp -> datap = (char *) putx(q);
1577 /* If we've got a register parameter, or (maybe?) a constant, save it in a
1580 t = (expptr) mktmp(q->headblock.vtype, q->headblock.vleng);
1582 /* Assign to temporary variables before invoking the subroutine or
1585 t1 = putassign( cpexpr(t), q );
1587 t = mkexpr(OPCOMMA_ARG, t1, t);
1590 cp -> datap = (char *) t;
1592 } /* if !ISERROR(q) */
1595 /* Now adjust the lengths of the CHARACTER parameters */
1597 for(cp = charsp ; cp ; cp = cp->nextp)
1598 cp->datap = (char *)addrfix(putx(
1599 /* in case MAIN has a character*(*)... */
1600 (s = cp->datap) ? mkconv(TYLENG,(expptr)s)
1603 /* ... and add them to the end of the argument list */
1605 hookup (arglist, charsp);
1607 /* Return the name of the temporary used to hold the results, if any was
1610 if (temp) *temp = fval;
1611 else frexpr ((expptr)fval);
1620 /* putmnmx -- Put min or max. p must point to an EXPR, not just a
1623 LOCAL expptr putmnmx(p)
1627 expptr arg, qp, temp;
1630 char comment_buf[80];
1634 badtag("putmnmx", p->tag);
1636 type = p->exprblock.vtype;
1637 op = p->exprblock.opcode;
1638 op2 = op == OPMIN ? OPMIN2 : OPMAX2;
1639 p0 = p->exprblock.leftp->listblock.listp;
1640 free( (charptr) (p->exprblock.leftp) );
1641 free( (charptr) p );
1643 /* special case for two addressable operands */
1645 if (addressable((expptr)p0->datap)
1647 && addressable((expptr)p1->datap)
1649 if (type == TYREAL && forcedouble)
1650 op2 = op == OPMIN ? OPDMIN : OPDMAX;
1651 p = mkexpr(op2, mkconv(type, cpexpr((expptr)p0->datap)),
1652 mkconv(type, cpexpr((expptr)p1->datap)));
1659 sp = mktmp(type, ENULL);
1661 /* We only need a second temporary if the arg list has an unaddressable
1666 for (p1 = p0 -> nextp; p1; p1 = p1 -> nextp)
1667 if (!addressable ((expptr) p1 -> datap)) {
1668 tp = mktmp(type, ENULL);
1669 qp = mkexpr(op2, cpexpr((expptr)sp), cpexpr((expptr)tp));
1670 qp = fixexpr((Exprp)qp);
1674 /* Now output the appropriate number of assignments and comparisons. Min
1675 and max are implemented by the simple O(n) algorithm:
1677 min (a, b, c, d) ==>
1681 t2 = b; t1 = (t1 < t2) ? t1 : t2;
1682 t2 = c; t1 = (t1 < t2) ? t1 : t2;
1683 t2 = d; t1 = (t1 < t2) ? t1 : t2;
1687 if (!doin_setbound) {
1698 sprintf (comment_buf, "Computing M%s", what);
1699 p1_comment (comment_buf);
1703 temp = (expptr)p0->datap;
1704 if (addressable(temp) && addressable((expptr)p1->datap)) {
1705 p = mkconv(type, cpexpr(temp));
1706 arg = mkconv(type, cpexpr((expptr)p1->datap));
1707 temp = mkexpr(op2, p, arg);
1709 temp = fixexpr((Exprp)temp);
1712 p = putassign (cpexpr((expptr)sp), temp);
1714 for(; p1 ; p1 = p1->nextp)
1716 if (addressable ((expptr) p1 -> datap)) {
1717 arg = mkconv(type, cpexpr((expptr)p1->datap));
1718 temp = mkexpr(op2, cpexpr((expptr)sp), arg);
1719 temp = fixexpr((Exprp)temp);
1721 temp = (expptr) cpexpr (qp);
1722 p = mkexpr(OPCOMMA, p,
1723 putassign(cpexpr((expptr)tp), (expptr)p1->datap));
1727 p = mkexpr(OPCOMMA, p,
1728 putassign(cpexpr((expptr)sp), temp));
1730 if (type == TYREAL && forcedouble)
1731 temp->exprblock.opcode =
1732 op == OPMIN ? OPDMIN : OPDMAX;
1734 p = mkexpr(OPCOMMA, p, temp);
1756 if (wh_next >= wh_last)
1758 k = wh_last - wh_first;
1761 wh_last = wh_first + n;
1763 memcpy(wh_next, wh_first, k);
1766 wh_last = wh_first + n;
1768 if( ( k = (p = fixtype(p))->headblock.vtype) != TYLOGICAL)
1771 err("non-logical expression in DO WHILE statement");
1774 p1put(P1_WHILE1START);
1775 where = ftell(pass1_file);
1777 *wh_next++ = ftell(pass1_file) > where;
1778 p1put(P1_WHILE2START);