#include "defs" #include "string_defs" /* Logical IF codes */ exif(p) expptr p; { pushctl(CTLIF); ctlstack->elselabel = newlabel(); putif(p, ctlstack->elselabel); } exelif(p) expptr p; { if(ctlstack->ctltype == CTLIF) { if(ctlstack->endlabel == 0) ctlstack->endlabel = newlabel(); putgoto(ctlstack->endlabel); putlabel(ctlstack->elselabel); ctlstack->elselabel = newlabel(); putif(p, ctlstack->elselabel); } else error("elseif out of place", 0,0,EXECERR); } exelse() { if(ctlstack->ctltype==CTLIF) { if(ctlstack->endlabel == 0) ctlstack->endlabel = newlabel(); putgoto( ctlstack->endlabel ); putlabel(ctlstack->elselabel); ctlstack->ctltype = CTLELSE; } else error("else out of place", 0,0,EXECERR); } exendif() { if(ctlstack->ctltype == CTLIF) { putlabel(ctlstack->elselabel); if(ctlstack->endlabel) putlabel(ctlstack->endlabel); popctl(); } else if(ctlstack->ctltype == CTLELSE) { putlabel(ctlstack->endlabel); popctl(); } else error("endif out of place", 0,0,EXECERR); } LOCAL pushctl(code) int code; { register int i; if(++ctlstack >= lastctl) error("nesting too deep",0,0,FATAL); ctlstack->ctltype = code; for(i = 0 ; i < 4 ; ++i) ctlstack->ctlabels[i] = 0; ++blklevel; } LOCAL popctl() { if( ctlstack-- < ctls ) error("control stack empty",0,0,FATAL); --blklevel; } LOCAL poplab() { register struct labelblock *lp; for(lp = labeltab ; lp < highlabtab ; ++lp) if(lp->labdefined) { /* mark all labels in inner blocks unreachable */ if(lp->blklevel > blklevel) lp->labinacc = YES; } else if(lp->blklevel > blklevel) { /* move all labels referred to in inner blocks out a level */ lp->blklevel = blklevel; } } /* BRANCHING CODE */ exgoto(lab) struct labelblock *lab; { putgoto(lab->labelno); } exequals(lp, rp) register struct primblock *lp; register expptr rp; { if(lp->tag != TPRIM) { error("assignment to a non-variable",0,0,ERR); frexpr(lp); frexpr(rp); } else if(lp->namep->vclass!=CLVAR && lp->argsp) { if(parstate >= INEXEC) error("statement function amid executables",0,0,ERR); else mkstfunct(lp, rp); } else { if(parstate < INDATA) enddcl(); puteq(mklhs(lp), rp); } } mkstfunct(lp, rp) struct primblock *lp; expptr rp; { register struct primblock *p; register struct nameblock *np; chainp args; np = lp->namep; if(np->vclass == CLUNKNOWN) np->vclass = CLPROC; else { error("redeclaration of statement function", np, 0, DCLERR); return; } np->vprocclass = PSTFUNCT; np->vstg = STGSTFUNCT; impldcl(np); args = (lp->argsp ? lp->argsp->listp : NULL); np->vardesc.vstfdesc = mkchain(args , rp ); for( ; args ; args = args->nextp) if( (p = args->datap)->tag!=TPRIM || p->argsp || p->fcharp || p->lcharp) error("non-variable argument in statement function definition",0,0,ERR); else { vardcl(args->datap = p->namep); free(p); } } excall(name, args, nstars, labels) struct hashentry *name; struct listblock *args; int nstars; struct labelblock *labels[ ]; { register expptr p; settype(name, TYSUBR, NULL); p = mkfunct( mkprim(name, args, NULL, NULL) ); p->vtype = p->leftp->vtype = TYINT; if(nstars > 0) putcmgo(p, nstars, labels); else putexpr(p); } exstop(stop, p) int stop; register expptr p; { char *q; int n; struct constblock *mkstrcon(); if(p) { if( ! ISCONST(p) ) { error("pause/stop argument must be constant", 0,0,EXECERR); frexpr(p); p = mkstrcon(0, 0); } else if( ISINT(p->vtype) ) { q = convic(p->const.ci); n = strlen(q); if(n > 0) { p->const.ccp = copyn(n, q); p->vtype = TYCHAR; p->vleng = ICON(n); } else p = mkstrcon(0, 0); } else if(p->vtype != TYCHAR) { error("pause/stop argument must be integer or string", 0,0,EXECERR); p = mkstrcon(0, 0); } } else p = mkstrcon(0, 0); putexpr( call1(TYSUBR, (stop ? "s_stop" : "s_paus"), p) ); } /* DO LOOP CODE */ #define DOINIT par[0] #define DOLIMIT par[1] #define DOINCR par[2] #define VARSTEP 0 #define POSSTEP 1 #define NEGSTEP 2 exdo(range, spec) int range; chainp spec; { register expptr p, q; expptr *q1; register struct nameblock *np; chainp cp; register int i; int dotype, incsign; struct addrblock *dovarp, *dostgp; expptr par[3]; pushctl(CTLDO); dorange = ctlstack->dolabel = range; np = spec->datap; ctlstack->donamep = NULL; if(np->vdovar) { error("nested loops with variable %s", varstr(VL,np->varname),0,ERR1); ctlstack->donamep = NULL; return; } dovarp = mklhs( mkprim(np, 0,0,0) ); if( ! ONEOF(dovarp->vtype, MSKINT|MSKREAL) ) { error("bad type on do variable",0,0,ERR); return; } ctlstack->donamep = np; np->vdovar = YES; if( enregister(np) ) { /* stgp points to a storage version, varp to a register version */ dostgp = dovarp; dovarp = mklhs( mkprim(np, 0,0,0) ); } else dostgp = NULL; dotype = dovarp->vtype; for(i=0 , cp = spec->nextp ; cp!=NULL && i<3 ; cp = cp->nextp) { p = par[i++] = fixtype(cp->datap); if( ! ONEOF(p->vtype, MSKINT|MSKREAL) ) { error("bad type on DO parameter",0,0,ERR); return; } } frchain(&spec); switch(i) { case 0: case 1: error("too few DO parameters",0,0,ERR); return; default: error("too many DO parameters",0,0,ERR); return; case 2: DOINCR = ICON(1); case 3: break; } ctlstack->endlabel = newlabel(); ctlstack->dobodylabel = newlabel(); if( ISCONST(DOLIMIT) ) ctlstack->domax = mkconv(dotype, DOLIMIT); else ctlstack->domax = mktemp(dotype, NULL); if( ISCONST(DOINCR) ) { ctlstack->dostep = mkconv(dotype, DOINCR); if( (incsign = conssgn(ctlstack->dostep)) == 0) error("zero DO increment",0,0,ERR); ctlstack->dostepsign = (incsign > 0 ? POSSTEP : NEGSTEP); } else { ctlstack->dostep = mktemp(dotype, NULL); ctlstack->dostepsign = VARSTEP; ctlstack->doposlabel = newlabel(); ctlstack->doneglabel = newlabel(); } if( ISCONST(ctlstack->domax) && ISCONST(DOINIT) && ctlstack->dostepsign!=VARSTEP) { puteq(cpexpr(dovarp), cpexpr(DOINIT)); if( onetripflag ) frexpr(DOINIT); else { q = mkexpr(OPPLUS, ICON(1), mkexpr(OPMINUS, cpexpr(ctlstack->domax), cpexpr(DOINIT)) ); if(incsign != conssgn(q)) { error("DO range never executed",0,0,WARN); putgoto(ctlstack->endlabel); } frexpr(q); } } else if(ctlstack->dostepsign!=VARSTEP && !onetripflag) { if( ISCONST(ctlstack->domax) ) q = cpexpr(ctlstack->domax); else q = mkexpr(OPASSIGN, cpexpr(ctlstack->domax), DOLIMIT); q1 = mkexpr(OPASSIGN, cpexpr(dovarp), DOINIT); q = mkexpr( (ctlstack->dostepsign==POSSTEP ? OPLE : OPGE), q1, q); putif(q, ctlstack->endlabel); } else { if(! ISCONST(ctlstack->domax) ) puteq( cpexpr(ctlstack->domax), DOLIMIT); q = DOINIT; if( ! onetripflag ) q = mkexpr(OPMINUS, q, mkexpr(OPASSIGN, cpexpr(ctlstack->dostep), DOINCR) ); puteq( cpexpr(dovarp), q); if(onetripflag && ctlstack->dostepsign==VARSTEP) puteq( cpexpr(ctlstack->dostep), DOINCR); } if(ctlstack->dostepsign == VARSTEP) { if(onetripflag) putgoto(ctlstack->dobodylabel); else putif( mkexpr(OPGE, cpexpr(ctlstack->dostep), ICON(0)), ctlstack->doneglabel ); putlabel(ctlstack->doposlabel); putif( mkexpr(OPLE, mkexpr(OPPLUSEQ, cpexpr(dovarp), cpexpr(ctlstack->dostep)), cpexpr(ctlstack->domax) ), ctlstack->endlabel); } putlabel(ctlstack->dobodylabel); if(dostgp) puteq(dostgp, cpexpr(dovarp)); frexpr(dovarp); } enddo(here) int here; { register struct ctlframe *q; register expptr t; struct nameblock *np; struct addrblock *ap; register int i; while(here == dorange) { if(np = ctlstack->donamep) { t = mkexpr(OPPLUSEQ, mklhs(mkprim(ctlstack->donamep, 0,0,0)), cpexpr(ctlstack->dostep) ); if(ctlstack->dostepsign == VARSTEP) { putif( mkexpr(OPLE, cpexpr(ctlstack->dostep), ICON(0)), ctlstack->doposlabel); putlabel(ctlstack->doneglabel); putif( mkexpr(OPLT, t, ctlstack->domax), ctlstack->dobodylabel); } else putif( mkexpr( (ctlstack->dostepsign==POSSTEP ? OPGT : OPLT), t, ctlstack->domax), ctlstack->dobodylabel); putlabel(ctlstack->endlabel); if(ap = memversion(np)) puteq(ap, mklhs( mkprim(np,0,0,0)) ); for(i = 0 ; i < 4 ; ++i) ctlstack->ctlabels[i] = 0; deregister(ctlstack->donamep); ctlstack->donamep->vdovar = NO; frexpr(ctlstack->dostep); } popctl(); poplab(); dorange = 0; for(q = ctlstack ; q>=ctls ; --q) if(q->ctltype == CTLDO) { dorange = q->dolabel; break; } } } exassign(vname, labelval) struct nameblock *vname; struct labelblock *labelval; { struct addrblock *p; struct constblock *mkaddcon(); p = mklhs(mkprim(vname,0,0,0)); if( ! ONEOF(p->vtype, MSKINT|MSKADDR) ) error("noninteger assign variable",0,0,ERR); else puteq(p, mkaddcon(labelval->labelno) ); } exarif(expr, neglab, zerlab, poslab) expptr expr; struct labelblock *neglab, *zerlab, *poslab; { register int lm, lz, lp; lm = neglab->labelno; lz = zerlab->labelno; lp = poslab->labelno; expr = fixtype(expr); if( ! ONEOF(expr->vtype, MSKINT|MSKREAL) ) { error("invalid type of arithmetic if expression",0,0,ERR); frexpr(expr); } else { if(lm == lz) exar2(OPLE, expr, lm, lp); else if(lm == lp) exar2(OPNE, expr, lm, lz); else if(lz == lp) exar2(OPGE, expr, lz, lm); else prarif(expr, lm, lz, lp); } } LOCAL exar2(op, e, l1, l2) int op; expptr e; int l1, l2; { putif( mkexpr(op, e, ICON(0)), l2); putgoto(l1); } exreturn(p) register expptr p; { if(procclass != CLPROC) error("RETURN statement in main or block data",0,0,WARN); if(p && (proctype!=TYSUBR || procclass!=CLPROC) ) { error("alternate return in nonsubroutine",0,0,ERR); p = 0; } if(p) { putforce(TYINT, p); putgoto(retlabel); } else putgoto(proctype==TYSUBR ? ret0label : retlabel); } exasgoto(labvar) struct hashentry *labvar; { register struct addrblock *p; p = mklhs( mkprim(labvar,0,0,0) ); if( ! ISINT(p->vtype) ) error("assigned goto variable must be integer",0,0,ERR); else putbranch(p); }