Resync patch with contrib.
[dragonfly.git] / sys / boot / ficl / tools.c
blob2c713eec4403754e7ed682b795a1e6d3b8ae8ce3
1 /*******************************************************************
2 ** t o o l s . c
3 ** Forth Inspired Command Language - programming tools
4 ** Author: John Sadler (john_sadler@alum.mit.edu)
5 ** Created: 20 June 2000
6 ** $Id: tools.c,v 1.11 2001/12/05 07:21:34 jsadler Exp $
7 *******************************************************************/
8 /*
9 ** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu)
10 ** All rights reserved.
12 ** Get the latest Ficl release at http://ficl.sourceforge.net
14 ** I am interested in hearing from anyone who uses ficl. If you have
15 ** a problem, a success story, a defect, an enhancement request, or
16 ** if you would like to contribute to the ficl release, please
17 ** contact me by email at the address above.
19 ** L I C E N S E and D I S C L A I M E R
20 **
21 ** Redistribution and use in source and binary forms, with or without
22 ** modification, are permitted provided that the following conditions
23 ** are met:
24 ** 1. Redistributions of source code must retain the above copyright
25 ** notice, this list of conditions and the following disclaimer.
26 ** 2. Redistributions in binary form must reproduce the above copyright
27 ** notice, this list of conditions and the following disclaimer in the
28 ** documentation and/or other materials provided with the distribution.
30 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
31 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
34 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 ** SUCH DAMAGE.
44 ** NOTES:
45 ** SEE needs information about the addresses of functions that
46 ** are the CFAs of colon definitions, constants, variables, DOES>
47 ** words, and so on. It gets this information from a table and supporting
48 ** functions in words.c.
49 ** colonParen doDoes createParen variableParen userParen constantParen
51 ** Step and break debugger for Ficl
52 ** debug ( xt -- ) Start debugging an xt
53 ** Set a breakpoint
54 ** Specify breakpoint default action
58 * $FreeBSD: src/sys/boot/ficl/tools.c,v 1.2 2002/04/09 17:45:11 dcs Exp $
59 * $DragonFly: src/sys/boot/ficl/tools.c,v 1.1 2003/11/10 06:08:33 dillon Exp $
61 #ifdef TESTMAIN
62 #include <stdlib.h>
63 #include <stdio.h> /* sprintf */
64 #include <ctype.h>
65 #else
66 #include <stand.h>
67 #endif
68 #include <string.h>
69 #include "ficl.h"
72 #if 0
74 ** nBREAKPOINTS sizes the breakpoint array. One breakpoint (bp 0) is reserved
75 ** for the STEP command. The rest are user programmable.
77 #define nBREAKPOINTS 32
79 #endif
82 /**************************************************************************
83 v m S e t B r e a k
84 ** Set a breakpoint at the current value of IP by
85 ** storing that address in a BREAKPOINT record
86 **************************************************************************/
87 static void vmSetBreak(FICL_VM *pVM, FICL_BREAKPOINT *pBP)
89 FICL_WORD *pStep = ficlLookup(pVM->pSys, "step-break");
90 assert(pStep);
92 pBP->address = pVM->ip;
93 pBP->origXT = *pVM->ip;
94 *pVM->ip = pStep;
98 /**************************************************************************
99 ** d e b u g P r o m p t
100 **************************************************************************/
101 static void debugPrompt(FICL_VM *pVM)
103 vmTextOut(pVM, "dbg> ", 0);
107 /**************************************************************************
108 ** i s A F i c l W o r d
109 ** Vet a candidate pointer carefully to make sure
110 ** it's not some chunk o' inline data...
111 ** It has to have a name, and it has to look
112 ** like it's in the dictionary address range.
113 ** NOTE: this excludes :noname words!
114 **************************************************************************/
115 int isAFiclWord(FICL_DICT *pd, FICL_WORD *pFW)
118 if (!dictIncludes(pd, pFW))
119 return 0;
121 if (!dictIncludes(pd, pFW->name))
122 return 0;
124 if ((pFW->link != NULL) && !dictIncludes(pd, pFW->link))
125 return 0;
127 if ((pFW->nName <= 0) || (pFW->name[pFW->nName] != '\0'))
128 return 0;
130 if (strlen(pFW->name) != pFW->nName)
131 return 0;
133 return 1;
137 #if 0
138 static int isPrimitive(FICL_WORD *pFW)
140 WORDKIND wk = ficlWordClassify(pFW);
141 return ((wk != COLON) && (wk != DOES));
143 #endif
146 /**************************************************************************
147 f i n d E n c l o s i n g W o r d
148 ** Given a pointer to something, check to make sure it's an address in the
149 ** dictionary. If so, search backwards until we find something that looks
150 ** like a dictionary header. If successful, return the address of the
151 ** FICL_WORD found. Otherwise return NULL.
152 ** nSEARCH_CELLS sets the maximum neighborhood this func will search before giving up
153 **************************************************************************/
154 #define nSEARCH_CELLS 100
156 static FICL_WORD *findEnclosingWord(FICL_VM *pVM, CELL *cp)
158 FICL_WORD *pFW;
159 FICL_DICT *pd = vmGetDict(pVM);
160 int i;
162 if (!dictIncludes(pd, (void *)cp))
163 return NULL;
165 for (i = nSEARCH_CELLS; i > 0; --i, --cp)
167 pFW = (FICL_WORD *)(cp + 1 - (sizeof (FICL_WORD) / sizeof (CELL)));
168 if (isAFiclWord(pd, pFW))
169 return pFW;
172 return NULL;
176 /**************************************************************************
177 s e e
178 ** TOOLS ( "<spaces>name" -- )
179 ** Display a human-readable representation of the named word's definition.
180 ** The source of the representation (object-code decompilation, source
181 ** block, etc.) and the particular form of the display is implementation
182 ** defined.
183 **************************************************************************/
185 ** seeColon (for proctologists only)
186 ** Walks a colon definition, decompiling
187 ** on the fly. Knows about primitive control structures.
189 static void seeColon(FICL_VM *pVM, CELL *pc)
191 char *cp;
192 CELL *param0 = pc;
193 FICL_DICT *pd = vmGetDict(pVM);
194 FICL_WORD *pSemiParen = ficlLookup(pVM->pSys, "(;)");
195 assert(pSemiParen);
197 for (; pc->p != pSemiParen; pc++)
199 FICL_WORD *pFW = (FICL_WORD *)(pc->p);
201 cp = pVM->pad;
202 if ((void *)pc == (void *)pVM->ip)
203 *cp++ = '>';
204 else
205 *cp++ = ' ';
206 cp += sprintf(cp, "%3d ", pc-param0);
208 if (isAFiclWord(pd, pFW))
210 WORDKIND kind = ficlWordClassify(pFW);
211 CELL c;
213 switch (kind)
215 case LITERAL:
216 c = *++pc;
217 if (isAFiclWord(pd, c.p))
219 FICL_WORD *pLit = (FICL_WORD *)c.p;
220 sprintf(cp, "%.*s ( %#lx literal )",
221 pLit->nName, pLit->name, c.u);
223 else
224 sprintf(cp, "literal %ld (%#lx)", c.i, c.u);
225 break;
226 case STRINGLIT:
228 FICL_STRING *sp = (FICL_STRING *)(void *)++pc;
229 pc = (CELL *)alignPtr(sp->text + sp->count + 1) - 1;
230 sprintf(cp, "s\" %.*s\"", sp->count, sp->text);
232 break;
233 case CSTRINGLIT:
235 FICL_STRING *sp = (FICL_STRING *)(void *)++pc;
236 pc = (CELL *)alignPtr(sp->text + sp->count + 1) - 1;
237 sprintf(cp, "c\" %.*s\"", sp->count, sp->text);
239 break;
240 case IF:
241 c = *++pc;
242 if (c.i > 0)
243 sprintf(cp, "if / while (branch %d)", pc+c.i-param0);
244 else
245 sprintf(cp, "until (branch %d)", pc+c.i-param0);
246 break;
247 case BRANCH:
248 c = *++pc;
249 if (c.i > 0)
250 sprintf(cp, "else (branch %d)", pc+c.i-param0);
251 else
252 sprintf(cp, "repeat (branch %d)", pc+c.i-param0);
253 break;
255 case QDO:
256 c = *++pc;
257 sprintf(cp, "?do (leave %d)", (CELL *)c.p-param0);
258 break;
259 case DO:
260 c = *++pc;
261 sprintf(cp, "do (leave %d)", (CELL *)c.p-param0);
262 break;
263 case LOOP:
264 c = *++pc;
265 sprintf(cp, "loop (branch %d)", pc+c.i-param0);
266 break;
267 case PLOOP:
268 c = *++pc;
269 sprintf(cp, "+loop (branch %d)", pc+c.i-param0);
270 break;
271 default:
272 sprintf(cp, "%.*s", pFW->nName, pFW->name);
273 break;
277 else /* probably not a word - punt and print value */
279 sprintf(cp, "%ld ( %#lx )", pc->i, pc->u);
282 vmTextOut(pVM, pVM->pad, 1);
285 vmTextOut(pVM, ";", 1);
289 ** Here's the outer part of the decompiler. It's
290 ** just a big nested conditional that checks the
291 ** CFA of the word to decompile for each kind of
292 ** known word-builder code, and tries to do
293 ** something appropriate. If the CFA is not recognized,
294 ** just indicate that it is a primitive.
296 static void seeXT(FICL_VM *pVM)
298 FICL_WORD *pFW;
299 WORDKIND kind;
301 pFW = (FICL_WORD *)stackPopPtr(pVM->pStack);
302 kind = ficlWordClassify(pFW);
304 switch (kind)
306 case COLON:
307 sprintf(pVM->pad, ": %.*s", pFW->nName, pFW->name);
308 vmTextOut(pVM, pVM->pad, 1);
309 seeColon(pVM, pFW->param);
310 break;
312 case DOES:
313 vmTextOut(pVM, "does>", 1);
314 seeColon(pVM, (CELL *)pFW->param->p);
315 break;
317 case CREATE:
318 vmTextOut(pVM, "create", 1);
319 break;
321 case VARIABLE:
322 sprintf(pVM->pad, "variable = %ld (%#lx)", pFW->param->i, pFW->param->u);
323 vmTextOut(pVM, pVM->pad, 1);
324 break;
326 #if FICL_WANT_USER
327 case USER:
328 sprintf(pVM->pad, "user variable %ld (%#lx)", pFW->param->i, pFW->param->u);
329 vmTextOut(pVM, pVM->pad, 1);
330 break;
331 #endif
333 case CONSTANT:
334 sprintf(pVM->pad, "constant = %ld (%#lx)", pFW->param->i, pFW->param->u);
335 vmTextOut(pVM, pVM->pad, 1);
337 default:
338 sprintf(pVM->pad, "%.*s is a primitive", pFW->nName, pFW->name);
339 vmTextOut(pVM, pVM->pad, 1);
340 break;
343 if (pFW->flags & FW_IMMEDIATE)
345 vmTextOut(pVM, "immediate", 1);
348 if (pFW->flags & FW_COMPILE)
350 vmTextOut(pVM, "compile-only", 1);
353 return;
357 static void see(FICL_VM *pVM)
359 ficlTick(pVM);
360 seeXT(pVM);
361 return;
365 /**************************************************************************
366 f i c l D e b u g X T
367 ** debug ( xt -- )
368 ** Given an xt of a colon definition or a word defined by DOES>, set the
369 ** VM up to debug the word: push IP, set the xt as the next thing to execute,
370 ** set a breakpoint at its first instruction, and run to the breakpoint.
371 ** Note: the semantics of this word are equivalent to "step in"
372 **************************************************************************/
373 void ficlDebugXT(FICL_VM *pVM)
375 FICL_WORD *xt = stackPopPtr(pVM->pStack);
376 WORDKIND wk = ficlWordClassify(xt);
378 stackPushPtr(pVM->pStack, xt);
379 seeXT(pVM);
381 switch (wk)
383 case COLON:
384 case DOES:
386 ** Run the colon code and set a breakpoint at the next instruction
388 vmExecute(pVM, xt);
389 vmSetBreak(pVM, &(pVM->pSys->bpStep));
390 break;
392 default:
393 vmExecute(pVM, xt);
394 break;
397 return;
401 /**************************************************************************
402 s t e p I n
403 ** FICL
404 ** Execute the next instruction, stepping into it if it's a colon definition
405 ** or a does> word. This is the easy kind of step.
406 **************************************************************************/
407 void stepIn(FICL_VM *pVM)
410 ** Do one step of the inner loop
413 M_VM_STEP(pVM)
417 ** Now set a breakpoint at the next instruction
419 vmSetBreak(pVM, &(pVM->pSys->bpStep));
421 return;
425 /**************************************************************************
426 s t e p O v e r
427 ** FICL
428 ** Execute the next instruction atomically. This requires some insight into
429 ** the memory layout of compiled code. Set a breakpoint at the next instruction
430 ** in this word, and run until we hit it
431 **************************************************************************/
432 void stepOver(FICL_VM *pVM)
434 FICL_WORD *pFW;
435 WORDKIND kind;
436 FICL_WORD *pStep = ficlLookup(pVM->pSys, "step-break");
437 assert(pStep);
439 pFW = *pVM->ip;
440 kind = ficlWordClassify(pFW);
442 switch (kind)
444 case COLON:
445 case DOES:
447 ** assume that the next cell holds an instruction
448 ** set a breakpoint there and return to the inner interp
450 pVM->pSys->bpStep.address = pVM->ip + 1;
451 pVM->pSys->bpStep.origXT = pVM->ip[1];
452 pVM->ip[1] = pStep;
453 break;
455 default:
456 stepIn(pVM);
457 break;
460 return;
464 /**************************************************************************
465 s t e p - b r e a k
466 ** FICL
467 ** Handles breakpoints for stepped execution.
468 ** Upon entry, bpStep contains the address and replaced instruction
469 ** of the current breakpoint.
470 ** Clear the breakpoint
471 ** Get a command from the console.
472 ** i (step in) - execute the current instruction and set a new breakpoint
473 ** at the IP
474 ** o (step over) - execute the current instruction to completion and set
475 ** a new breakpoint at the IP
476 ** g (go) - execute the current instruction and exit
477 ** q (quit) - abort current word
478 ** b (toggle breakpoint)
479 **************************************************************************/
480 void stepBreak(FICL_VM *pVM)
482 STRINGINFO si;
483 FICL_WORD *pFW;
484 FICL_WORD *pOnStep;
486 if (!pVM->fRestart)
488 assert(pVM->pSys->bpStep.address);
489 assert(pVM->pSys->bpStep.origXT);
491 ** Clear the breakpoint that caused me to run
492 ** Restore the original instruction at the breakpoint,
493 ** and restore the IP
495 pVM->ip = (IPTYPE)(pVM->pSys->bpStep.address);
496 *pVM->ip = pVM->pSys->bpStep.origXT;
499 ** If there's an onStep, do it
501 pOnStep = ficlLookup(pVM->pSys, "on-step");
502 if (pOnStep)
503 ficlExecXT(pVM, pOnStep);
506 ** Print the name of the next instruction
508 pFW = pVM->pSys->bpStep.origXT;
509 sprintf(pVM->pad, "next: %.*s", pFW->nName, pFW->name);
510 #if 0
511 if (isPrimitive(pFW))
513 strcat(pVM->pad, " ( primitive )");
515 #endif
517 vmTextOut(pVM, pVM->pad, 1);
518 debugPrompt(pVM);
520 else
522 pVM->fRestart = 0;
525 si = vmGetWord(pVM);
527 if (!strincmp(si.cp, "i", si.count))
529 stepIn(pVM);
531 else if (!strincmp(si.cp, "g", si.count))
533 return;
535 else if (!strincmp(si.cp, "l", si.count))
537 FICL_WORD *xt;
538 xt = findEnclosingWord(pVM, (CELL *)(pVM->ip));
539 if (xt)
541 stackPushPtr(pVM->pStack, xt);
542 seeXT(pVM);
544 else
546 vmTextOut(pVM, "sorry - can't do that", 1);
548 vmThrow(pVM, VM_RESTART);
550 else if (!strincmp(si.cp, "o", si.count))
552 stepOver(pVM);
554 else if (!strincmp(si.cp, "q", si.count))
556 ficlTextOut(pVM, FICL_PROMPT, 0);
557 vmThrow(pVM, VM_ABORT);
559 else if (!strincmp(si.cp, "x", si.count))
562 ** Take whatever's left in the TIB and feed it to a subordinate ficlExec
564 int ret;
565 char *cp = pVM->tib.cp + pVM->tib.index;
566 int count = pVM->tib.end - cp;
567 FICL_WORD *oldRun = pVM->runningWord;
569 ret = ficlExecC(pVM, cp, count);
571 if (ret == VM_OUTOFTEXT)
573 ret = VM_RESTART;
574 pVM->runningWord = oldRun;
575 vmTextOut(pVM, "", 1);
578 vmThrow(pVM, ret);
580 else
582 vmTextOut(pVM, "i -- step In", 1);
583 vmTextOut(pVM, "o -- step Over", 1);
584 vmTextOut(pVM, "g -- Go (execute to completion)", 1);
585 vmTextOut(pVM, "l -- List source code", 1);
586 vmTextOut(pVM, "q -- Quit (stop debugging and abort)", 1);
587 vmTextOut(pVM, "x -- eXecute the rest of the line as ficl words", 1);
588 debugPrompt(pVM);
589 vmThrow(pVM, VM_RESTART);
592 return;
596 /**************************************************************************
597 b y e
598 ** TOOLS
599 ** Signal the system to shut down - this causes ficlExec to return
600 ** VM_USEREXIT. The rest is up to you.
601 **************************************************************************/
602 static void bye(FICL_VM *pVM)
604 vmThrow(pVM, VM_USEREXIT);
605 return;
609 /**************************************************************************
610 d i s p l a y S t a c k
611 ** TOOLS
612 ** Display the parameter stack (code for ".s")
613 **************************************************************************/
614 static void displayPStack(FICL_VM *pVM)
616 FICL_STACK *pStk = pVM->pStack;
617 int d = stackDepth(pStk);
618 int i;
619 CELL *pCell;
621 vmCheckStack(pVM, 0, 0);
623 if (d == 0)
624 vmTextOut(pVM, "(Stack Empty) ", 0);
625 else
627 pCell = pStk->base;
628 for (i = 0; i < d; i++)
630 vmTextOut(pVM, ltoa((*pCell++).i, pVM->pad, pVM->base), 0);
631 vmTextOut(pVM, " ", 0);
634 return;
638 static void displayRStack(FICL_VM *pVM)
640 FICL_STACK *pStk = pVM->rStack;
641 int d = stackDepth(pStk);
642 int i;
643 CELL *pCell;
644 FICL_DICT *dp = vmGetDict(pVM);
646 vmCheckStack(pVM, 0, 0);
648 if (d == 0)
649 vmTextOut(pVM, "(Stack Empty) ", 0);
650 else
652 pCell = pStk->base;
653 for (i = 0; i < d; i++)
655 CELL c = *pCell++;
657 ** Attempt to find the word that contains the
658 ** stacked address (as if it is part of a colon definition).
659 ** If this works, print the name of the word. Otherwise print
660 ** the value as a number.
662 if (dictIncludes(dp, c.p))
664 FICL_WORD *pFW = findEnclosingWord(pVM, c.p);
665 if (pFW)
667 int offset = (CELL *)c.p - &pFW->param[0];
668 sprintf(pVM->pad, "%s+%d ", pFW->name, offset);
669 vmTextOut(pVM, pVM->pad, 0);
670 continue; /* no need to print the numeric value */
673 vmTextOut(pVM, ltoa(c.i, pVM->pad, pVM->base), 0);
674 vmTextOut(pVM, " ", 0);
678 return;
682 /**************************************************************************
683 f o r g e t - w i d
685 **************************************************************************/
686 static void forgetWid(FICL_VM *pVM)
688 FICL_DICT *pDict = vmGetDict(pVM);
689 FICL_HASH *pHash;
691 pHash = (FICL_HASH *)stackPopPtr(pVM->pStack);
692 hashForget(pHash, pDict->here);
694 return;
698 /**************************************************************************
699 f o r g e t
700 ** TOOLS EXT ( "<spaces>name" -- )
701 ** Skip leading space delimiters. Parse name delimited by a space.
702 ** Find name, then delete name from the dictionary along with all
703 ** words added to the dictionary after name. An ambiguous
704 ** condition exists if name cannot be found.
706 ** If the Search-Order word set is present, FORGET searches the
707 ** compilation word list. An ambiguous condition exists if the
708 ** compilation word list is deleted.
709 **************************************************************************/
710 static void forget(FICL_VM *pVM)
712 void *where;
713 FICL_DICT *pDict = vmGetDict(pVM);
714 FICL_HASH *pHash = pDict->pCompile;
716 ficlTick(pVM);
717 where = ((FICL_WORD *)stackPopPtr(pVM->pStack))->name;
718 hashForget(pHash, where);
719 pDict->here = PTRtoCELL where;
721 return;
725 /**************************************************************************
726 l i s t W o r d s
728 **************************************************************************/
729 #define nCOLWIDTH 8
730 static void listWords(FICL_VM *pVM)
732 FICL_DICT *dp = vmGetDict(pVM);
733 FICL_HASH *pHash = dp->pSearch[dp->nLists - 1];
734 FICL_WORD *wp;
735 int nChars = 0;
736 int len;
737 int y = 0;
738 unsigned i;
739 int nWords = 0;
740 char *cp;
741 char *pPad = pVM->pad;
743 for (i = 0; i < pHash->size; i++)
745 for (wp = pHash->table[i]; wp != NULL; wp = wp->link, nWords++)
747 if (wp->nName == 0) /* ignore :noname defs */
748 continue;
750 cp = wp->name;
751 nChars += sprintf(pPad + nChars, "%s", cp);
753 if (nChars > 70)
755 pPad[nChars] = '\0';
756 nChars = 0;
757 y++;
758 if(y>23) {
759 y=0;
760 vmTextOut(pVM, "--- Press Enter to continue ---",0);
761 getchar();
762 vmTextOut(pVM,"\r",0);
764 vmTextOut(pVM, pPad, 1);
766 else
768 len = nCOLWIDTH - nChars % nCOLWIDTH;
769 while (len-- > 0)
770 pPad[nChars++] = ' ';
773 if (nChars > 70)
775 pPad[nChars] = '\0';
776 nChars = 0;
777 y++;
778 if(y>23) {
779 y=0;
780 vmTextOut(pVM, "--- Press Enter to continue ---",0);
781 getchar();
782 vmTextOut(pVM,"\r",0);
784 vmTextOut(pVM, pPad, 1);
789 if (nChars > 0)
791 pPad[nChars] = '\0';
792 nChars = 0;
793 vmTextOut(pVM, pPad, 1);
796 sprintf(pVM->pad, "Dictionary: %d words, %ld cells used of %u total",
797 nWords, (long) (dp->here - dp->dict), dp->size);
798 vmTextOut(pVM, pVM->pad, 1);
799 return;
803 /**************************************************************************
804 l i s t E n v
805 ** Print symbols defined in the environment
806 **************************************************************************/
807 static void listEnv(FICL_VM *pVM)
809 FICL_DICT *dp = pVM->pSys->envp;
810 FICL_HASH *pHash = dp->pForthWords;
811 FICL_WORD *wp;
812 unsigned i;
813 int nWords = 0;
815 for (i = 0; i < pHash->size; i++)
817 for (wp = pHash->table[i]; wp != NULL; wp = wp->link, nWords++)
819 vmTextOut(pVM, wp->name, 1);
823 sprintf(pVM->pad, "Environment: %d words, %ld cells used of %u total",
824 nWords, (long) (dp->here - dp->dict), dp->size);
825 vmTextOut(pVM, pVM->pad, 1);
826 return;
830 /**************************************************************************
831 e n v C o n s t a n t
832 ** Ficl interface to ficlSetEnv and ficlSetEnvD - allow ficl code to set
833 ** environment constants...
834 **************************************************************************/
835 static void envConstant(FICL_VM *pVM)
837 unsigned value;
839 #if FICL_ROBUST > 1
840 vmCheckStack(pVM, 1, 0);
841 #endif
843 vmGetWordToPad(pVM);
844 value = POPUNS();
845 ficlSetEnv(pVM->pSys, pVM->pad, (FICL_UNS)value);
846 return;
849 static void env2Constant(FICL_VM *pVM)
851 unsigned v1, v2;
853 #if FICL_ROBUST > 1
854 vmCheckStack(pVM, 2, 0);
855 #endif
857 vmGetWordToPad(pVM);
858 v2 = POPUNS();
859 v1 = POPUNS();
860 ficlSetEnvD(pVM->pSys, pVM->pad, v1, v2);
861 return;
865 /**************************************************************************
866 f i c l C o m p i l e T o o l s
867 ** Builds wordset for debugger and TOOLS optional word set
868 **************************************************************************/
870 void ficlCompileTools(FICL_SYSTEM *pSys)
872 FICL_DICT *dp = pSys->dp;
873 assert (dp);
876 ** TOOLS and TOOLS EXT
878 dictAppendWord(dp, ".s", displayPStack, FW_DEFAULT);
879 dictAppendWord(dp, "bye", bye, FW_DEFAULT);
880 dictAppendWord(dp, "forget", forget, FW_DEFAULT);
881 dictAppendWord(dp, "see", see, FW_DEFAULT);
882 dictAppendWord(dp, "words", listWords, FW_DEFAULT);
885 ** Set TOOLS environment query values
887 ficlSetEnv(pSys, "tools", FICL_TRUE);
888 ficlSetEnv(pSys, "tools-ext", FICL_FALSE);
891 ** Ficl extras
893 dictAppendWord(dp, "r.s", displayRStack, FW_DEFAULT); /* guy carver */
894 dictAppendWord(dp, ".env", listEnv, FW_DEFAULT);
895 dictAppendWord(dp, "env-constant",
896 envConstant, FW_DEFAULT);
897 dictAppendWord(dp, "env-2constant",
898 env2Constant, FW_DEFAULT);
899 dictAppendWord(dp, "debug-xt", ficlDebugXT, FW_DEFAULT);
900 dictAppendWord(dp, "parse-order",
901 ficlListParseSteps,
902 FW_DEFAULT);
903 dictAppendWord(dp, "step-break",stepBreak, FW_DEFAULT);
904 dictAppendWord(dp, "forget-wid",forgetWid, FW_DEFAULT);
905 dictAppendWord(dp, "see-xt", seeXT, FW_DEFAULT);
907 return;