1 /****************************************************************
2 Copyright 1990 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 ****************************************************************/
28 LOCAL void exar2(), popctl(), pushctl();
38 putif(p, 0); /* 0 => if, not elseif */
46 if (ctlstack->ctltype == CTLIF || ctlstack->ctltype == CTLIFX)
47 putif(p, 1); /* 1 ==> elseif */
49 execerr("elseif out of place", CNULL);
58 register struct Ctlframe *c;
60 for(c = ctlstack; c->ctltype == CTLIFX; --c);
61 if(c->ctltype == CTLIF) {
66 execerr("else out of place", CNULL);
72 while(ctlstack->ctltype == CTLIFX) {
76 if(ctlstack->ctltype == CTLIF) {
80 else if(ctlstack->ctltype == CTLELSE) {
85 execerr("endif out of place", CNULL);
91 if (ctlstack->ctltype == CTLIF || ctlstack->ctltype == CTLIFX)
97 /* pushctl -- Start a new control construct, initialize the labels (to
106 if(++ctlstack >= lastctl)
107 many("loops or if-then-elses", 'c', maxctl);
108 ctlstack->ctltype = code;
109 for(i = 0 ; i < 4 ; ++i)
110 ctlstack->ctlabels[i] = 0;
111 ctlstack->dowhile = 0;
119 if( ctlstack-- < ctls )
120 Fatal("control stack empty");
126 /* poplab -- update the flags in labeltab */
130 register struct Labelblock *lp;
132 for(lp = labeltab ; lp < highlabtab ; ++lp)
135 /* mark all labels in inner blocks unreachable */
136 if(lp->blklevel > blklevel)
139 else if(lp->blklevel > blklevel)
141 /* move all labels referred to in inner blocks out a level */
142 lp->blklevel = blklevel;
151 struct Labelblock *lab;
154 p1_goto (lab -> stateno);
164 register struct Primblock *lp;
169 err("assignment to a non-variable");
173 else if(lp->namep->vclass!=CLVAR && lp->argsp)
175 if(parstate >= INEXEC)
176 err("statement function amid executables");
181 expptr new_lp, new_rp;
183 if(parstate < INDATA)
186 new_rp = fixtype (rp);
187 puteq(new_lp, new_rp);
193 /* Make Statement Function */
195 long laststfcn = -1, thisstno;
199 struct Primblock *lp;
202 register struct Primblock *p;
206 laststfcn = thisstno;
208 if(np->vclass == CLUNKNOWN)
212 dclerr("redeclaration of statement function", np);
215 np->vprocclass = PSTFUNCT;
216 np->vstg = STGSTFUNCT;
218 /* Set the type of the function */
221 if (np->vtype == TYCHAR && !np->vleng)
222 err("character statement function with length (*)");
223 args = (lp->argsp ? lp->argsp->listp : CHNULL);
224 np->varxptr.vstfdesc = mkchain((char *)args, (chainp)rp);
226 for(doing_stmtfcn = 1 ; args ; args = args->nextp)
228 /* It is an error for the formal parameters to have arguments or
231 if( ((tagptr)(args->datap))->tag!=TPRIM ||
232 (p = (struct Primblock *)(args->datap) )->argsp ||
233 p->fcharp || p->lcharp )
234 err("non-variable argument in statement function definition");
238 /* Replace the name on the left-hand side */
240 args->datap = (char *)p->namep;
252 sprintf(buf, "%s function %.90s invoked as subroutine",
253 ftn_types[np->vtype], np->fvarname);
258 excall(name, args, nstars, labels)
260 struct Listblock *args;
262 struct Labelblock *labels[ ];
266 if (name->vtype != TYSUBR) {
267 if (name->vinfproc && !name->vcalled) {
268 name->vtype = TYSUBR;
272 else if (!name->vimpltype && name->vtype != TYUNKNOWN)
275 settype(name, TYSUBR, (ftnint)0);
277 p = mkfunct( mkprim(name, args, CHNULL) );
279 /* Subroutines and their identifiers acquire the type INT */
281 p->exprblock.vtype = p->exprblock.leftp->headblock.vtype = TYINT;
283 /* Handle the alternate return mechanism */
286 putcmgo(putx(fixtype(p)), nstars, labels);
305 execerr("pause/stop argument must be constant", CNULL);
307 p = mkstrcon(0, CNULL);
309 else if( ISINT(p->constblock.vtype) )
311 str = convic(p->constblock.Const.ci);
315 p->constblock.Const.ccp = copyn(n, str);
316 p->constblock.Const.ccp1.blanks = 0;
317 p->constblock.vtype = TYCHAR;
318 p->constblock.vleng = (expptr) ICON(n);
321 p = (expptr) mkstrcon(0, CNULL);
323 else if(p->constblock.vtype != TYCHAR)
325 execerr("pause/stop argument must be integer or string", CNULL);
326 p = (expptr) mkstrcon(0, CNULL);
329 else p = (expptr) mkstrcon(0, CNULL);
334 subr_call = call1(TYSUBR, (stop ? "s_stop" : "s_paus"), p);
335 putexpr( subr_call );
341 #define DOINIT par[0]
342 #define DOLIMIT par[1]
343 #define DOINCR par[2]
346 /* Macros for ctlstack -> dostepsign */
353 /* exdo -- generate DO loop code. In the case of a variable increment,
354 positive increment tests are placed above the body, negative increment
355 tests are placed below (see enddo() ) */
357 exdo(range, loopname, spec)
358 int range; /* end label */
360 chainp spec; /* input spec must have at least 2 exprs */
364 chainp cp; /* loops over the fields in spec */
366 int dotype; /* type of the index variable */
367 int incsign; /* sign of the increment, if it's constant
369 Addrp dovarp; /* loop index variable */
370 expptr doinit; /* constant or register for init param */
371 expptr par[3]; /* local specification parameters */
373 expptr init, test, inc; /* Expressions in the resulting FOR loop */
379 dorange = ctlstack->dolabel = range;
380 ctlstack->loopname = loopname;
382 /* Declare the loop index */
384 np = (Namep)spec->datap;
385 ctlstack->donamep = NULL;
386 if (!np) { /* do while */
387 ctlstack->dowhile = 1;
390 if (loopname->vtype == TYUNKNOWN) {
391 loopname->vdcldone = 1;
392 loopname->vclass = CLLABEL;
393 loopname->vprocclass = PLABEL;
394 loopname->vtype = TYLABEL;
396 if (loopname->vtype == TYLABEL)
397 if (loopname->vdovar)
398 dclerr("already in use as a loop name",
401 loopname->vdovar = 1;
403 dclerr("already declared; cannot be a loop name",
407 putwhile((expptr)spec->nextp);
415 errstr("nested loops with variable %s", np->fvarname);
416 ctlstack->donamep = NULL;
420 /* Create a memory-resident version of the index variable */
422 dovarp = mkplace(np);
423 if( ! ONEOF(dovarp->vtype, MSKINT|MSKREAL) )
425 err("bad type on do variable");
428 ctlstack->donamep = np;
432 /* Now dovarp points to the index to be used within the loop, dostgp
433 points to the one which may need to be stored */
435 dotype = dovarp->vtype;
437 /* Count the input specifications and type-check each one independently;
438 this just eliminates non-numeric values from the specification */
440 for(i=0 , cp = spec->nextp ; cp!=NULL && i<3 ; cp = cp->nextp)
442 p = par[i++] = fixtype((tagptr)cp->datap);
443 if( ! ONEOF(p->headblock.vtype, MSKINT|MSKREAL) )
445 err("bad type on DO parameter");
455 err("too few DO parameters");
459 err("too many DO parameters");
463 DOINCR = (expptr) ICON(1);
470 /* Now all of the local specification fields are set, but their types are
471 not yet consistent */
473 /* Declare the loop initialization value, casting it properly and declaring a
474 register if need be */
476 if (ISCONST (DOINIT) || !onetripflag)
477 /* putx added 6-29-89 (mwm), not sure if fixtype is required, but I doubt it
478 since mkconv is called just before */
479 doinit = putx (mkconv (dotype, DOINIT));
481 doinit = (expptr) mktmp(dotype, ENULL);
482 puteq (cpexpr (doinit), DOINIT);
485 /* Declare the loop ending value, casting it to the type of the index
488 if( ISCONST(DOLIMIT) )
489 ctlstack->domax = mkconv(dotype, DOLIMIT);
491 ctlstack->domax = (expptr) mktmp0(dotype, ENULL);
492 puteq (cpexpr (ctlstack -> domax), DOLIMIT);
495 /* Declare the loop increment value, casting it to the type of the index
498 if( ISCONST(DOINCR) )
500 ctlstack->dostep = mkconv(dotype, DOINCR);
501 if( (incsign = conssgn(ctlstack->dostep)) == 0)
502 err("zero DO increment");
503 ctlstack->dostepsign = (incsign > 0 ? POSSTEP : NEGSTEP);
507 ctlstack->dostep = (expptr) mktmp0(dotype, ENULL);
508 ctlstack->dostepsign = VARSTEP;
509 puteq (cpexpr (ctlstack -> dostep), DOINCR);
512 /* All data is now properly typed and in the ctlstack, except for the
513 initial value. Assignments of temps have been generated already */
515 switch (ctlstack -> dostepsign) {
517 test = mkexpr (OPQUEST, mkexpr (OPLT,
518 cpexpr (ctlstack -> dostep), ICON(0)),
520 mkexpr (OPGE, cpexpr((expptr)dovarp),
521 cpexpr (ctlstack -> domax)),
522 mkexpr (OPLE, cpexpr((expptr)dovarp),
523 cpexpr (ctlstack -> domax))));
526 test = mkexpr (OPLE, cpexpr((expptr)dovarp),
527 cpexpr (ctlstack -> domax));
530 test = mkexpr (OPGE, cpexpr((expptr)dovarp),
531 cpexpr (ctlstack -> domax));
534 erri ("exdo: bad dostepsign '%d'", ctlstack -> dostepsign);
536 } /* switch (ctlstack -> dostepsign) */
539 test = mkexpr (OPOR, test,
540 mkexpr (OPEQ, cpexpr((expptr)dovarp), cpexpr (doinit)));
541 init = mkexpr (OPASSIGN, cpexpr((expptr)dovarp), doinit);
542 inc = mkexpr (OPPLUSEQ, (expptr)dovarp, cpexpr (ctlstack -> dostep));
544 if (!onetripflag && ISCONST (ctlstack -> domax) && ISCONST (doinit)
545 && ctlstack -> dostepsign != VARSTEP) {
548 tester = mkexpr (OPMINUS, cpexpr (doinit),
549 cpexpr (ctlstack -> domax));
550 if (incsign == conssgn (tester))
551 warn ("DO range never executed");
553 } /* if !onetripflag && */
555 p1_for (init, test, inc);
565 if( ctlstack < ctls )
566 Fatal("control stack empty");
567 here = ctlstack->dolabel;
568 if (ctlstack->ctltype != CTLDO || here >= 0) {
569 err("misplaced ENDDO");
572 if (np != ctlstack->loopname) {
573 if (np1 = ctlstack->loopname)
574 errstr("expected \"enddo %s\"", np1->fvarname);
576 err("expected unnamed ENDDO");
577 for(cf = ctls; cf < ctlstack; cf++)
578 if (cf->ctltype == CTLDO && cf->loopname == np) {
590 register struct Ctlframe *q;
591 Namep np; /* name of the current DO index */
596 /* Many DO's can end at the same statement, so keep looping over all
599 while(here == dorange)
601 if(np = ctlstack->donamep)
605 /* Now we're done with all of the tests, and the loop has terminated.
606 Store the index value back in long-term memory */
608 if(ap = memversion(np))
609 puteq((expptr)ap, (expptr)mkplace(np));
610 for(i = 0 ; i < 4 ; ++i)
611 ctlstack->ctlabels[i] = 0;
612 deregister(ctlstack->donamep);
613 ctlstack->donamep->vdovar = NO;
614 e = ctlstack->dostep;
615 if (e->tag == TADDR && e->addrblock.istemp)
620 if (e->tag == TADDR && e->addrblock.istemp)
625 else if (ctlstack->dowhile)
628 /* Set dorange to the closing label of the next most enclosing DO loop
634 for(q = ctlstack ; q>=ctls ; --q)
635 if(q->ctltype == CTLDO)
637 dorange = q->dolabel;
643 exassign(vname, labelval)
644 register Namep vname;
645 struct Labelblock *labelval;
650 static char nullstr[] = "";
652 register chainp cp, cpprev;
653 register ftnint k, stno;
656 if( ! ONEOF(p->vtype, MSKINT|MSKADDR) ) {
657 err("noninteger assign variable");
661 /* If the label hasn't been defined, then we do things twice:
662 * once for an executable stmt label, once for a format
665 /* code for executable label... */
667 /* Now store the assigned value in a list associated with this variable.
668 This will be used later to generate a switch() statement in the C output */
670 if (!labelval->labdefined || !labelval->fmtstring) {
672 if (vname -> vis_assigned == 0) {
673 vname -> varxptr.assigned_values = CHNULL;
674 vname -> vis_assigned = 1;
677 /* don't duplicate labels... */
679 stno = labelval->stateno;
681 for(k = 0, cp = vname->varxptr.assigned_values;
682 cp; cpprev = cp, cp = cp->nextp, k++)
683 if ((ftnint)cp->datap == stno)
686 cp = mkchain((char *)stno, CHNULL);
690 vname->varxptr.assigned_values = cp;
691 labelval->labused = 1;
693 putout(mkexpr(OPASSIGN, (expptr)p, mkintcon(k)));
696 /* Code for FORMAT label... */
698 fs = labelval->fmtstring;
699 if (!labelval->labdefined || fs && fs != nullstr) {
700 extern void fmtname();
703 labelval->fmtstring = nullstr;
704 labelval->fmtlabused = 1;
705 p = ALLOC(Addrblock);
709 p->memoffset = ICON(0);
711 q = ALLOC(Addrblock);
716 q->memoffset = ICON(0);
717 q->uname_tag = UNAM_IDENT;
718 sprintf(q->user.ident, "fmt_%ld", labelval->stateno);
719 putout(mkexpr(OPASSIGN, (expptr)p, (expptr)q));
726 exarif(expr, neglab, zerlab, poslab)
728 struct Labelblock *neglab, *zerlab, *poslab;
730 register int lm, lz, lp;
732 lm = neglab->stateno;
733 lz = zerlab->stateno;
734 lp = poslab->stateno;
735 expr = fixtype(expr);
737 if( ! ONEOF(expr->headblock.vtype, MSKINT|MSKREAL) )
739 err("invalid type of arithmetic if expression");
744 if (lm == lz && lz == lp)
747 exar2(OPLE, expr, neglab, poslab);
749 exar2(OPNE, expr, neglab, zerlab);
751 exar2(OPGE, expr, zerlab, neglab);
755 if (!addressable (expr)) {
756 t = (expptr) mktmp(expr -> headblock.vtype, ENULL);
757 expr = mkexpr (OPASSIGN, cpexpr (t), expr);
759 t = (expptr) cpexpr (expr);
761 p1_if(putx(fixtype(mkexpr (OPLT, expr, ICON (0)))));
763 p1_elif (mkexpr (OPEQ, t, ICON (0)));
774 /* exar2 -- Do arithmetic IF for only 2 distinct labels; if !(e.op.0)
775 goto l2 else goto l1. If this seems backwards, that's because it is,
776 in order to make the 1 pass algorithm work. */
782 struct Labelblock *l1, *l2;
786 comp = mkexpr (op, e, ICON (0));
787 p1_if(putx(fixtype(comp)));
795 /* exreturn -- return the value in p from a SUBROUTINE call -- used to
796 implement the alternate return mechanism */
801 if(procclass != CLPROC)
802 warn("RETURN statement in main or block data");
803 if(p && (proctype!=TYSUBR || procclass!=CLPROC) )
805 err("alternate return in nonsubroutine");
809 if (p || proctype == TYSUBR) {
810 if (p == ENULL) p = ICON (0);
811 p = mkconv (TYLONG, fixtype (p));
813 } /* if p || proctype == TYSUBR */
815 p1_subr_ret((expptr)retslot);
826 if( ! ISINT(p->vtype) )
827 err("assigned goto variable must be integer");