static char rcsid[] = "$Header:blklab.c 12.0$";
#include "defs"


hide(p)
ptr p;
{
warn1("Name %s hidden by a new declaration", ((struct stentry *)p)->namep);
hidlist = mkchain(((struct stentry *)p)->varp, hidlist);
((struct stentry *)p)->varp = 0;
++nhid[blklevel];
}



/*  remove all symbol table entries in terminated block,
    revive old hidden names
*/
unhide()
{
chainp p;
register ptr q;
register ptr v;
register struct stentry *s;
struct stentry **hp;

for(hp = hashtab ; hp<hashend ; ++hp)
	if(s = *hp)
		{
	if( (v = ((struct stentry *)s)->varp) && ((struct headbits *)v)->blklevel == blklevel)
			{
			if(((struct headbits *)v)->tag==TLABEL)
				if(blklevel <= 1)
					{
					if(((struct execblock *)v)->labdefined==0)
						laberr("%s never defined",
							((struct stentry *)((struct varblock *)v)->sthead)->namep);
					((struct stentry *)s)->varp = 0;
					}
				else	{ /* move label out a level */
					if(((struct execblock *)v)->labdefined)
						((struct execblock *)v)->labinacc = 1;
					((struct headbits *)v)->blklevel--;
					++ndecl[blklevel-1];
					}
			else	{
				if(((struct headbits *)v)->tag == TNAME)
					{
					TEST fprintf(diagfile,"gone(%s) level %d\n",
						((struct stentry *)s)->namep, blklevel);
					gonelist = mkchain(((struct stentry *)s)->varp, gonelist);
					}

				else if(((struct headbits *)v)->tag!=TSTRUCT)
					{
					++ndecl[blklevel];
					if(((struct headbits *)v)->tag==TDEFINE)
						frdef(v);
					}
				((struct stentry *)s)->varp = 0;
				}
			--ndecl[blklevel];
			}
		}

for( p=hidlist  ;  p && (v = (q=(ptr)(((struct stentry *)((struct varblock *)((struct chain *)p)->datap)->sthead)->varp==NULL))) ; p=hidlist )
	{
	((struct stentry *)v)->varp = q;
	((struct headbits *)v)->tag = ((struct headbits *)q)->tag;
	((struct headbits *)v)->subtype = ((struct headbits *)q)->subtype;
	if(((struct headbits *)v)->blklevel > ((struct headbits *)q)->blklevel)
		((struct headbits *)v)->blklevel = ((struct headbits *)q)->blklevel;
	hidlist = (chainp)((struct chain *)p)->nextp;
	((struct chain *)p)->nextp = (ptr)CHNULL;
	frchain(&p);
	--nhid[blklevel];
TEST fprintf(diagfile, "unhide(%s), blklevel %d\n", ((struct stentry *)v)->namep, ((struct headbits *)v)->blklevel);
	}
if(ndecl[blklevel] != 0)
	{
	sprintf(msg, "%d declarations leftover at block level %d",
		ndecl[blklevel], blklevel);
	fatal(msg);
	}
if(nhid[blklevel] != 0)
	fatal("leftover hidden variables");
}




ptr bgnexec()
{
register ptr p;

p = allexcblock();
((struct headbits *)p)->tag = TEXEC;
((struct execblock *)p)->prevexec = thisexec;
if(thisexec && ((struct labelblock *)thisexec)->copylab)
	{
	((struct caseblock *)p)->labelno = ((struct caseblock *)thisexec)->labelno;
	((struct labelblock *)p)->labused = ((struct labelblock *)thisexec)->labused;
	((struct caseblock *)thisexec)->labelno = 0;
	}
thisexec = p;
return(p);
}


