home: hub: 9ficl

Download patch

ref: b2efd53776f2279045f42a2a95467b47f33da01c
parent: 7995ea0d43c8e024add6708416bbd7b4c94c8804
author: jsadler <jsadler@ficl.sf.net>
date: Wed Jul 12 01:44:19 CDT 2000

*** empty log message ***

binary files /dev/null b/doc/sigplan9906.doc differ
binary files /dev/null b/doc/skey.gif differ
--- /dev/null
+++ b/tools.c.bak
@@ -1,0 +1,519 @@
+/*******************************************************************
+** t o o l s . c
+** Forth Inspired Command Language - programming tools
+** Author: John Sadler (john_sadler@alum.mit.edu)
+** Created: 20 June 2000
+** $Id: tools.c.bak,v 1.0 2000/07/12 06:44:17 jsadler Exp $
+*******************************************************************/
+/*
+** NOTES:
+** SEE needs information about the addresses of functions that
+** are the CFAs of colon definitions, constants, variables, DOES>
+** words, and so on. It gets this information from a table and supporting
+** functions in words.c.
+** colonParen doDoes createParen variableParen userParen constantParen
+**
+** Step and break debugger for Ficl
+** The debugger requies real implementations of KEY and ACCEPT
+** because it bypasses the normal VM return mechanism for getting 
+** text??
+** debug  ( xt -- )   Start debugging an xt
+** Set a breakpoint
+** Specify breakpoint default action
+*/
+
+#include <stdlib.h>
+#include <stdio.h>          /* sprintf */
+#include <string.h>
+#include <ctype.h>
+#include "ficl.h"
+
+
+/*
+** nBREAKPOINTS sizes the breakpoint array. One breakpoint (bp 0) is reserved
+** for the STEP command. The rest are user programmable. 
+*/
+#define nBREAKPOINTS 10
+
+/*
+** BREAKPOINT record.
+** origXT - if NULL, this breakpoint is unused. Otherwise it stores the xt 
+** that the breakpoint overwrote. This is restored to the dictionary when the
+** BP executes or gets cleared
+*/
+typedef struct breakpoint
+{
+	FICL_WORD *origXT;
+	FICL_WORD *onBreak;
+} BREAKPOINT;
+
+static BREAKPOINT bpTable[nBREAKPOINTS];
+static FICL_WORD *pBreak = NULL;
+
+/**************************************************************************
+                        i n i t T o o l s
+** Initializes static variables of this file, including:
+** 1. The lookup table of control structure XTs used by isDebuggable and
+** see
+** 2. The breakpoint table
+** This routine MUST execute AFTER the core dictionary is successfully
+** built, and AFTER debug words are inserted into the dictionary, but
+** BEFORE any use of the debugger.
+**************************************************************************/
+static void initTools(FICL_VM *pVM)
+{
+    FICL_DICT *dp = ficlGetDict();
+	&pVM;
+
+    return;	
+}
+
+
+
+/**************************************************************************
+                        s e e 
+** TOOLS ( "<spaces>name" -- )
+** Display a human-readable representation of the named word's definition.
+** The source of the representation (object-code decompilation, source
+** block, etc.) and the particular form of the display is implementation
+** defined. 
+** NOTE: these funcs come late in the file because they reference all
+** of the word-builder funcs without declaring them again. Call me lazy.
+**************************************************************************/
+/*
+** isAFiclWord
+** Vet a candidate pointer carefully to make sure
+** it's not some chunk o' inline data...
+** It has to have a name, and it has to look
+** like it's in the dictionary address range.
+** NOTE: this excludes :noname words!
+*/
+static int isAFiclWord(FICL_WORD *pFW)
+{
+    FICL_DICT *pd  = ficlGetDict();
+
+    if (!dictIncludes(pd, pFW))
+       return 0;
+
+    if (!dictIncludes(pd, pFW->name))
+        return 0;
+
+    return ((pFW->nName > 0) && (pFW->name[pFW->nName] == '\0'));
+}
+
+/*
+** seeColon (for proctologists only)
+** Walks a colon definition, decompiling
+** on the fly. Knows about primitive control structures.
+*/
+static void seeColon(FICL_VM *pVM, CELL *pc)
+{
+    static FICL_WORD *pSemiParen = NULL;
+
+	if (!pSemiParen)
+		pSemiParen = ficlLookup("(;)");
+	assert(pSemiParen);
+
+    for (; pc->p != pSemiParen; pc++)
+    {
+        FICL_WORD *pFW = (FICL_WORD *)(pc->p);
+
+        if (isAFiclWord(pFW))
+        {
+			WORDKIND kind = ficlWordClassify(pFW);
+			CELL c;
+
+			switch (kind)
+			{
+			case LITERAL:
+				c = *++pc;
+				if (isAFiclWord(c.p))
+				{
+					FICL_WORD *pLit = (FICL_WORD *)c.p;
+					sprintf(pVM->pad, "    literal %.*s (%#lx)", 
+						pLit->nName, pLit->name, c.u);
+				}
+				else
+					sprintf(pVM->pad, "    literal %ld (%#lx)", c.i, c.u);
+				break;
+            case STRINGLIT:
+				{
+					FICL_STRING *sp = (FICL_STRING *)(void *)++pc;
+					pc = (CELL *)alignPtr(sp->text + sp->count + 1) - 1;
+					sprintf(pVM->pad, "    s\" %.*s\"", sp->count, sp->text);
+				}
+				break;
+			case IF:
+				c = *++pc;
+				if (c.i > 0)
+					sprintf(pVM->pad, "    if / while (branch rel %ld)", c.i);
+				else
+					sprintf(pVM->pad, "    until (branch rel %ld)", c.i);
+				break;
+			case BRANCH:
+				c = *++pc;
+				if (c.i > 0)
+					sprintf(pVM->pad, "    else (branch rel %ld)", c.i);
+				else
+					sprintf(pVM->pad, "    repeat (branch rel %ld)", c.i);
+				break;
+
+			case QDO:
+				c = *++pc;
+				sprintf(pVM->pad, "    ?do (leave abs %#lx)", c.u);
+				break;
+			case DO:
+				c = *++pc;
+				sprintf(pVM->pad, "    do (leave abs %#lx)", c.u);
+				break;
+            case LOOP:
+				c = *++pc;
+				sprintf(pVM->pad, "    loop (branch rel %#ld)", c.i);
+				break;
+			case PLOOP:
+				c = *++pc;
+				sprintf(pVM->pad, "    +loop (branch rel %#ld)", c.i);
+				break;
+			default:
+                sprintf(pVM->pad, "    %.*s", pFW->nName, pFW->name);
+				break;
+            }
+ 
+            vmTextOut(pVM, pVM->pad, 1);
+        }
+        else /* probably not a word - punt and print value */
+        {
+            sprintf(pVM->pad, "    %ld (%#lx)", pc->i, pc->u);
+            vmTextOut(pVM, pVM->pad, 1);
+        }
+    }
+
+    vmTextOut(pVM, ";", 1);
+}
+
+/*
+** Here's the outer part of the decompiler. It's 
+** just a big nested conditional that checks the
+** CFA of the word to decompile for each kind of
+** known word-builder code, and tries to do 
+** something appropriate. If the CFA is not recognized,
+** just indicate that it is a primitive.
+*/
+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)", pFW->param->i, pFW->param->u);
+        vmTextOut(pVM, pVM->pad, 1);
+		break;
+
+	case USER:
+        sprintf(pVM->pad, "user variable %ld (%#lx)", pFW->param->i, pFW->param->u);
+        vmTextOut(pVM, pVM->pad, 1);
+		break;
+
+	case CONSTANT:
+        sprintf(pVM->pad, "constant = %ld (%#lx)", pFW->param->i, pFW->param->u);
+        vmTextOut(pVM, pVM->pad, 1);
+
+	default:
+        vmTextOut(pVM, "primitive", 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;
+}
+
+
+/**************************************************************************
+                        f i c l D e b u g
+** debug  ( xt -- )
+** Given an xt of a colon definition or a word defined by DOES>, set the
+** VM up to debug the word: push IP, set the xt as the next thing to execute,
+** set a breakpoint at its first instruction, and run to the breakpoint.
+**************************************************************************/
+void ficlDebug(FICL_VM *pVM)
+{
+	int ret;
+	FICL_WORD *xt = stackPopPtr(pVM->pStack);
+    assert(pBreak);
+
+	if (ficlWordIsDebuggable(xt))
+	{
+		stackPushPtr(pVM, xt);
+		seeXT(pVM);
+		/*
+		** Set a breakpoint at the first instruction and run the word
+		*/
+        
+	    ret = ficlExecXT(pVM, xt);
+	}
+	else
+	{
+		ficlTextOut(pVM, "primitive - cannot debug", 1);
+	}
+
+    return;
+}
+
+
+
+/**************************************************************************
+                        d e b u g - b r e a k
+** FICL
+** Throws a breakpoint exception - used by DEBUG to step and break.
+**************************************************************************/
+void debugBreak(FICL_VM *pVM)
+{
+	vmThrow(pVM, VM_BREAK);
+	return;
+}
+
+
+/**************************************************************************
+                        b y e
+** TOOLS
+** Signal the system to shut down - this causes ficlExec to return
+** VM_USEREXIT. The rest is up to you.
+**************************************************************************/
+
+static void bye(FICL_VM *pVM)
+{
+    vmThrow(pVM, VM_USEREXIT);
+    return;
+}
+
+
+/**************************************************************************
+                        d i s p l a y S t a c k
+** TOOLS 
+** Display the parameter stack (code for ".s")
+**************************************************************************/
+
+static void displayStack(FICL_VM *pVM)
+{
+    int d = stackDepth(pVM->pStack);
+    int i;
+    CELL *pCell;
+
+    vmCheckStack(pVM, 0, 0);
+
+    if (d == 0)
+        vmTextOut(pVM, "(Stack Empty) ", 0);
+    else
+    {
+        pCell = pVM->pStack->base;
+        for (i = 0; i < d; i++)
+        {
+            vmTextOut(pVM, ltoa((*pCell++).i, pVM->pad, pVM->base), 0);
+            vmTextOut(pVM, " ", 0);
+        }
+    }
+}
+
+
+/**************************************************************************
+                        f o r g e t
+** TOOLS EXT  ( "<spaces>name" -- )
+** Skip leading space delimiters. Parse name delimited by a space.
+** Find name, then delete name from the dictionary along with all
+** words added to the dictionary after name. An ambiguous
+** condition exists if name cannot be found. 
+** 
+** If the Search-Order word set is present, FORGET searches the
+** compilation word list. An ambiguous condition exists if the
+** compilation word list is deleted. 
+**************************************************************************/
+static void forgetWid(FICL_VM *pVM)
+{
+    FICL_DICT *pDict = ficlGetDict();
+    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 = ficlGetDict();
+    FICL_HASH *pHash = pDict->pCompile;
+
+    ficlTick(pVM);
+    where = ((FICL_WORD *)stackPopPtr(pVM->pStack))->name;
+    hashForget(pHash, where);
+    pDict->here = PTRtoCELL where;
+
+    return;
+}
+
+
+/**************************************************************************
+                        l i s t W o r d s
+** 
+**************************************************************************/
+#define nCOLWIDTH 8
+static void listWords(FICL_VM *pVM)
+{
+    FICL_DICT *dp = ficlGetDict();
+    FICL_HASH *pHash = dp->pSearch[dp->nLists - 1];
+    FICL_WORD *wp;
+    int nChars = 0;
+    int len;
+    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) /* ignore :noname defs */
+                continue;
+
+            cp = wp->name;
+            nChars += sprintf(pPad + nChars, "%s", cp);
+
+            if (nChars > 70)
+            {
+                pPad[nChars] = '\0';
+                nChars = 0;
+                vmTextOut(pVM, pPad, 1);
+            }
+            else
+            {
+                len = nCOLWIDTH - nChars % nCOLWIDTH;
+                while (len-- > 0)
+                    pPad[nChars++] = ' ';
+            }
+
+            if (nChars > 70)
+            {
+                pPad[nChars] = '\0';
+                nChars = 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;
+}
+
+
+/**************************************************************************
+                        l i s t E n v
+** 
+**************************************************************************/
+static void listEnv(FICL_VM *pVM)
+{
+    FICL_DICT *dp = ficlGetEnv();
+    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;
+}
+
+
+/**************************************************************************
+                        f i c l C o m p i l e T o o l s
+** Builds wordset for debugger and TOOLS optional word set
+**************************************************************************/
+
+void ficlCompileTools(FICL_DICT *dp)
+{
+    assert (dp);
+
+    /*
+    ** TOOLS and TOOLS EXT
+    */
+    dictAppendWord(dp, ".s",        displayStack,   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);
+
+    /*
+    ** Set TOOLS environment query values
+    */
+    ficlSetEnv("tools",            FICL_TRUE);
+    ficlSetEnv("tools-ext",        FICL_FALSE);
+
+    /*
+    ** Ficl extras
+    */
+    dictAppendWord(dp, ".env",      listEnv,        FW_DEFAULT);
+    dictAppendWord(dp, "debug",     ficlDebug,      FW_DEFAULT);
+	pBreak = 
+    dictAppendWord(dp, "debug-break",debugBreak,    FW_DEFAULT);
+    dictAppendWord(dp, "forget-wid",forgetWid,      FW_DEFAULT);
+    dictAppendWord(dp, "see-xt",    seeXT,          FW_DEFAULT);
+    return;
+}
+