/*
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 */
#include "bem.h"

#ifndef NORSCID
static char rcs_id[] = "$Header$" ;
#endif


List *forwardlabel=0;

Linerecord	*firstline, 
		*currline, 
		*lastline;

List *newlist()
{
	List *l;
	/*NOSTRICT*/ l= (List *) salloc(sizeof(List));
	return(l);
}

/* Line management is handled here */

Linerecord *srchline(nr)
int nr;
{
	Linerecord *l;
	for(l=firstline;l && l->linenr<=nr;l= l->nextline)
	if( l->linenr== nr) return(l);
	return(0);
}
List *srchforward(nr)
int nr;
{
	List *l;
	for(l=forwardlabel;l ;l=l->nextlist)
	if( l->linenr== nr) return(l);
	return(0);
}
linewarnings()
{
	List *l;
	extern int errorcnt;
	l= forwardlabel;
	while(l)
	{
	 	if( !srchline(l->linenr))
		{
			fprintf(stderr,"ERROR: line %d not defined\n",l->linenr);
			errorcnt++;
		}
		l=l->nextlist;
	}
}

newblock(nr)
int	nr;
{
	Linerecord	*l;
	List		*frwrd;

	if( debug) printf("newblock at %d\n",nr);
	if( nr>0 && currline && currline->linenr>= nr)
	{
		if( debug) printf("old line:%d\n",currline->linenr);
		error("Lines out of sequence");
	}

	frwrd=srchforward(nr);
	if( frwrd && debug) printf("forward found %d\n",frwrd->emlabel);
	l= srchline(nr);
	if( l)
	{
		error("Line redefined");
		nr= -genlabel();
	}

	/* make new EM block structure */
	/*NOSTRICT*/ l= (Linerecord *) salloc(sizeof(*l));
	l->emlabel= frwrd? frwrd->emlabel: genlabel();
	l->linenr= nr;
	/* save offset into Tmpfile too */
	l->offset = (long) ftell(Tmpfile);
	l->codelines= emlinecount;

	/* insert this record */
	if( firstline)
	{
		currline->nextline=l;
		l->prevline= currline;
		lastline= currline=l;
	} else
		firstline = lastline =currline=l;
}

gotolabel(nr)
int nr;
{
	/* simulate a goto statement in the line record table */
	Linerecord *l1;
	List	*ll;

	if(debug) printf("goto label %d\n",nr);
	/* update currline */
	ll= newlist();
	ll-> linenr=nr;
	ll-> nextlist= currline->gotos;
	currline->gotos= ll;

	/* try to generate code */
	l1= srchline(nr);
	if( (ll=srchforward(nr))!=0) 
		nr= ll->emlabel;
	else
	if( l1==0)
	{
		/* declare forward label */
		if(debug) printf("declare forward %d\n",nr);
		ll= newlist();
		ll->emlabel= genlabel();
		ll-> linenr=nr;
		ll->nextlist= forwardlabel;
		forwardlabel= ll;
		nr= ll->emlabel;
	} else 
		nr= l1->emlabel;
	return(nr);
}
gotostmt(nr)
int nr;
{
	emcode("bra",instrlabel(gotolabel(nr)));
}
/* GOSUB-return, assume that proper entries are made to subroutines
   only. The return statement is triggered by a fake constant label */

List	*gosubhead, *gotail;
int	gosubcnt=1;

