V10/cmd/basic/basic/go.c

Compare this file to the similar file:
Show the results in this format:

/*	"@(#) go.c: V 1.13 6/8/83"	*/

#include <stdio.h>
#include "bas.h"

extern char	*ptr;

extern short	fortop,
		whiletop,
		endfcnt;

struct gnode {
	LINNO		tolin;
	LINNO		fromlin;
	short		fromstmt;
	short		fornest;
	short		whilenest;
	short		ifnest;
	struct gnode	*next;
}	gotolist[CACHESIZE];

struct gnode	*front;

extern int	FORcmd,
		IFcmd,
		ENDIFcmd,
		WHILEcmd,
		WENDcmd,
		NEXTcmd;

extern UCHAR	stmtno;

extern struct conrec	constack[],
			*contop;



__goto()
{
	LINNO	savno,
		start;
	short	savstmt;

	savno = inst.thing.linno;
	savstmt = inst.thing.stmtno;
	if ((start = atoln(expr)) == 0)
	{
		error(inst.thing.linno,inst.thing.stmtno, 89);
		return(-1);
	}
	stmtno = STMT;
	fetch(start,STMT,&ptr);
	if (inst.thing.linno != start)
	{
		error(savno,savstmt,0);
		inst.thing.linno = savno;
		return(-1);
	}
	if (savno == IMMED)			/* jumping into program */
	{
		fortop = contop->fornest;
		whiletop = contop->whilenest;
		endfcnt = contop->ifnest;
	}
	else if (!gofound(savno,start,savstmt))
	{
		if (countnest(savno,savstmt,start) < 0)
			return(-1);
	}
	else
	{
		if (changenest(front) < 0)
			return(-1);
		if (front->ifnest > 0)
			endfcnt -= front->ifnest;
	}
	ptr = curptr;
	return(0);
}



gofound(savno,start,stmtno)
LINNO	savno,
	start;
short	stmtno;
{
	struct gnode	*find,
			*trail;

	find = front;
	trail = NULL;
	while (find != NULL)
	{
		if (find->tolin == 0 && find->fromlin == 0)
			return(0);
		if (find->tolin == start && find->fromlin == savno
						&& find->fromstmt == stmtno)
		{
			if (trail != NULL)
			{
				trail->next = find->next;
				find->next = front;
				front = find;
			}
			return(1);
		}
		trail = find;
		find = find->next;
	}
	return(0);
}



addgo(newgo)
struct gnode	*newgo;
{
	struct gnode	*find,
			*trail;

	find = front;
	trail = NULL;
	while (find->next != NULL && (find->tolin != 0 && find->fromlin != 0))
	{
		trail = find;
		find = find->next;
	}
	if (trail != NULL)
		trail->next = find->next;
	if (find != front)
		find->next = front;
	front = find;
	front->tolin = newgo->tolin;
	front->fromlin = newgo->fromlin;
	front->fromstmt = newgo->fromstmt;
	front->fornest = newgo->fornest;
	front->whilenest = newgo->whilenest;
	front->ifnest = newgo->ifnest;
}



initgo()
{
	int	i;

	front = gotolist;
	for (i = 1; i < CACHESIZE; ++i)
	{
		gotolist[i-1].tolin = 0;
		gotolist[i-1].fromlin = 0;
		gotolist[i-1].fromstmt = 0;
		gotolist[i-1].fornest = 0;
		gotolist[i-1].whilenest = 0;
		gotolist[i-1].ifnest = 0;
		gotolist[i-1].next = gotolist + i;
	}
	gotolist[CACHESIZE-1].tolin = 0;
	gotolist[CACHESIZE-1].fromlin = 0;
	gotolist[CACHESIZE-1].fromstmt = 0;
	gotolist[CACHESIZE-1].fornest = 0;
	gotolist[CACHESIZE-1].whilenest = 0;
	gotolist[CACHESIZE-1].ifnest = 0;
	gotolist[CACHESIZE-1].next = NULL;
}




gosub()
{
	LINNO		savno,
			tarline;
	short		savstmt;

	savno = inst.thing.linno;	/* save the gosub line number */
	savstmt = inst.thing.stmtno;	/* for diagnostic reasons */
	skip00(&expr);
	if ((tarline = atoln(expr)) == 0)
	{
		error(inst.thing.linno,inst.thing.stmtno, 89);
		return(-1);
	}
	if (fetch(tarline,STMT,&lbdptr) != 0)
	{
		error(savno,savstmt,0);			/* Bad line number */
		inst.thing.linno = savno;
		return(-1);
	}
	if (push_context() < 0)
		return(-1);
	contop->gosublin = savno;
	contop->gosubstmt = savstmt;
	ptr = curptr;
	return(0);
}




