#ifdef TESTMAIN
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#else
#include <stand.h>
#endif
#include <string.h>
#include "ficl.h"
#if 0
#define nBREAKPOINTS 32
#endif
static void vmSetBreak(FICL_VM *pVM, FICL_BREAKPOINT *pBP)
{
FICL_WORD *pStep = ficlLookup(pVM->pSys, "step-break");
assert(pStep);
pBP->address = pVM->ip;
pBP->origXT = *pVM->ip;
*pVM->ip = pStep;
}
static void debugPrompt(FICL_VM *pVM)
{
vmTextOut(pVM, "dbg> ", 0);
}
int isAFiclWord(FICL_DICT *pd, FICL_WORD *pFW)
{
if (!dictIncludes(pd, pFW))
return 0;
if (!dictIncludes(pd, pFW->name))
return 0;
if ((pFW->link != NULL) && !dictIncludes(pd, pFW->link))
return 0;
if ((pFW->nName <= 0) || (pFW->name[pFW->nName] != '\0'))
return 0;
if (strlen(pFW->name) != pFW->nName)
return 0;
return 1;
}
#if 0
static int isPrimitive(FICL_WORD *pFW)
{
WORDKIND wk = ficlWordClassify(pFW);
return ((wk != COLON) && (wk != DOES));
}
#endif
#define nSEARCH_CELLS 100
static FICL_WORD *findEnclosingWord(FICL_VM *pVM, CELL *cp)
{
FICL_WORD *pFW;
FICL_DICT *pd = vmGetDict(pVM);
int i;
if (!dictIncludes(pd, (void *)cp))
return NULL;
for (i = nSEARCH_CELLS; i > 0; --i, --cp)
{
pFW = (FICL_WORD *)(cp + 1 - (sizeof (FICL_WORD) / sizeof (CELL)));
if (isAFiclWord(pd, pFW))
return pFW;
}
return NULL;
}
static void seeColon(FICL_VM *pVM, CELL *pc)
{
char *cp;
CELL *param0 = pc;
FICL_DICT *pd = vmGetDict(pVM);
FICL_WORD *pSemiParen = ficlLookup(pVM->pSys, "(;)");
assert(pSemiParen);
for (; pc->p != pSemiParen; pc++)
{
FICL_WORD *pFW = (FICL_WORD *)(pc->p);
cp = pVM->pad;
if ((void *)pc == (void *)pVM->ip)
*cp++ = '>';
else
*cp++ = ' ';
cp += sprintf(cp, "%3d ", (int)(pc-param0));
if (isAFiclWord(pd, pFW))
{
WORDKIND kind = ficlWordClassify(pFW);
CELL c;
switch (kind)
{
case LITERAL:
c = *++pc;
if (isAFiclWord(pd, c.p))
{
FICL_WORD *pLit = (FICL_WORD *)c.p;
sprintf(cp, "%.*s ( %#lx literal )",
pLit->nName, pLit->name, (unsigned long)c.u);
}
else
sprintf(cp, "literal %ld (%#lx)",
(long)c.i, (unsigned long)c.u);
break;
case STRINGLIT:
{
FICL_STRING *sp = (FICL_STRING *)(void *)++pc;
pc = (CELL *)alignPtr(sp->text + sp->count + 1) - 1;
sprintf(cp, "s\" %.*s\"", sp->count, sp->text);
}
break;
case CSTRINGLIT:
{
FICL_STRING *sp = (FICL_STRING *)(void *)++pc;
pc = (CELL *)alignPtr(sp->text + sp->count + 1) - 1;
sprintf(cp, "c\" %.*s\"", sp->count, sp->text);
}
break;
case IF:
c = *++pc;
if (c.i > 0)
sprintf(cp, "if / while (branch %d)", (int)(pc+c.i-param0));
else
sprintf(cp, "until (branch %d)", (int)(pc+c.i-param0));
break;
case BRANCH:
c = *++pc;
if (c.i == 0)
sprintf(cp, "repeat (branch %d)", (int)(pc+c.i-param0));
else if (c.i == 1)
sprintf(cp, "else (branch %d)", (int)(pc+c.i-param0));
else
sprintf(cp, "endof (branch %d)", (int)(pc+c.i-param0));
break;
case OF:
c = *++pc;
sprintf(cp, "of (branch %d)", (int)(pc+c.i-param0));
break;
case QDO:
c = *++pc;
sprintf(cp, "?do (leave %d)", (int)((CELL *)c.p-param0));
break;
case DO:
c = *++pc;
sprintf(cp, "do (leave %d)", (int)((CELL *)c.p-param0));
break;
case LOOP:
c = *++pc;
sprintf(cp, "loop (branch %d)", (int)(pc+c.i-param0));
break;
case PLOOP:
c = *++pc;
sprintf(cp, "+loop (branch %d)", (int)(pc+c.i-param0));
break;
default:
sprintf(cp, "%.*s", pFW->nName, pFW->name);
break;
}
}
else
{
sprintf(cp, "%ld ( %#lx )", (long)pc->i, (unsigned long)pc->u);
}
vmTextOut(pVM, pVM->pad, 1);
}
vmTextOut(pVM, ";", 1);
}
static void seeXT(FICL_VM *pVM)
{
FICL_WORD *pFW;
WORDKIND kind;
pFW = (FICL_WORD *)stackPopPtr(pVM->pStack);
kind = ficlWordClassify(pFW);
switch (kind)
{
case COLON:
sprintf(pVM->pad, ": %.*s", pFW->nName, pFW->name);
vmTextOut(pVM, pVM->pad, 1);
seeColon(pVM, pFW->param);
break;
case DOES:
vmTextOut(pVM, "does>", 1);
seeColon(pVM, (CELL *)pFW->param->p);
break;
case CREATE:
vmTextOut(pVM, "create", 1);
break;
case VARIABLE:
sprintf(pVM->pad, "variable = %ld (%#lx)",
(long)pFW->param->i, (unsigned long)pFW->param->u);
vmTextOut(pVM, pVM->pad, 1);
break;
#if FICL_WANT_USER
case USER:
sprintf(pVM->pad, "user variable %ld (%#lx)",
(long)pFW->param->i, (unsigned long)pFW->param->u);
vmTextOut(pVM, pVM->pad, 1);
break;
#endif
case CONSTANT:
sprintf(pVM->pad, "constant = %ld (%#lx)",
(long)pFW->param->i, (unsigned long)pFW->param->u);
vmTextOut(pVM, pVM->pad, 1);
default:
sprintf(pVM->pad, "%.*s is a primitive", pFW->nName, pFW->name);
vmTextOut(pVM, pVM->pad, 1);
break;
}
if (pFW->flags & FW_IMMEDIATE)
{
vmTextOut(pVM, "immediate", 1);
}
if (pFW->flags & FW_COMPILE)
{
vmTextOut(pVM, "compile-only", 1);
}
return;
}
static void see(FICL_VM *pVM)
{
ficlTick(pVM);
seeXT(pVM);
return;
}
void ficlDebugXT(FICL_VM *pVM)
{
FICL_WORD *xt = stackPopPtr(pVM->pStack);
WORDKIND wk = ficlWordClassify(xt);
stackPushPtr(pVM->pStack, xt);
seeXT(pVM);
switch (wk)
{
case COLON:
case DOES:
vmExecute(pVM, xt);
vmSetBreak(pVM, &(pVM->pSys->bpStep));
break;
default:
vmExecute(pVM, xt);
break;
}
return;
}
void stepIn(FICL_VM *pVM)
{
{
M_VM_STEP(pVM)
}
vmSetBreak(pVM, &(pVM->pSys->bpStep));
return;
}
void stepOver(FICL_VM *pVM)
{
FICL_WORD *pFW;
WORDKIND kind;
FICL_WORD *pStep = ficlLookup(pVM->pSys, "step-break");
assert(pStep);
pFW = *pVM->ip;
kind = ficlWordClassify(pFW);
switch (kind)
{
case COLON:
case DOES:
pVM->pSys->bpStep.address = pVM->ip + 1;
pVM->pSys->bpStep.origXT = pVM->ip[1];
pVM->ip[1] = pStep;
break;
default:
stepIn(pVM);
break;
}
return;
}
void stepBreak(FICL_VM *pVM)
{
STRINGINFO si;
FICL_WORD *pFW;
FICL_WORD *pOnStep;
if (!pVM->fRestart)
{
assert(pVM->pSys->bpStep.address);
assert(pVM->pSys->bpStep.origXT);
pVM->ip = (IPTYPE)(pVM->pSys->bpStep.address);
*pVM->ip = pVM->pSys->bpStep.origXT;
pOnStep = ficlLookup(pVM->pSys, "on-step");
if (pOnStep)
ficlExecXT(pVM, pOnStep);
pFW = pVM->pSys->bpStep.origXT;
sprintf(pVM->pad, "next: %.*s", pFW->nName, pFW->name);
#if 0
if (isPrimitive(pFW))
{
strcat(pVM->pad, " ( primitive )");
}
#endif
vmTextOut(pVM, pVM->pad, 1);
debugPrompt(pVM);
}
else
{
pVM->fRestart = 0;
}
si = vmGetWord(pVM);
if (!strincmp(si.cp, "i", si.count))
{
stepIn(pVM);
}
else if (!strincmp(si.cp, "g", si.count))
{
return;
}
else if (!strincmp(si.cp, "l", si.count))
{
FICL_WORD *xt;
xt = findEnclosingWord(pVM, (CELL *)(pVM->ip));
if (xt)
{
stackPushPtr(pVM->pStack, xt);
seeXT(pVM);
}
else
{
vmTextOut(pVM, "sorry - can't do that", 1);
}
vmThrow(pVM, VM_RESTART);
}
else if (!strincmp(si.cp, "o", si.count))
{
stepOver(pVM);
}
else if (!strincmp(si.cp, "q", si.count))
{
ficlTextOut(pVM, FICL_PROMPT, 0);
vmThrow(pVM, VM_ABORT);
}
else if (!strincmp(si.cp, "x", si.count))
{
int ret;
char *cp = pVM->tib.cp + pVM->tib.index;
int count = pVM->tib.end - cp;
FICL_WORD *oldRun = pVM->runningWord;
ret = ficlExecC(pVM, cp, count);
if (ret == VM_OUTOFTEXT)
{
ret = VM_RESTART;
pVM->runningWord = oldRun;
vmTextOut(pVM, "", 1);
}
vmThrow(pVM, ret);
}
else
{
vmTextOut(pVM, "i -- step In", 1);
vmTextOut(pVM, "o -- step Over", 1);
vmTextOut(pVM, "g -- Go (execute to completion)", 1);
vmTextOut(pVM, "l -- List source code", 1);
vmTextOut(pVM, "q -- Quit (stop debugging and abort)", 1);
vmTextOut(pVM, "x -- eXecute the rest of the line as ficl words", 1);
debugPrompt(pVM);
vmThrow(pVM, VM_RESTART);
}
return;
}
static void bye(FICL_VM *pVM)
{
vmThrow(pVM, VM_USEREXIT);
return;
}
static void displayPStack(FICL_VM *pVM)
{
FICL_STACK *pStk = pVM->pStack;
int d = stackDepth(pStk);
int i;
CELL *pCell;
vmCheckStack(pVM, 0, 0);
if (d == 0)
vmTextOut(pVM, "(Stack Empty) ", 0);
else
{
pCell = pStk->base;
for (i = 0; i < d; i++)
{
vmTextOut(pVM, ltoa((*pCell++).i, pVM->pad, pVM->base), 0);
vmTextOut(pVM, " ", 0);
}
}
return;
}
static void displayRStack(FICL_VM *pVM)
{
FICL_STACK *pStk = pVM->rStack;
int d = stackDepth(pStk);
int i;
CELL *pCell;
FICL_DICT *dp = vmGetDict(pVM);
vmCheckStack(pVM, 0, 0);
if (d == 0)
vmTextOut(pVM, "(Stack Empty) ", 0);
else
{
pCell = pStk->base;
for (i = 0; i < d; i++)
{
CELL c = *pCell++;
if (dictIncludes(dp, c.p))
{
FICL_WORD *pFW = findEnclosingWord(pVM, c.p);
if (pFW)
{
int offset = (CELL *)c.p - &pFW->param[0];
sprintf(pVM->pad, "%s+%d ", pFW->name, offset);
vmTextOut(pVM, pVM->pad, 0);
continue;
}
}
vmTextOut(pVM, ltoa(c.i, pVM->pad, pVM->base), 0);
vmTextOut(pVM, " ", 0);
}
}
return;
}
static void forgetWid(FICL_VM *pVM)
{
FICL_DICT *pDict = vmGetDict(pVM);
FICL_HASH *pHash;
pHash = (FICL_HASH *)stackPopPtr(pVM->pStack);
hashForget(pHash, pDict->here);
return;
}
static void forget(FICL_VM *pVM)
{
void *where;
FICL_DICT *pDict = vmGetDict(pVM);
FICL_HASH *pHash = pDict->pCompile;
ficlTick(pVM);
where = ((FICL_WORD *)stackPopPtr(pVM->pStack))->name;
hashForget(pHash, where);
pDict->here = PTRtoCELL where;
return;
}
#define nCOLWIDTH 8
static void listWords(FICL_VM *pVM)
{
FICL_DICT *dp = vmGetDict(pVM);
FICL_HASH *pHash = dp->pSearch[dp->nLists - 1];
FICL_WORD *wp;
int nChars = 0;
int len;
int y = 0;
unsigned i;
int nWords = 0;
char *cp;
char *pPad = pVM->pad;
for (i = 0; i < pHash->size; i++)
{
for (wp = pHash->table[i]; wp != NULL; wp = wp->link, nWords++)
{
if (wp->nName == 0)
continue;
cp = wp->name;
nChars += sprintf(pPad + nChars, "%s", cp);
if (nChars > 70)
{
pPad[nChars] = '\0';
nChars = 0;
y++;
if(y>23) {
y=0;
vmTextOut(pVM, "--- Press Enter to continue ---",0);
getchar();
vmTextOut(pVM,"\r",0);
}
vmTextOut(pVM, pPad, 1);
}
else
{
len = nCOLWIDTH - nChars % nCOLWIDTH;
while (len-- > 0)
pPad[nChars++] = ' ';
}
if (nChars > 70)
{
pPad[nChars] = '\0';
nChars = 0;
y++;
if(y>23) {
y=0;
vmTextOut(pVM, "--- Press Enter to continue ---",0);
getchar();
vmTextOut(pVM,"\r",0);
}
vmTextOut(pVM, pPad, 1);
}
}
}
if (nChars > 0)
{
pPad[nChars] = '\0';
nChars = 0;
vmTextOut(pVM, pPad, 1);
}
sprintf(pVM->pad, "Dictionary: %d words, %ld cells used of %u total",
nWords, (long) (dp->here - dp->dict), dp->size);
vmTextOut(pVM, pVM->pad, 1);
return;
}
static void listEnv(FICL_VM *pVM)
{
FICL_DICT *dp = pVM->pSys->envp;
FICL_HASH *pHash = dp->pForthWords;
FICL_WORD *wp;
unsigned i;
int nWords = 0;
for (i = 0; i < pHash->size; i++)
{
for (wp = pHash->table[i]; wp != NULL; wp = wp->link, nWords++)
{
vmTextOut(pVM, wp->name, 1);
}
}
sprintf(pVM->pad, "Environment: %d words, %ld cells used of %u total",
nWords, (long) (dp->here - dp->dict), dp->size);
vmTextOut(pVM, pVM->pad, 1);
return;
}
static void envConstant(FICL_VM *pVM)
{
unsigned value;
#if FICL_ROBUST > 1
vmCheckStack(pVM, 1, 0);
#endif
vmGetWordToPad(pVM);
value = POPUNS();
ficlSetEnv(pVM->pSys, pVM->pad, (FICL_UNS)value);
return;
}
static void env2Constant(FICL_VM *pVM)
{
unsigned v1, v2;
#if FICL_ROBUST > 1
vmCheckStack(pVM, 2, 0);
#endif
vmGetWordToPad(pVM);
v2 = POPUNS();
v1 = POPUNS();
ficlSetEnvD(pVM->pSys, pVM->pad, v1, v2);
return;
}
void ficlCompileTools(FICL_SYSTEM *pSys)
{
FICL_DICT *dp = pSys->dp;
assert (dp);
dictAppendWord(dp, ".s", displayPStack, FW_DEFAULT);
dictAppendWord(dp, "bye", bye, FW_DEFAULT);
dictAppendWord(dp, "forget", forget, FW_DEFAULT);
dictAppendWord(dp, "see", see, FW_DEFAULT);
dictAppendWord(dp, "words", listWords, FW_DEFAULT);
ficlSetEnv(pSys, "tools", FICL_TRUE);
ficlSetEnv(pSys, "tools-ext", FICL_FALSE);
dictAppendWord(dp, "r.s", displayRStack, FW_DEFAULT);
dictAppendWord(dp, ".env", listEnv, FW_DEFAULT);
dictAppendWord(dp, "env-constant",
envConstant, FW_DEFAULT);
dictAppendWord(dp, "env-2constant",
env2Constant, FW_DEFAULT);
dictAppendWord(dp, "debug-xt", ficlDebugXT, FW_DEFAULT);
dictAppendWord(dp, "parse-order",
ficlListParseSteps,
FW_DEFAULT);
dictAppendWord(dp, "step-break",stepBreak, FW_DEFAULT);
dictAppendWord(dp, "forget-wid",forgetWid, FW_DEFAULT);
dictAppendWord(dp, "see-xt", seeXT, FW_DEFAULT);
return;
}