List *gosublabel()
{
	List *l;

	l= newlist();
	l->nextlist=0;
	l->emlabel=genlabel();
	if( gotail){
		gotail->nextlist=l;
		gotail=l;
	} else gotail= gosubhead=l;
	gosubcnt++;
	return(l);
}
gosubstmt(lab)
int lab;
{
	List *l;
	int nr,n;

	n=gosubcnt;
	l= gosublabel();
	nr=gotolabel(lab);
	emcode("loc",itoa(n));	/*return index */
	emcode("cal","$_gosub");	/* administer legal return */
	emcode("asp",EMINTSIZE);
	emcode("bra",instrlabel(nr));
	fprintf(Tmpfile,"%d\n",l->emlabel);
	emlinecount++;
}
genreturns()
{
	int nr;
	nr= genlabel();
	fprintf(emfile,"returns\n");
	fprintf(emfile," rom *%d,1,%d\n",nr,gosubcnt-1);
	while( gosubhead)
	{
		fprintf(emfile," rom *%d\n",gosubhead->emlabel);
		gosubhead= gosubhead->nextlist;
	}
	fprintf(emfile,"%d\n",nr);
	fprintf(emfile," loc 1\n");
	fprintf(emfile," cal $error\n");
}
returnstmt()
{
	emcode("cal","$_retstmt");	/* ensure legal return*/
	emcode("lfr",EMINTSIZE);
	fprintf(Tmpfile," lae returns\n");
	emlinecount++;
	emcode("csa",EMINTSIZE);
}
/* compound goto-gosub statements */
List	*jumphead,*jumptail;
int	jumpcnt;

jumpelm(nr)
int nr;
{
	List *l;

	l= newlist();
	l->emlabel= gotolabel(nr);
	l->nextlist=0;
	if( jumphead==0) jumphead= jumptail= l;
	else {
		jumptail->nextlist=l;
		jumptail=l;
	}
	jumpcnt++;
}
ongotostmt(type)
int type;
{
	/* generate the code itself, index in on top of the stack */
	/* blurh, store the number of entries in the descriptor */
	int firstlabel;
	int descr;
	List *l;
	/* create descriptor first */
	descr= genlabel();
	firstlabel=genlabel();
	fprintf(Tmpfile,"l%d\n",descr); emlinecount++;
	fprintf(Tmpfile," rom *%d,1,%d\n",firstlabel,jumpcnt-1); emlinecount++;
	l= jumphead;
	while( l)
	{
		fprintf(Tmpfile," rom *%d\n",l->emlabel); emlinecount++;
		l= l->nextlist;
	}
	jumphead= jumptail=0; jumpcnt=0;
	if(debug) printf("ongotst:%d labels\n", jumpcnt);
	conversion(type,INTTYPE);
	emcode("lae",datalabel(descr));
	emcode("csa",EMINTSIZE);
	fprintf(Tmpfile,"%d\n",firstlabel); emlinecount++;
}
ongosubstmt(type)
int type;
{
	List *l;
	int firstlabel;
	int descr;
	/* create descriptor first */
	descr= genlabel();
	firstlabel=genlabel();
	fprintf(Tmpfile,"l%d\n",descr); emlinecount++;
	fprintf(Tmpfile," rom *%d,1,%d\n",firstlabel,jumpcnt-1); emlinecount++;
	l= jumphead;
	while( l)
	{
		fprintf(Tmpfile," rom *%d\n",l->emlabel); emlinecount++;
		l= l->nextlist;
	}
	jumphead= jumptail=0; jumpcnt=0;

	l= newlist();
	l->nextlist=0;
	l->emlabel=firstlabel;
	if( gotail){
		gotail->nextlist=l;
		gotail=l;
	} else gotail= gosubhead=l;
	/* save the return point of the gosub */
	emcode("loc",itoa(gosubcnt));
	emcode("cal","$_gosub");
	emcode("asp",EMINTSIZE);
	gosubcnt++;
	/* generate gosub */
	conversion(type,INTTYPE);
	emcode("lae",datalabel(descr));
	emcode("csa",EMINTSIZE);
	fprintf(Tmpfile,"%d\n",firstlabel);
	emlinecount++;
}

/* REGION ANALYSIS and FINAL VERSION GENERATION */

simpleprogram()
{
	char	buf[512];
	int length;

	/* a small EM programs has been found */
	prologcode();
	prolog2();
	(void) fclose(Tmpfile);
	Tmpfile= fopen(tmpfname,"r");
	if( Tmpfile==NULL)
		fatal("tmp file disappeared");
	while( (length=fread(buf,1,512,Tmpfile)) != 0)
		(void) fwrite(buf,1,length,emfile);
	epilogcode();
	(void) unlink(tmpfname);
}