ptr addexec()
{
register ptr p;
register ptr q;

q = thisexec;
p = ((struct execblock *)q)->prevexec;

if(((struct execblock *)q)->temps)
	tempvarlist = hookup(((struct execblock *)q)->temps, tempvarlist);

((struct caseblock *)p)->brnchend = ((struct caseblock *)q)->brnchend;
((struct execblock *)p)->nftnst += ((struct execblock *)q)->nftnst;
((struct labelblock *)p)->labeled |= ((struct labelblock *)q)->labeled;
((struct execblock *)p)->uniffable |= ((struct execblock *)q)->uniffable;

if(((struct caseblock *)q)->labelno && !(((struct labelblock *)q)->labused))
	{
	if(((struct execblock *)q)->nxtlabno)
		exnull();
	else ((struct execblock *)q)->nxtlabno = ((struct caseblock *)q)->labelno;
	}

thisexec = p;

if(((struct execblock *)q)->nxtlabno)
	{
	if(((struct caseblock *)p)->labelno && !(((struct labelblock *)p)->labused))
		exnull();
	((struct caseblock *)p)->labelno = ((struct execblock *)q)->nxtlabno;
	((struct labelblock *)p)->labused = 0;
	}

frexcblock(q);
return(p);
}



pushctl(t,vp)
int t;
register ptr vp;
{
register ptr q;
ptr p;
int junk;

q = allexcblock();
((struct headbits *)q)->tag = TCONTROL;
((struct headbits *)q)->subtype = t;
((struct ctlblock *)q)->loopvar = vp;
((struct ctlblock *)q)->prevctl = thisctl;
thisctl = q;

switch(t)
	{
	case STSWITCH:
		((struct ctlblock *)q)->xlab = nextlab();
		((struct ctlblock *)q)->nextlab = 0;
		exgoto(((struct ctlblock *)q)->xlab);
		ncases = -1;
		break;

	case STFOR:
		exlab(0);
		((struct ctlblock *)q)->nextlab = nextlab();
		((struct ctlblock *)q)->xlab = nextlab();
		break;

	case STWHILE:
		((struct ctlblock *)q)->nextlab = thislab();
		if(vp)
			exifgo( mknode(TNOTOP,OPNOT,vp,PNULL),
				((struct ctlblock *)q)->breaklab = nextlab() );
		else	((struct execblock *)thisexec)->copylab = 1;
		break;

	case STREPEAT:
		exnull();
		((struct ctlblock *)q)->xlab = thislab();
		((struct execblock *)thisexec)->copylab = 1;
		junk = nextindif();
		indifs[junk] = 0;
		((struct ctlblock *)q)->indifn = junk;
		indifs[((struct ctlblock *)q)->indifn] = ((struct ctlblock *)q)->xlab;
		break;

	case STDO:
		((struct ctlblock *)q)->nextlab = nextlab();
		exlab(0);
		putic(ICKEYWORD,FDO);
		putic(ICLABEL, ((struct ctlblock *)q)->nextlab);
		putic(ICBLANK, 1);
		p = mknode(TASGNOP,OPASGN,((struct doblock *)vp)->dovar,((struct doblock *)vp)->dopar[0]);
		prexpr(p);
		frexpr(p);
		putic(ICOP, OPCOMMA);
		prexpr(((struct doblock *)vp)->dopar[1]);
		frexpr(((struct doblock *)vp)->dopar[1]);
		if(((struct doblock *)vp)->dopar[2])
			{
			putic(ICOP, OPCOMMA);
			prexpr(((struct doblock *)vp)->dopar[2]);
			frexpr(((struct doblock *)vp)->dopar[2]);
			}
		cfree(vp);
		break;

	case STIF:
		exif(vp);
		((struct execblock *)thisexec)->nftnst = 0;
		break;

	default:
		fatal1("pushctl: invalid control block type %d", t);
	}

++ctllevel;
}