__return()
{
	if (contop->gosublin == 0)
	{
		if (contop - 1 >= constack && (contop - 1)->gosublin == IMMED)
			__end();
		else
		{   				/* return with no gosub */
			error(inst.thing.linno,inst.thing.stmtno,73);
			return(-1);
		}
	}
	else
		fetch(contop->gosublin,contop->gosubstmt,&ptr);
	pop_context();
	return(0);
}



countnest(curline,curstmt,tarline)
LINNO	curline;
short	curstmt;
LINNO	tarline;
{
	int	ifseen;
	struct gnode	newgo;

	if (curline == IMMED)
	{
		initstack();
		return(0);
	}
	newgo.tolin = tarline;
	newgo.fromlin = curline;
	newgo.fromstmt = curstmt;
	newgo.fornest = 0;
	newgo.whilenest = 0;
	newgo.ifnest = 0;
	ifseen = 0;
	if (curline >= tarline)				/* backward jump */
	{
		fetch(tarline,STMT,&ptr);
		while (inst.thing.linno != curline
					|| inst.thing.stmtno != curstmt)
		{
			if (inst.thing.opcode == FORcmd)
				--(newgo.fornest);
			else if (inst.thing.opcode == NEXTcmd)
				++(newgo.fornest);
			else if (inst.thing.opcode == IFcmd)
			{
				while ((*expr & 0377) != THENcode 
							&& *expr != '\0')
					++expr;
				if (*expr != '\0')
				{
					++expr;
					skip00(&expr);
					if (*expr == '\0')
						++ifseen;
				}
			}
			else if (inst.thing.opcode == ENDIFcmd)
			{
				if (ifseen > 0)
					--ifseen;
			}
			else if (inst.thing.opcode == WHILEcmd)
				--(newgo.whilenest);
			else if (inst.thing.opcode == WENDcmd)
				++(newgo.whilenest);
			fetch(NEXT,STMT,&ptr);
		}
		newgo.ifnest = ifseen;
		if (changenest(&newgo) < 0)
			return(-1);
		addgo(&newgo);
		endfcnt -= ifseen;
		if (endfcnt < 0)
			endfcnt = 0;
		fetch(tarline,STMT,&ptr);
	}
	else if (tarline > curline)			/* forward jump */
	{
		fetch(curline,curstmt,&ptr);
		fetch(NEXT,STMT,&ptr);
		while (inst.thing.linno != tarline)
		{
			if (inst.thing.opcode == NEXTcmd)
			{
				if (popfor() < 0)
					return(-1);
				--(newgo.fornest);
			}
			else if (inst.thing.opcode == FORcmd)
			{
				if (pushfor() < 0)
					return(-1);
				++(newgo.fornest);
			}
			if (inst.thing.opcode == WENDcmd)
			{
				if (popwhile() < 0)
					return(-1);
				--(newgo.whilenest);
			}
			else if (inst.thing.opcode == WHILEcmd)
			{
				if (pushwhile() < 0)
					return(-1);
				++(newgo.whilenest);
			}
			else if (inst.thing.opcode == IFcmd)
			{
				while ((*expr & 0377) != THENcode 
							&& *expr != '\0')
					++expr;
				if (*expr != '\0')
				{
					++expr;
					skip00(&expr);
					if (*expr == '\0')
						++ifseen;
				}
			}
			else if (inst.thing.opcode == ENDIFcmd)
			{
				if (ifseen == 0)
				{
					if (endfcnt > -1)
					{
						--endfcnt;
						++(newgo.ifnest);
					}
				}
				else
					--ifseen;
			}
			fetch(NEXT,STMT,&ptr);
		}
		addgo(&newgo);
	}
	return(0);
}



changenest(ptr)
struct gnode	*ptr;
{
	int	i;

	i = ptr->fornest;
	if (i > 0)
	{
		while (i-- > 0)
			if (pushfor() < 0)
				return(-1);
	}
	else
	{
		while (i++ < 0)
			if (popfor() < 0)
				return(-1);
	}
	i = ptr->whilenest;
	if (i > 0)
	{
		while (i-- > 0)
			if (pushwhile() < 0)
				return(-1);
	}
	else
	{
		while (i++ < 0)
			if (popwhile() < 0)
				return(-1);
	}
	return(0);
}