/* xljump - execution context routines */
/* Copyright (c) 1989, by David Michael Betz. */
/* You may give out copies of this software; for conditions see the file */
/* COPYING included with this distribution. */
#include "xlisp.h"
/* forward declarations */
LOCAL VOID findandjump P2H(int, char *);
/* xlbegin - beginning of an execution context */
VOID xlbegin P3C(CONTEXT *, cptr, int, flags, LVAL, expr)
{
cptr->c_flags = flags;
cptr->c_expr = expr;
cptr->c_xlstack = xlstack;
cptr->c_xlenv = xlenv;
cptr->c_xlfenv = xlfenv;
cptr->c_xldenv = xldenv;
cptr->c_xlcontext = xlcontext;
cptr->c_xlargv = xlargv;
cptr->c_xlargc = xlargc;
cptr->c_xlfp = xlfp;
cptr->c_xlsp = xlsp;
#ifdef BYTECODE
cptr->c_xlcstop = xlcstop;
#endif /* BYTECODE */
xlcontext = cptr;
}
/* xlend - end of an execution context */
VOID xlend P1C(CONTEXT *, cptr)
{
xlcontext = cptr->c_xlcontext;
}
/* xlgo - go to a label */
/* TAA MOD 4/94 -- changed mechanism that GO target was
propagated back to tagbody(). Formerly the context block
was altered, but this caused problems with GO's within
UNWIND-PROTECTS (Error reported by Gottfried Ira, 3/94) */
VOID xlgo P1C(LVAL, label)
{
#ifdef LEXBIND
CONTEXT *cptr, *ctarg;
FRAMEP argv;
LVAL env,frame,tags;
int argc;
/* find a lexically visible tag context */
for (ctarg = NULL, env = xlenv; consp(env); env = cdr(env))
for (frame = car(env); consp(frame); frame = cdr(frame))
if (tagentry_p(car(frame)) && consp(tagentry_value(car(frame))))
for (tags = car(tagentry_value(car(frame)));
consp(tags);
tags = cdr(tags))
if (label == car(tags)) {
ctarg = tagentry_context(car(frame));
goto find_and_jump;
}
/* find a tagbody context */
find_and_jump:
for (cptr = xlcontext; cptr != NULL; cptr = cptr->c_xlcontext)
if (cptr->c_flags & CF_GO && cptr == ctarg) {
argc = cptr->c_xlargc;
argv = cptr->c_xlargv;
while (--argc >= 0)
if (*argv++ == label) {
xljump(cptr,(cptr->c_xlargc - argc),NIL);
}
}
xlerror("no target for GO", label);
#else
CONTEXT *cptr;
FRAMEP argv;
int argc;
/* find a tagbody context */
for (cptr = xlcontext; cptr != NULL; cptr = cptr->c_xlcontext)
if (cptr->c_flags & CF_GO) {
argc = cptr->c_xlargc;
argv = cptr->c_xlargv;
while (--argc >= 0)
if (*argv++ == label) {
xljump(cptr,(cptr->c_xlargc - argc),NIL);
}
}
xlfail("no target for GO");
#endif
}
/* xlreturn - return from a block */
VOID xlreturn P2C(LVAL, name, LVAL, val)
{
#ifdef LEXBIND
CONTEXT *cptr, *ctarg;
LVAL env, frame;
/* find the lexical context */
for (ctarg = NULL, env = xlenv; consp(env); env = cdr(env))
for (frame = car(env); consp(frame); frame = cdr(frame))
if (consp(car(frame)) && /* Added 6/16/95, from Niels Mayer */
tagentry_p(car(frame)) && tagentry_value(car(frame)) == name) {
ctarg = tagentry_context(car(frame));
goto find_and_jump;
}
/* find the context and jump */
find_and_jump:
for (cptr = xlcontext; cptr != NULL; cptr = cptr->c_xlcontext)
if (cptr->c_flags & CF_RETURN && cptr->c_expr == name && cptr == ctarg)
xljump(cptr,CF_RETURN,val);
xlerror("no target for RETURN", name);
#else
CONTEXT *cptr;
/* find a block context */
for (cptr = xlcontext; cptr != NULL; cptr = cptr->c_xlcontext)
if (cptr->c_flags & CF_RETURN && cptr->c_expr == name)
xljump(cptr,CF_RETURN,val);
xlfail("no target for RETURN");
#endif
}
/* xlthrow - throw to a catch */
VOID xlthrow P2C(LVAL, tag, LVAL, val)
{
CONTEXT *cptr;
/* find a catch context */
for (cptr = xlcontext; cptr != NULL; cptr = cptr->c_xlcontext)
if ((cptr->c_flags & CF_THROW) && cptr->c_expr == tag)
xljump(cptr,CF_THROW,val);
xlfail("no target for THROW");
}
/* xlsignal - signal an error */
VOID xlsignal P2C(char *, emsg, LVAL, arg)
{
CONTEXT *cptr;
/* find an error catcher */
for (cptr = xlcontext; cptr != NULL; cptr = cptr->c_xlcontext)
if (cptr->c_flags & CF_ERROR) {
if (!null(cptr->c_expr) && emsg != NULL)
xlerrprint("error",NULL,emsg,arg);
xljump(cptr,CF_ERROR,NIL);
}
}
/* xltoplevel - go back to the top level */
VOID xltoplevel P1C(int, print)
{
if (print)
dbgputstr("[ back to top level ]\n"); /* TAA MOD -- was std */
findandjump(CF_TOPLEVEL,"no top level");
}
/* xlbrklevel - go back to the previous break level */
VOID xlbrklevel(V)
{
if (batchmode) xlfatal("uncaught error");
findandjump(CF_BRKLEVEL,"no previous break level");
}
/* xlcleanup - clean-up after an error */
VOID xlcleanup(V)
{
dbgputstr("[ back to previous break level ]\n"); /* TAA MOD -- was std */
findandjump(CF_CLEANUP,"not in a break loop");
}
/* xlcontinue - continue from an error */
VOID xlcontinue(V)
{
findandjump(CF_CONTINUE,"not in a break loop");
}
/* xljump - jump to a saved execution context */
VOID xljump P3C(CONTEXT *, target, int, mask, LVAL, val)
{
/* unwind the execution stack */
for (; xlcontext != target; xlcontext = xlcontext->c_xlcontext)
/* check for an UNWIND-PROTECT */
if ((xlcontext->c_flags & CF_UNWIND)) {
xltarget = target;
xlmask = mask;
break;
}
/* restore the state */
xlstack = xlcontext->c_xlstack;
xlenv = xlcontext->c_xlenv;
xlfenv = xlcontext->c_xlfenv;
xlunbind(xlcontext->c_xldenv);
xlargv = xlcontext->c_xlargv;
xlargc = xlcontext->c_xlargc;
xlfp = xlcontext->c_xlfp;
xlsp = xlcontext->c_xlsp;
#ifdef BYTECODE
xlcstop = xlcontext->c_xlcstop;
#endif /* BYTECODE */
xlvalue = val;
/* call the handler */
XL_LONGJMP(xlcontext->c_jmpbuf,mask);
}
/* findandjump - find a target context frame and jump to it */
LOCAL VOID findandjump P2C(int, mask, char *, error)
{
CONTEXT *cptr;
/* find a block context */
for (cptr = xlcontext; cptr != NULL; cptr = cptr->c_xlcontext)
if (cptr->c_flags & mask)
xljump(cptr,mask,NIL);
xlabort(error);
}
syntax highlighted by Code2HTML, v. 0.9.1