popctl()
{
register ptr p;
ptr newp;
chainp q;
int first, deflabno, blab, cmin, cmax, range, caseval, optcase;
int labp[MAXSWITCH];

if(thisctl == 0)
	fatal("empty control stack popped");

switch(((struct headbits *)thisctl)->subtype)
	{
	case STSWITCH:
/*		if(((struct caseblock *)thisexec)->brnchend == 0)	*/
			{
			if(((struct ctlblock *)thisctl)->breaklab == 0)
				((struct ctlblock *)thisctl)->breaklab = nextlab();
			exgoto(((struct ctlblock *)thisctl)->breaklab);
			}
		exlab(((struct ctlblock *)thisctl)->xlab);
		deflabno = 0;
		first = YES;
		optcase = (((struct varblock *)((struct ctlblock *)thisctl)->loopvar)->vtype == TYINT);

		for(p=((struct ctlblock *)thisctl)->loopctl ; p!=0 ; p = ((struct caseblock *)p)->nextcase)
			if(((struct labelblock *)p)->labdefined == 0)
				{
				laberr("undefined case label", CNULL);
				optcase = NO;
				}
			else if(((struct caseblock *)p)->casexpr == 0)
				deflabno = ((struct labelblock *)p)->labelno;
			else if( isicon(((struct caseblock *)p)->casexpr, &caseval))
				{
				if(first)
					{
					first = NO;
					cmin = cmax = caseval;
					}
				else	{
					if(caseval < cmin)
						cmin = caseval;
					if(caseval > cmax)
						cmax = caseval;
					}
				++ncases;
				}
			else	optcase = NO;

		range = cmax - cmin + 1;
		if(optcase && ncases>2 && range<2*ncases && range<MAXSWITCH)
			{
			register int i;
			for(i=0; i<range ; ++i)
				labp[i] = 0;
			for(p=((struct ctlblock *)thisctl)->loopctl ; p!=0 ; p = ((struct caseblock *)p)->nextcase)
				if(((struct labelblock *)p)->labdefined && ((struct caseblock *)p)->casexpr)
					{
					isicon(((struct caseblock *)p)->casexpr, &caseval);
					frexpr(((struct caseblock *)p)->casexpr);
					labp[caseval-cmin] = ((struct labelblock *)p)->labelno;
					}
			
			q = CHNULL;
			blab = (deflabno ? deflabno : ((struct ctlblock *)thisctl)->breaklab);
			for(i=range-1 ; i>=0 ; --i)
				q = mkchain(labp[i] ? labp[i] : blab, q);
			excompgoto(q, mknode(TAROP,OPPLUS, mkint(1-cmin),
				     cpexpr(((struct ctlblock *)thisctl)->loopvar) ));
			}
		else	{
			for(p=((struct ctlblock *)thisctl)->loopctl ; p!=0 ; p = ((struct caseblock *)p)->nextcase)
				if(((struct labelblock *)p)->labdefined && ((struct caseblock *)p)->casexpr)
					exifgo( mknode(TRELOP,OPEQ,
					   cpexpr(((struct ctlblock *)thisctl)->loopvar),((struct caseblock *)p)->casexpr),
					   ((struct labelblock *)p)->labelno);
			}
		if(deflabno)
			exgoto(deflabno);

		for(p = ((struct ctlblock *)thisctl)->loopctl ; p; p = newp)
			{
			newp = ((struct caseblock *)p)->nextcase;
			cfree(p);
			}
		((struct ctlblock *)thisctl)->loopctl = NULL;
		break;

	case STFOR:
		exgoto(((struct ctlblock *)thisctl)->nextlab);
		break;

	case STWHILE:
		exgoto(((struct ctlblock *)thisctl)->nextlab);
		break;

	case STREPEAT:
		break;

	case STDO:
		exnull();
		exlab(((struct ctlblock *)thisctl)->nextlab);
		putic(ICKEYWORD,FCONTINUE);
		break;

	case STIF:
		break;

	case STPROC:
		break;

	default:
		fatal1("popctl: invalid control block type %d",
			((struct headbits *)thisctl)->subtype);
	}

if(((struct ctlblock *)thisctl)->breaklab != 0)
	((struct execblock *)thisexec)->nxtlabno = ((struct ctlblock *)thisctl)->breaklab;
p = ((struct ctlblock *)thisctl)->prevctl;
frexcblock(thisctl);
thisctl = p;
--ctllevel;
}
