V10/cmd/basic/basic/go.c
/* "@(#) 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);
}