1*a1bf3f78SToomas Soome /* 2*a1bf3f78SToomas Soome * t o o l s . c 3*a1bf3f78SToomas Soome * Forth Inspired Command Language - programming tools 4*a1bf3f78SToomas Soome * Author: John Sadler (john_sadler@alum.mit.edu) 5*a1bf3f78SToomas Soome * Created: 20 June 2000 6*a1bf3f78SToomas Soome * $Id: tools.c,v 1.12 2010/08/12 13:57:22 asau Exp $ 7*a1bf3f78SToomas Soome */ 8*a1bf3f78SToomas Soome /* 9*a1bf3f78SToomas Soome * Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu) 10*a1bf3f78SToomas Soome * All rights reserved. 11*a1bf3f78SToomas Soome * 12*a1bf3f78SToomas Soome * Get the latest Ficl release at http://ficl.sourceforge.net 13*a1bf3f78SToomas Soome * 14*a1bf3f78SToomas Soome * I am interested in hearing from anyone who uses Ficl. If you have 15*a1bf3f78SToomas Soome * a problem, a success story, a defect, an enhancement request, or 16*a1bf3f78SToomas Soome * if you would like to contribute to the Ficl release, please 17*a1bf3f78SToomas Soome * contact me by email at the address above. 18*a1bf3f78SToomas Soome * 19*a1bf3f78SToomas Soome * L I C E N S E and D I S C L A I M E R 20*a1bf3f78SToomas Soome * 21*a1bf3f78SToomas Soome * Redistribution and use in source and binary forms, with or without 22*a1bf3f78SToomas Soome * modification, are permitted provided that the following conditions 23*a1bf3f78SToomas Soome * are met: 24*a1bf3f78SToomas Soome * 1. Redistributions of source code must retain the above copyright 25*a1bf3f78SToomas Soome * notice, this list of conditions and the following disclaimer. 26*a1bf3f78SToomas Soome * 2. Redistributions in binary form must reproduce the above copyright 27*a1bf3f78SToomas Soome * notice, this list of conditions and the following disclaimer in the 28*a1bf3f78SToomas Soome * documentation and/or other materials provided with the distribution. 29*a1bf3f78SToomas Soome * 30*a1bf3f78SToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 31*a1bf3f78SToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32*a1bf3f78SToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33*a1bf3f78SToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 34*a1bf3f78SToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35*a1bf3f78SToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36*a1bf3f78SToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 37*a1bf3f78SToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38*a1bf3f78SToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 39*a1bf3f78SToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 40*a1bf3f78SToomas Soome * SUCH DAMAGE. 41*a1bf3f78SToomas Soome */ 42*a1bf3f78SToomas Soome 43*a1bf3f78SToomas Soome /* 44*a1bf3f78SToomas Soome * NOTES: 45*a1bf3f78SToomas Soome * SEE needs information about the addresses of functions that 46*a1bf3f78SToomas Soome * are the CFAs of colon definitions, constants, variables, DOES> 47*a1bf3f78SToomas Soome * words, and so on. It gets this information from a table and supporting 48*a1bf3f78SToomas Soome * functions in words.c. 49*a1bf3f78SToomas Soome * fiColonParen fiDoDoes createParen fiVariableParen fiUserParen fiConstantParen 50*a1bf3f78SToomas Soome * 51*a1bf3f78SToomas Soome * Step and break debugger for Ficl 52*a1bf3f78SToomas Soome * debug ( xt -- ) Start debugging an xt 53*a1bf3f78SToomas Soome * Set a breakpoint 54*a1bf3f78SToomas Soome * Specify breakpoint default action 55*a1bf3f78SToomas Soome */ 56*a1bf3f78SToomas Soome 57*a1bf3f78SToomas Soome #include "ficl.h" 58*a1bf3f78SToomas Soome 59*a1bf3f78SToomas Soome extern void exit(int); 60*a1bf3f78SToomas Soome 61*a1bf3f78SToomas Soome static void ficlPrimitiveStepIn(ficlVm *vm); 62*a1bf3f78SToomas Soome static void ficlPrimitiveStepOver(ficlVm *vm); 63*a1bf3f78SToomas Soome static void ficlPrimitiveStepBreak(ficlVm *vm); 64*a1bf3f78SToomas Soome 65*a1bf3f78SToomas Soome void 66*a1bf3f78SToomas Soome ficlCallbackAssert(ficlCallback *callback, int expression, 67*a1bf3f78SToomas Soome char *expressionString, char *filename, int line) 68*a1bf3f78SToomas Soome { 69*a1bf3f78SToomas Soome #if FICL_ROBUST >= 1 70*a1bf3f78SToomas Soome if (!expression) { 71*a1bf3f78SToomas Soome static char buffer[256]; 72*a1bf3f78SToomas Soome sprintf(buffer, "ASSERTION FAILED at %s:%d: \"%s\"\n", 73*a1bf3f78SToomas Soome filename, line, expressionString); 74*a1bf3f78SToomas Soome ficlCallbackTextOut(callback, buffer); 75*a1bf3f78SToomas Soome exit(-1); 76*a1bf3f78SToomas Soome } 77*a1bf3f78SToomas Soome #else /* FICL_ROBUST >= 1 */ 78*a1bf3f78SToomas Soome FICL_IGNORE(callback); 79*a1bf3f78SToomas Soome FICL_IGNORE(expression); 80*a1bf3f78SToomas Soome FICL_IGNORE(expressionString); 81*a1bf3f78SToomas Soome FICL_IGNORE(filename); 82*a1bf3f78SToomas Soome FICL_IGNORE(line); 83*a1bf3f78SToomas Soome #endif /* FICL_ROBUST >= 1 */ 84*a1bf3f78SToomas Soome } 85*a1bf3f78SToomas Soome 86*a1bf3f78SToomas Soome /* 87*a1bf3f78SToomas Soome * v m S e t B r e a k 88*a1bf3f78SToomas Soome * Set a breakpoint at the current value of IP by 89*a1bf3f78SToomas Soome * storing that address in a BREAKPOINT record 90*a1bf3f78SToomas Soome */ 91*a1bf3f78SToomas Soome static void 92*a1bf3f78SToomas Soome ficlVmSetBreak(ficlVm *vm, ficlBreakpoint *pBP) 93*a1bf3f78SToomas Soome { 94*a1bf3f78SToomas Soome ficlWord *pStep = ficlSystemLookup(vm->callback.system, "step-break"); 95*a1bf3f78SToomas Soome FICL_VM_ASSERT(vm, pStep); 96*a1bf3f78SToomas Soome 97*a1bf3f78SToomas Soome pBP->address = vm->ip; 98*a1bf3f78SToomas Soome pBP->oldXT = *vm->ip; 99*a1bf3f78SToomas Soome *vm->ip = pStep; 100*a1bf3f78SToomas Soome } 101*a1bf3f78SToomas Soome 102*a1bf3f78SToomas Soome /* 103*a1bf3f78SToomas Soome * d e b u g P r o m p t 104*a1bf3f78SToomas Soome */ 105*a1bf3f78SToomas Soome static void 106*a1bf3f78SToomas Soome ficlDebugPrompt(ficlVm *vm, int debug) 107*a1bf3f78SToomas Soome { 108*a1bf3f78SToomas Soome if (debug) 109*a1bf3f78SToomas Soome setenv("prompt", "dbg> ", 1); 110*a1bf3f78SToomas Soome else 111*a1bf3f78SToomas Soome setenv("prompt", "${interpret}", 1); 112*a1bf3f78SToomas Soome } 113*a1bf3f78SToomas Soome 114*a1bf3f78SToomas Soome #if 0 115*a1bf3f78SToomas Soome static int 116*a1bf3f78SToomas Soome isPrimitive(ficlWord *word) 117*a1bf3f78SToomas Soome { 118*a1bf3f78SToomas Soome ficlWordKind wk = ficlWordClassify(word); 119*a1bf3f78SToomas Soome return ((wk != COLON) && (wk != DOES)); 120*a1bf3f78SToomas Soome } 121*a1bf3f78SToomas Soome #endif 122*a1bf3f78SToomas Soome 123*a1bf3f78SToomas Soome /* 124*a1bf3f78SToomas Soome * d i c t H a s h S u m m a r y 125*a1bf3f78SToomas Soome * Calculate a figure of merit for the dictionary hash table based 126*a1bf3f78SToomas Soome * on the average search depth for all the words in the dictionary, 127*a1bf3f78SToomas Soome * assuming uniform distribution of target keys. The figure of merit 128*a1bf3f78SToomas Soome * is the ratio of the total search depth for all keys in the table 129*a1bf3f78SToomas Soome * versus a theoretical optimum that would be achieved if the keys 130*a1bf3f78SToomas Soome * were distributed into the table as evenly as possible. 131*a1bf3f78SToomas Soome * The figure would be worse if the hash table used an open 132*a1bf3f78SToomas Soome * addressing scheme (i.e. collisions resolved by searching the 133*a1bf3f78SToomas Soome * table for an empty slot) for a given size table. 134*a1bf3f78SToomas Soome */ 135*a1bf3f78SToomas Soome #if FICL_WANT_FLOAT 136*a1bf3f78SToomas Soome void 137*a1bf3f78SToomas Soome ficlPrimitiveHashSummary(ficlVm *vm) 138*a1bf3f78SToomas Soome { 139*a1bf3f78SToomas Soome ficlDictionary *dictionary = ficlVmGetDictionary(vm); 140*a1bf3f78SToomas Soome ficlHash *pFHash; 141*a1bf3f78SToomas Soome ficlWord **hash; 142*a1bf3f78SToomas Soome unsigned size; 143*a1bf3f78SToomas Soome ficlWord *word; 144*a1bf3f78SToomas Soome unsigned i; 145*a1bf3f78SToomas Soome int nMax = 0; 146*a1bf3f78SToomas Soome int nWords = 0; 147*a1bf3f78SToomas Soome int nFilled; 148*a1bf3f78SToomas Soome double avg = 0.0; 149*a1bf3f78SToomas Soome double best; 150*a1bf3f78SToomas Soome int nAvg, nRem, nDepth; 151*a1bf3f78SToomas Soome 152*a1bf3f78SToomas Soome FICL_VM_DICTIONARY_CHECK(vm, dictionary, 0); 153*a1bf3f78SToomas Soome 154*a1bf3f78SToomas Soome pFHash = dictionary->wordlists[dictionary->wordlistCount - 1]; 155*a1bf3f78SToomas Soome hash = pFHash->table; 156*a1bf3f78SToomas Soome size = pFHash->size; 157*a1bf3f78SToomas Soome nFilled = size; 158*a1bf3f78SToomas Soome 159*a1bf3f78SToomas Soome for (i = 0; i < size; i++) { 160*a1bf3f78SToomas Soome int n = 0; 161*a1bf3f78SToomas Soome word = hash[i]; 162*a1bf3f78SToomas Soome 163*a1bf3f78SToomas Soome while (word) { 164*a1bf3f78SToomas Soome ++n; 165*a1bf3f78SToomas Soome ++nWords; 166*a1bf3f78SToomas Soome word = word->link; 167*a1bf3f78SToomas Soome } 168*a1bf3f78SToomas Soome 169*a1bf3f78SToomas Soome avg += (double)(n * (n+1)) / 2.0; 170*a1bf3f78SToomas Soome 171*a1bf3f78SToomas Soome if (n > nMax) 172*a1bf3f78SToomas Soome nMax = n; 173*a1bf3f78SToomas Soome if (n == 0) 174*a1bf3f78SToomas Soome --nFilled; 175*a1bf3f78SToomas Soome } 176*a1bf3f78SToomas Soome 177*a1bf3f78SToomas Soome /* Calc actual avg search depth for this hash */ 178*a1bf3f78SToomas Soome avg = avg / nWords; 179*a1bf3f78SToomas Soome 180*a1bf3f78SToomas Soome /* Calc best possible performance with this size hash */ 181*a1bf3f78SToomas Soome nAvg = nWords / size; 182*a1bf3f78SToomas Soome nRem = nWords % size; 183*a1bf3f78SToomas Soome nDepth = size * (nAvg * (nAvg+1))/2 + (nAvg+1)*nRem; 184*a1bf3f78SToomas Soome best = (double)nDepth/nWords; 185*a1bf3f78SToomas Soome 186*a1bf3f78SToomas Soome sprintf(vm->pad, "%d bins, %2.0f%% filled, Depth: " 187*a1bf3f78SToomas Soome "Max=%d, Avg=%2.1f, Best=%2.1f, Score: %2.0f%%\n", 188*a1bf3f78SToomas Soome size, (double)nFilled * 100.0 / size, nMax, 189*a1bf3f78SToomas Soome avg, best, 100.0 * best / avg); 190*a1bf3f78SToomas Soome 191*a1bf3f78SToomas Soome ficlVmTextOut(vm, vm->pad); 192*a1bf3f78SToomas Soome } 193*a1bf3f78SToomas Soome #endif 194*a1bf3f78SToomas Soome 195*a1bf3f78SToomas Soome /* 196*a1bf3f78SToomas Soome * Here's the outer part of the decompiler. It's 197*a1bf3f78SToomas Soome * just a big nested conditional that checks the 198*a1bf3f78SToomas Soome * CFA of the word to decompile for each kind of 199*a1bf3f78SToomas Soome * known word-builder code, and tries to do 200*a1bf3f78SToomas Soome * something appropriate. If the CFA is not recognized, 201*a1bf3f78SToomas Soome * just indicate that it is a primitive. 202*a1bf3f78SToomas Soome */ 203*a1bf3f78SToomas Soome static void 204*a1bf3f78SToomas Soome ficlPrimitiveSeeXT(ficlVm *vm) 205*a1bf3f78SToomas Soome { 206*a1bf3f78SToomas Soome ficlWord *word; 207*a1bf3f78SToomas Soome ficlWordKind kind; 208*a1bf3f78SToomas Soome 209*a1bf3f78SToomas Soome word = (ficlWord *)ficlStackPopPointer(vm->dataStack); 210*a1bf3f78SToomas Soome kind = ficlWordClassify(word); 211*a1bf3f78SToomas Soome 212*a1bf3f78SToomas Soome switch (kind) { 213*a1bf3f78SToomas Soome case FICL_WORDKIND_COLON: 214*a1bf3f78SToomas Soome sprintf(vm->pad, ": %.*s\n", word->length, word->name); 215*a1bf3f78SToomas Soome ficlVmTextOut(vm, vm->pad); 216*a1bf3f78SToomas Soome ficlDictionarySee(ficlVmGetDictionary(vm), word, 217*a1bf3f78SToomas Soome &(vm->callback)); 218*a1bf3f78SToomas Soome break; 219*a1bf3f78SToomas Soome case FICL_WORDKIND_DOES: 220*a1bf3f78SToomas Soome ficlVmTextOut(vm, "does>\n"); 221*a1bf3f78SToomas Soome ficlDictionarySee(ficlVmGetDictionary(vm), 222*a1bf3f78SToomas Soome (ficlWord *)word->param->p, &(vm->callback)); 223*a1bf3f78SToomas Soome break; 224*a1bf3f78SToomas Soome case FICL_WORDKIND_CREATE: 225*a1bf3f78SToomas Soome ficlVmTextOut(vm, "create\n"); 226*a1bf3f78SToomas Soome break; 227*a1bf3f78SToomas Soome case FICL_WORDKIND_VARIABLE: 228*a1bf3f78SToomas Soome sprintf(vm->pad, "variable = %ld (%#lx)\n", 229*a1bf3f78SToomas Soome (long)word->param->i, (long unsigned)word->param->u); 230*a1bf3f78SToomas Soome ficlVmTextOut(vm, vm->pad); 231*a1bf3f78SToomas Soome break; 232*a1bf3f78SToomas Soome #if FICL_WANT_USER 233*a1bf3f78SToomas Soome case FICL_WORDKIND_USER: 234*a1bf3f78SToomas Soome sprintf(vm->pad, "user variable %ld (%#lx)\n", 235*a1bf3f78SToomas Soome (long)word->param->i, (long unsigned)word->param->u); 236*a1bf3f78SToomas Soome ficlVmTextOut(vm, vm->pad); 237*a1bf3f78SToomas Soome break; 238*a1bf3f78SToomas Soome #endif 239*a1bf3f78SToomas Soome case FICL_WORDKIND_CONSTANT: 240*a1bf3f78SToomas Soome sprintf(vm->pad, "constant = %ld (%#lx)\n", 241*a1bf3f78SToomas Soome (long)word->param->i, (long unsigned)word->param->u); 242*a1bf3f78SToomas Soome ficlVmTextOut(vm, vm->pad); 243*a1bf3f78SToomas Soome break; 244*a1bf3f78SToomas Soome case FICL_WORDKIND_2CONSTANT: 245*a1bf3f78SToomas Soome sprintf(vm->pad, "constant = %ld %ld (%#lx %#lx)\n", 246*a1bf3f78SToomas Soome (long)word->param[1].i, (long)word->param->i, 247*a1bf3f78SToomas Soome (long unsigned)word->param[1].u, 248*a1bf3f78SToomas Soome (long unsigned)word->param->u); 249*a1bf3f78SToomas Soome ficlVmTextOut(vm, vm->pad); 250*a1bf3f78SToomas Soome break; 251*a1bf3f78SToomas Soome 252*a1bf3f78SToomas Soome default: 253*a1bf3f78SToomas Soome sprintf(vm->pad, "%.*s is a primitive\n", word->length, 254*a1bf3f78SToomas Soome word->name); 255*a1bf3f78SToomas Soome ficlVmTextOut(vm, vm->pad); 256*a1bf3f78SToomas Soome break; 257*a1bf3f78SToomas Soome } 258*a1bf3f78SToomas Soome 259*a1bf3f78SToomas Soome if (word->flags & FICL_WORD_IMMEDIATE) { 260*a1bf3f78SToomas Soome ficlVmTextOut(vm, "immediate\n"); 261*a1bf3f78SToomas Soome } 262*a1bf3f78SToomas Soome 263*a1bf3f78SToomas Soome if (word->flags & FICL_WORD_COMPILE_ONLY) { 264*a1bf3f78SToomas Soome ficlVmTextOut(vm, "compile-only\n"); 265*a1bf3f78SToomas Soome } 266*a1bf3f78SToomas Soome } 267*a1bf3f78SToomas Soome 268*a1bf3f78SToomas Soome static void 269*a1bf3f78SToomas Soome ficlPrimitiveSee(ficlVm *vm) 270*a1bf3f78SToomas Soome { 271*a1bf3f78SToomas Soome ficlPrimitiveTick(vm); 272*a1bf3f78SToomas Soome ficlPrimitiveSeeXT(vm); 273*a1bf3f78SToomas Soome } 274*a1bf3f78SToomas Soome 275*a1bf3f78SToomas Soome /* 276*a1bf3f78SToomas Soome * f i c l D e b u g X T 277*a1bf3f78SToomas Soome * debug ( xt -- ) 278*a1bf3f78SToomas Soome * Given an xt of a colon definition or a word defined by DOES>, set the 279*a1bf3f78SToomas Soome * VM up to debug the word: push IP, set the xt as the next thing to execute, 280*a1bf3f78SToomas Soome * set a breakpoint at its first instruction, and run to the breakpoint. 281*a1bf3f78SToomas Soome * Note: the semantics of this word are equivalent to "step in" 282*a1bf3f78SToomas Soome */ 283*a1bf3f78SToomas Soome static void 284*a1bf3f78SToomas Soome ficlPrimitiveDebugXT(ficlVm *vm) 285*a1bf3f78SToomas Soome { 286*a1bf3f78SToomas Soome ficlWord *xt = ficlStackPopPointer(vm->dataStack); 287*a1bf3f78SToomas Soome ficlWordKind wk = ficlWordClassify(xt); 288*a1bf3f78SToomas Soome 289*a1bf3f78SToomas Soome ficlStackPushPointer(vm->dataStack, xt); 290*a1bf3f78SToomas Soome ficlPrimitiveSeeXT(vm); 291*a1bf3f78SToomas Soome 292*a1bf3f78SToomas Soome switch (wk) { 293*a1bf3f78SToomas Soome case FICL_WORDKIND_COLON: 294*a1bf3f78SToomas Soome case FICL_WORDKIND_DOES: 295*a1bf3f78SToomas Soome /* 296*a1bf3f78SToomas Soome * Run the colon code and set a breakpoint at the next 297*a1bf3f78SToomas Soome * instruction 298*a1bf3f78SToomas Soome */ 299*a1bf3f78SToomas Soome ficlVmExecuteWord(vm, xt); 300*a1bf3f78SToomas Soome ficlVmSetBreak(vm, &(vm->callback.system->breakpoint)); 301*a1bf3f78SToomas Soome break; 302*a1bf3f78SToomas Soome default: 303*a1bf3f78SToomas Soome ficlVmExecuteWord(vm, xt); 304*a1bf3f78SToomas Soome break; 305*a1bf3f78SToomas Soome } 306*a1bf3f78SToomas Soome } 307*a1bf3f78SToomas Soome 308*a1bf3f78SToomas Soome /* 309*a1bf3f78SToomas Soome * s t e p I n 310*a1bf3f78SToomas Soome * Ficl 311*a1bf3f78SToomas Soome * Execute the next instruction, stepping into it if it's a colon definition 312*a1bf3f78SToomas Soome * or a does> word. This is the easy kind of step. 313*a1bf3f78SToomas Soome */ 314*a1bf3f78SToomas Soome static void 315*a1bf3f78SToomas Soome ficlPrimitiveStepIn(ficlVm *vm) 316*a1bf3f78SToomas Soome { 317*a1bf3f78SToomas Soome /* 318*a1bf3f78SToomas Soome * Do one step of the inner loop 319*a1bf3f78SToomas Soome */ 320*a1bf3f78SToomas Soome ficlVmExecuteWord(vm, *vm->ip++); 321*a1bf3f78SToomas Soome 322*a1bf3f78SToomas Soome /* 323*a1bf3f78SToomas Soome * Now set a breakpoint at the next instruction 324*a1bf3f78SToomas Soome */ 325*a1bf3f78SToomas Soome ficlVmSetBreak(vm, &(vm->callback.system->breakpoint)); 326*a1bf3f78SToomas Soome } 327*a1bf3f78SToomas Soome 328*a1bf3f78SToomas Soome /* 329*a1bf3f78SToomas Soome * s t e p O v e r 330*a1bf3f78SToomas Soome * Ficl 331*a1bf3f78SToomas Soome * Execute the next instruction atomically. This requires some insight into 332*a1bf3f78SToomas Soome * the memory layout of compiled code. Set a breakpoint at the next instruction 333*a1bf3f78SToomas Soome * in this word, and run until we hit it 334*a1bf3f78SToomas Soome */ 335*a1bf3f78SToomas Soome static void 336*a1bf3f78SToomas Soome ficlPrimitiveStepOver(ficlVm *vm) 337*a1bf3f78SToomas Soome { 338*a1bf3f78SToomas Soome ficlWord *word; 339*a1bf3f78SToomas Soome ficlWordKind kind; 340*a1bf3f78SToomas Soome ficlWord *pStep = ficlSystemLookup(vm->callback.system, "step-break"); 341*a1bf3f78SToomas Soome FICL_VM_ASSERT(vm, pStep); 342*a1bf3f78SToomas Soome 343*a1bf3f78SToomas Soome word = *vm->ip; 344*a1bf3f78SToomas Soome kind = ficlWordClassify(word); 345*a1bf3f78SToomas Soome 346*a1bf3f78SToomas Soome switch (kind) { 347*a1bf3f78SToomas Soome case FICL_WORDKIND_COLON: 348*a1bf3f78SToomas Soome case FICL_WORDKIND_DOES: 349*a1bf3f78SToomas Soome /* 350*a1bf3f78SToomas Soome * assume that the next ficlCell holds an instruction 351*a1bf3f78SToomas Soome * set a breakpoint there and return to the inner interpreter 352*a1bf3f78SToomas Soome */ 353*a1bf3f78SToomas Soome vm->callback.system->breakpoint.address = vm->ip + 1; 354*a1bf3f78SToomas Soome vm->callback.system->breakpoint.oldXT = vm->ip[1]; 355*a1bf3f78SToomas Soome vm->ip[1] = pStep; 356*a1bf3f78SToomas Soome break; 357*a1bf3f78SToomas Soome default: 358*a1bf3f78SToomas Soome ficlPrimitiveStepIn(vm); 359*a1bf3f78SToomas Soome break; 360*a1bf3f78SToomas Soome } 361*a1bf3f78SToomas Soome } 362*a1bf3f78SToomas Soome 363*a1bf3f78SToomas Soome /* 364*a1bf3f78SToomas Soome * s t e p - b r e a k 365*a1bf3f78SToomas Soome * Ficl 366*a1bf3f78SToomas Soome * Handles breakpoints for stepped execution. 367*a1bf3f78SToomas Soome * Upon entry, breakpoint contains the address and replaced instruction 368*a1bf3f78SToomas Soome * of the current breakpoint. 369*a1bf3f78SToomas Soome * Clear the breakpoint 370*a1bf3f78SToomas Soome * Get a command from the console. 371*a1bf3f78SToomas Soome * i (step in) - execute the current instruction and set a new breakpoint 372*a1bf3f78SToomas Soome * at the IP 373*a1bf3f78SToomas Soome * o (step over) - execute the current instruction to completion and set 374*a1bf3f78SToomas Soome * a new breakpoint at the IP 375*a1bf3f78SToomas Soome * g (go) - execute the current instruction and exit 376*a1bf3f78SToomas Soome * q (quit) - abort current word 377*a1bf3f78SToomas Soome * b (toggle breakpoint) 378*a1bf3f78SToomas Soome */ 379*a1bf3f78SToomas Soome 380*a1bf3f78SToomas Soome extern char *ficlDictionaryInstructionNames[]; 381*a1bf3f78SToomas Soome 382*a1bf3f78SToomas Soome static void 383*a1bf3f78SToomas Soome ficlPrimitiveStepBreak(ficlVm *vm) 384*a1bf3f78SToomas Soome { 385*a1bf3f78SToomas Soome ficlString command; 386*a1bf3f78SToomas Soome ficlWord *word; 387*a1bf3f78SToomas Soome ficlWord *pOnStep; 388*a1bf3f78SToomas Soome int debug = 1; 389*a1bf3f78SToomas Soome 390*a1bf3f78SToomas Soome if (!vm->restart) { 391*a1bf3f78SToomas Soome FICL_VM_ASSERT(vm, vm->callback.system->breakpoint.address); 392*a1bf3f78SToomas Soome FICL_VM_ASSERT(vm, vm->callback.system->breakpoint.oldXT); 393*a1bf3f78SToomas Soome 394*a1bf3f78SToomas Soome /* 395*a1bf3f78SToomas Soome * Clear the breakpoint that caused me to run 396*a1bf3f78SToomas Soome * Restore the original instruction at the breakpoint, 397*a1bf3f78SToomas Soome * and restore the IP 398*a1bf3f78SToomas Soome */ 399*a1bf3f78SToomas Soome vm->ip = (ficlIp)(vm->callback.system->breakpoint.address); 400*a1bf3f78SToomas Soome *vm->ip = vm->callback.system->breakpoint.oldXT; 401*a1bf3f78SToomas Soome 402*a1bf3f78SToomas Soome /* 403*a1bf3f78SToomas Soome * If there's an onStep, do it 404*a1bf3f78SToomas Soome */ 405*a1bf3f78SToomas Soome pOnStep = ficlSystemLookup(vm->callback.system, "on-step"); 406*a1bf3f78SToomas Soome if (pOnStep) 407*a1bf3f78SToomas Soome ficlVmExecuteXT(vm, pOnStep); 408*a1bf3f78SToomas Soome 409*a1bf3f78SToomas Soome /* 410*a1bf3f78SToomas Soome * Print the name of the next instruction 411*a1bf3f78SToomas Soome */ 412*a1bf3f78SToomas Soome word = vm->callback.system->breakpoint.oldXT; 413*a1bf3f78SToomas Soome 414*a1bf3f78SToomas Soome if ((((ficlInstruction)word) > ficlInstructionInvalid) && 415*a1bf3f78SToomas Soome (((ficlInstruction)word) < ficlInstructionLast)) 416*a1bf3f78SToomas Soome sprintf(vm->pad, "next: %s (instruction %ld)\n", 417*a1bf3f78SToomas Soome ficlDictionaryInstructionNames[(long)word], 418*a1bf3f78SToomas Soome (long)word); 419*a1bf3f78SToomas Soome else { 420*a1bf3f78SToomas Soome sprintf(vm->pad, "next: %s\n", word->name); 421*a1bf3f78SToomas Soome if (strcmp(word->name, "interpret") == 0) 422*a1bf3f78SToomas Soome debug = 0; 423*a1bf3f78SToomas Soome } 424*a1bf3f78SToomas Soome 425*a1bf3f78SToomas Soome ficlVmTextOut(vm, vm->pad); 426*a1bf3f78SToomas Soome ficlDebugPrompt(vm, debug); 427*a1bf3f78SToomas Soome } else { 428*a1bf3f78SToomas Soome vm->restart = 0; 429*a1bf3f78SToomas Soome } 430*a1bf3f78SToomas Soome 431*a1bf3f78SToomas Soome command = ficlVmGetWord(vm); 432*a1bf3f78SToomas Soome 433*a1bf3f78SToomas Soome switch (command.text[0]) { 434*a1bf3f78SToomas Soome case 'i': 435*a1bf3f78SToomas Soome ficlPrimitiveStepIn(vm); 436*a1bf3f78SToomas Soome break; 437*a1bf3f78SToomas Soome 438*a1bf3f78SToomas Soome case 'o': 439*a1bf3f78SToomas Soome ficlPrimitiveStepOver(vm); 440*a1bf3f78SToomas Soome break; 441*a1bf3f78SToomas Soome 442*a1bf3f78SToomas Soome case 'g': 443*a1bf3f78SToomas Soome break; 444*a1bf3f78SToomas Soome 445*a1bf3f78SToomas Soome case 'l': { 446*a1bf3f78SToomas Soome ficlWord *xt; 447*a1bf3f78SToomas Soome xt = ficlDictionaryFindEnclosingWord( 448*a1bf3f78SToomas Soome ficlVmGetDictionary(vm), (ficlCell *)(vm->ip)); 449*a1bf3f78SToomas Soome if (xt) { 450*a1bf3f78SToomas Soome ficlStackPushPointer(vm->dataStack, xt); 451*a1bf3f78SToomas Soome ficlPrimitiveSeeXT(vm); 452*a1bf3f78SToomas Soome } else { 453*a1bf3f78SToomas Soome ficlVmTextOut(vm, "sorry - can't do that\n"); 454*a1bf3f78SToomas Soome } 455*a1bf3f78SToomas Soome ficlVmThrow(vm, FICL_VM_STATUS_RESTART); 456*a1bf3f78SToomas Soome break; 457*a1bf3f78SToomas Soome } 458*a1bf3f78SToomas Soome 459*a1bf3f78SToomas Soome case 'q': 460*a1bf3f78SToomas Soome ficlDebugPrompt(vm, 0); 461*a1bf3f78SToomas Soome ficlVmThrow(vm, FICL_VM_STATUS_ABORT); 462*a1bf3f78SToomas Soome break; 463*a1bf3f78SToomas Soome case 'x': { 464*a1bf3f78SToomas Soome /* 465*a1bf3f78SToomas Soome * Take whatever's left in the TIB and feed it to a 466*a1bf3f78SToomas Soome * subordinate ficlVmExecuteString 467*a1bf3f78SToomas Soome */ 468*a1bf3f78SToomas Soome int returnValue; 469*a1bf3f78SToomas Soome ficlString s; 470*a1bf3f78SToomas Soome ficlWord *oldRunningWord = vm->runningWord; 471*a1bf3f78SToomas Soome 472*a1bf3f78SToomas Soome FICL_STRING_SET_POINTER(s, 473*a1bf3f78SToomas Soome vm->tib.text + vm->tib.index); 474*a1bf3f78SToomas Soome FICL_STRING_SET_LENGTH(s, 475*a1bf3f78SToomas Soome vm->tib.end - FICL_STRING_GET_POINTER(s)); 476*a1bf3f78SToomas Soome 477*a1bf3f78SToomas Soome returnValue = ficlVmExecuteString(vm, s); 478*a1bf3f78SToomas Soome 479*a1bf3f78SToomas Soome if (returnValue == FICL_VM_STATUS_OUT_OF_TEXT) { 480*a1bf3f78SToomas Soome returnValue = FICL_VM_STATUS_RESTART; 481*a1bf3f78SToomas Soome vm->runningWord = oldRunningWord; 482*a1bf3f78SToomas Soome ficlVmTextOut(vm, "\n"); 483*a1bf3f78SToomas Soome } 484*a1bf3f78SToomas Soome if (returnValue == FICL_VM_STATUS_ERROR_EXIT) 485*a1bf3f78SToomas Soome ficlDebugPrompt(vm, 0); 486*a1bf3f78SToomas Soome 487*a1bf3f78SToomas Soome ficlVmThrow(vm, returnValue); 488*a1bf3f78SToomas Soome break; 489*a1bf3f78SToomas Soome } 490*a1bf3f78SToomas Soome 491*a1bf3f78SToomas Soome default: 492*a1bf3f78SToomas Soome ficlVmTextOut(vm, 493*a1bf3f78SToomas Soome "i -- step In\n" 494*a1bf3f78SToomas Soome "o -- step Over\n" 495*a1bf3f78SToomas Soome "g -- Go (execute to completion)\n" 496*a1bf3f78SToomas Soome "l -- List source code\n" 497*a1bf3f78SToomas Soome "q -- Quit (stop debugging and abort)\n" 498*a1bf3f78SToomas Soome "x -- eXecute the rest of the line " 499*a1bf3f78SToomas Soome "as Ficl words\n"); 500*a1bf3f78SToomas Soome ficlDebugPrompt(vm, 1); 501*a1bf3f78SToomas Soome ficlVmThrow(vm, FICL_VM_STATUS_RESTART); 502*a1bf3f78SToomas Soome break; 503*a1bf3f78SToomas Soome } 504*a1bf3f78SToomas Soome 505*a1bf3f78SToomas Soome ficlDebugPrompt(vm, 0); 506*a1bf3f78SToomas Soome } 507*a1bf3f78SToomas Soome 508*a1bf3f78SToomas Soome /* 509*a1bf3f78SToomas Soome * b y e 510*a1bf3f78SToomas Soome * TOOLS 511*a1bf3f78SToomas Soome * Signal the system to shut down - this causes ficlExec to return 512*a1bf3f78SToomas Soome * VM_USEREXIT. The rest is up to you. 513*a1bf3f78SToomas Soome */ 514*a1bf3f78SToomas Soome static void 515*a1bf3f78SToomas Soome ficlPrimitiveBye(ficlVm *vm) 516*a1bf3f78SToomas Soome { 517*a1bf3f78SToomas Soome ficlVmThrow(vm, FICL_VM_STATUS_USER_EXIT); 518*a1bf3f78SToomas Soome } 519*a1bf3f78SToomas Soome 520*a1bf3f78SToomas Soome /* 521*a1bf3f78SToomas Soome * d i s p l a y S t a c k 522*a1bf3f78SToomas Soome * TOOLS 523*a1bf3f78SToomas Soome * Display the parameter stack (code for ".s") 524*a1bf3f78SToomas Soome */ 525*a1bf3f78SToomas Soome 526*a1bf3f78SToomas Soome struct stackContext 527*a1bf3f78SToomas Soome { 528*a1bf3f78SToomas Soome ficlVm *vm; 529*a1bf3f78SToomas Soome ficlDictionary *dictionary; 530*a1bf3f78SToomas Soome int count; 531*a1bf3f78SToomas Soome }; 532*a1bf3f78SToomas Soome 533*a1bf3f78SToomas Soome static ficlInteger 534*a1bf3f78SToomas Soome ficlStackDisplayCallback(void *c, ficlCell *cell) 535*a1bf3f78SToomas Soome { 536*a1bf3f78SToomas Soome struct stackContext *context = (struct stackContext *)c; 537*a1bf3f78SToomas Soome char buffer[80]; 538*a1bf3f78SToomas Soome 539*a1bf3f78SToomas Soome #ifdef _LP64 540*a1bf3f78SToomas Soome snprintf(buffer, sizeof (buffer), "[0x%016lx %3d]: %20ld (0x%016lx)\n", 541*a1bf3f78SToomas Soome (unsigned long)cell, context->count++, (long)cell->i, 542*a1bf3f78SToomas Soome (unsigned long)cell->u); 543*a1bf3f78SToomas Soome #else 544*a1bf3f78SToomas Soome snprintf(buffer, sizeof (buffer), "[0x%08x %3d]: %12d (0x%08x)\n", 545*a1bf3f78SToomas Soome (unsigned)cell, context->count++, cell->i, cell->u); 546*a1bf3f78SToomas Soome #endif 547*a1bf3f78SToomas Soome 548*a1bf3f78SToomas Soome ficlVmTextOut(context->vm, buffer); 549*a1bf3f78SToomas Soome return (FICL_TRUE); 550*a1bf3f78SToomas Soome } 551*a1bf3f78SToomas Soome 552*a1bf3f78SToomas Soome void 553*a1bf3f78SToomas Soome ficlStackDisplay(ficlStack *stack, ficlStackWalkFunction callback, 554*a1bf3f78SToomas Soome void *context) 555*a1bf3f78SToomas Soome { 556*a1bf3f78SToomas Soome ficlVm *vm = stack->vm; 557*a1bf3f78SToomas Soome char buffer[128]; 558*a1bf3f78SToomas Soome struct stackContext myContext; 559*a1bf3f78SToomas Soome 560*a1bf3f78SToomas Soome FICL_STACK_CHECK(stack, 0, 0); 561*a1bf3f78SToomas Soome 562*a1bf3f78SToomas Soome #ifdef _LP64 563*a1bf3f78SToomas Soome sprintf(buffer, "[%s stack has %d entries, top at 0x%016lx]\n", 564*a1bf3f78SToomas Soome stack->name, ficlStackDepth(stack), (unsigned long)stack->top); 565*a1bf3f78SToomas Soome #else 566*a1bf3f78SToomas Soome sprintf(buffer, "[%s stack has %d entries, top at 0x%08x]\n", 567*a1bf3f78SToomas Soome stack->name, ficlStackDepth(stack), (unsigned)stack->top); 568*a1bf3f78SToomas Soome #endif 569*a1bf3f78SToomas Soome ficlVmTextOut(vm, buffer); 570*a1bf3f78SToomas Soome 571*a1bf3f78SToomas Soome if (callback == NULL) { 572*a1bf3f78SToomas Soome myContext.vm = vm; 573*a1bf3f78SToomas Soome myContext.count = 0; 574*a1bf3f78SToomas Soome context = &myContext; 575*a1bf3f78SToomas Soome callback = ficlStackDisplayCallback; 576*a1bf3f78SToomas Soome } 577*a1bf3f78SToomas Soome ficlStackWalk(stack, callback, context, FICL_FALSE); 578*a1bf3f78SToomas Soome 579*a1bf3f78SToomas Soome #ifdef _LP64 580*a1bf3f78SToomas Soome sprintf(buffer, "[%s stack base at 0x%016lx]\n", stack->name, 581*a1bf3f78SToomas Soome (unsigned long)stack->base); 582*a1bf3f78SToomas Soome #else 583*a1bf3f78SToomas Soome sprintf(buffer, "[%s stack base at 0x%08x]\n", stack->name, 584*a1bf3f78SToomas Soome (unsigned)stack->base); 585*a1bf3f78SToomas Soome #endif 586*a1bf3f78SToomas Soome ficlVmTextOut(vm, buffer); 587*a1bf3f78SToomas Soome } 588*a1bf3f78SToomas Soome 589*a1bf3f78SToomas Soome void 590*a1bf3f78SToomas Soome ficlVmDisplayDataStack(ficlVm *vm) 591*a1bf3f78SToomas Soome { 592*a1bf3f78SToomas Soome ficlStackDisplay(vm->dataStack, NULL, NULL); 593*a1bf3f78SToomas Soome } 594*a1bf3f78SToomas Soome 595*a1bf3f78SToomas Soome static ficlInteger 596*a1bf3f78SToomas Soome ficlStackDisplaySimpleCallback(void *c, ficlCell *cell) 597*a1bf3f78SToomas Soome { 598*a1bf3f78SToomas Soome struct stackContext *context = (struct stackContext *)c; 599*a1bf3f78SToomas Soome char buffer[32]; 600*a1bf3f78SToomas Soome 601*a1bf3f78SToomas Soome sprintf(buffer, "%s%ld", context->count ? " " : "", (long)cell->i); 602*a1bf3f78SToomas Soome context->count++; 603*a1bf3f78SToomas Soome ficlVmTextOut(context->vm, buffer); 604*a1bf3f78SToomas Soome return (FICL_TRUE); 605*a1bf3f78SToomas Soome } 606*a1bf3f78SToomas Soome 607*a1bf3f78SToomas Soome void 608*a1bf3f78SToomas Soome ficlVmDisplayDataStackSimple(ficlVm *vm) 609*a1bf3f78SToomas Soome { 610*a1bf3f78SToomas Soome ficlStack *stack = vm->dataStack; 611*a1bf3f78SToomas Soome char buffer[32]; 612*a1bf3f78SToomas Soome struct stackContext context; 613*a1bf3f78SToomas Soome 614*a1bf3f78SToomas Soome FICL_STACK_CHECK(stack, 0, 0); 615*a1bf3f78SToomas Soome 616*a1bf3f78SToomas Soome sprintf(buffer, "[%d] ", ficlStackDepth(stack)); 617*a1bf3f78SToomas Soome ficlVmTextOut(vm, buffer); 618*a1bf3f78SToomas Soome 619*a1bf3f78SToomas Soome context.vm = vm; 620*a1bf3f78SToomas Soome context.count = 0; 621*a1bf3f78SToomas Soome ficlStackWalk(stack, ficlStackDisplaySimpleCallback, &context, 622*a1bf3f78SToomas Soome FICL_TRUE); 623*a1bf3f78SToomas Soome } 624*a1bf3f78SToomas Soome 625*a1bf3f78SToomas Soome static ficlInteger 626*a1bf3f78SToomas Soome ficlReturnStackDisplayCallback(void *c, ficlCell *cell) 627*a1bf3f78SToomas Soome { 628*a1bf3f78SToomas Soome struct stackContext *context = (struct stackContext *)c; 629*a1bf3f78SToomas Soome char buffer[128]; 630*a1bf3f78SToomas Soome 631*a1bf3f78SToomas Soome #ifdef _LP64 632*a1bf3f78SToomas Soome sprintf(buffer, "[0x%016lx %3d] %20ld (0x%016lx)", (unsigned long)cell, 633*a1bf3f78SToomas Soome context->count++, cell->i, cell->u); 634*a1bf3f78SToomas Soome #else 635*a1bf3f78SToomas Soome sprintf(buffer, "[0x%08x %3d] %12d (0x%08x)", (unsigned)cell, 636*a1bf3f78SToomas Soome context->count++, cell->i, cell->u); 637*a1bf3f78SToomas Soome #endif 638*a1bf3f78SToomas Soome 639*a1bf3f78SToomas Soome /* 640*a1bf3f78SToomas Soome * Attempt to find the word that contains the return 641*a1bf3f78SToomas Soome * stack address (as if it is part of a colon definition). 642*a1bf3f78SToomas Soome * If this works, also print the name of the word. 643*a1bf3f78SToomas Soome */ 644*a1bf3f78SToomas Soome if (ficlDictionaryIncludes(context->dictionary, cell->p)) { 645*a1bf3f78SToomas Soome ficlWord *word; 646*a1bf3f78SToomas Soome word = ficlDictionaryFindEnclosingWord(context->dictionary, 647*a1bf3f78SToomas Soome cell->p); 648*a1bf3f78SToomas Soome if (word) { 649*a1bf3f78SToomas Soome int offset = (ficlCell *)cell->p - &word->param[0]; 650*a1bf3f78SToomas Soome sprintf(buffer + strlen(buffer), ", %s + %d ", 651*a1bf3f78SToomas Soome word->name, offset); 652*a1bf3f78SToomas Soome } 653*a1bf3f78SToomas Soome } 654*a1bf3f78SToomas Soome strcat(buffer, "\n"); 655*a1bf3f78SToomas Soome ficlVmTextOut(context->vm, buffer); 656*a1bf3f78SToomas Soome return (FICL_TRUE); 657*a1bf3f78SToomas Soome } 658*a1bf3f78SToomas Soome 659*a1bf3f78SToomas Soome void 660*a1bf3f78SToomas Soome ficlVmDisplayReturnStack(ficlVm *vm) 661*a1bf3f78SToomas Soome { 662*a1bf3f78SToomas Soome struct stackContext context; 663*a1bf3f78SToomas Soome context.vm = vm; 664*a1bf3f78SToomas Soome context.count = 0; 665*a1bf3f78SToomas Soome context.dictionary = ficlVmGetDictionary(vm); 666*a1bf3f78SToomas Soome ficlStackDisplay(vm->returnStack, ficlReturnStackDisplayCallback, 667*a1bf3f78SToomas Soome &context); 668*a1bf3f78SToomas Soome } 669*a1bf3f78SToomas Soome 670*a1bf3f78SToomas Soome /* 671*a1bf3f78SToomas Soome * f o r g e t - w i d 672*a1bf3f78SToomas Soome */ 673*a1bf3f78SToomas Soome static void 674*a1bf3f78SToomas Soome ficlPrimitiveForgetWid(ficlVm *vm) 675*a1bf3f78SToomas Soome { 676*a1bf3f78SToomas Soome ficlDictionary *dictionary = ficlVmGetDictionary(vm); 677*a1bf3f78SToomas Soome ficlHash *hash; 678*a1bf3f78SToomas Soome 679*a1bf3f78SToomas Soome hash = (ficlHash *)ficlStackPopPointer(vm->dataStack); 680*a1bf3f78SToomas Soome ficlHashForget(hash, dictionary->here); 681*a1bf3f78SToomas Soome } 682*a1bf3f78SToomas Soome 683*a1bf3f78SToomas Soome /* 684*a1bf3f78SToomas Soome * f o r g e t 685*a1bf3f78SToomas Soome * TOOLS EXT ( "<spaces>name" -- ) 686*a1bf3f78SToomas Soome * Skip leading space delimiters. Parse name delimited by a space. 687*a1bf3f78SToomas Soome * Find name, then delete name from the dictionary along with all 688*a1bf3f78SToomas Soome * words added to the dictionary after name. An ambiguous 689*a1bf3f78SToomas Soome * condition exists if name cannot be found. 690*a1bf3f78SToomas Soome * 691*a1bf3f78SToomas Soome * If the Search-Order word set is present, FORGET searches the 692*a1bf3f78SToomas Soome * compilation word list. An ambiguous condition exists if the 693*a1bf3f78SToomas Soome * compilation word list is deleted. 694*a1bf3f78SToomas Soome */ 695*a1bf3f78SToomas Soome static void 696*a1bf3f78SToomas Soome ficlPrimitiveForget(ficlVm *vm) 697*a1bf3f78SToomas Soome { 698*a1bf3f78SToomas Soome void *where; 699*a1bf3f78SToomas Soome ficlDictionary *dictionary = ficlVmGetDictionary(vm); 700*a1bf3f78SToomas Soome ficlHash *hash = dictionary->compilationWordlist; 701*a1bf3f78SToomas Soome 702*a1bf3f78SToomas Soome ficlPrimitiveTick(vm); 703*a1bf3f78SToomas Soome where = ((ficlWord *)ficlStackPopPointer(vm->dataStack))->name; 704*a1bf3f78SToomas Soome ficlHashForget(hash, where); 705*a1bf3f78SToomas Soome dictionary->here = FICL_POINTER_TO_CELL(where); 706*a1bf3f78SToomas Soome } 707*a1bf3f78SToomas Soome 708*a1bf3f78SToomas Soome /* 709*a1bf3f78SToomas Soome * w o r d s 710*a1bf3f78SToomas Soome */ 711*a1bf3f78SToomas Soome #define nCOLWIDTH 8 712*a1bf3f78SToomas Soome 713*a1bf3f78SToomas Soome static void 714*a1bf3f78SToomas Soome ficlPrimitiveWords(ficlVm *vm) 715*a1bf3f78SToomas Soome { 716*a1bf3f78SToomas Soome ficlDictionary *dictionary = ficlVmGetDictionary(vm); 717*a1bf3f78SToomas Soome ficlHash *hash = dictionary->wordlists[dictionary->wordlistCount - 1]; 718*a1bf3f78SToomas Soome ficlWord *wp; 719*a1bf3f78SToomas Soome int nChars = 0; 720*a1bf3f78SToomas Soome int len; 721*a1bf3f78SToomas Soome unsigned i; 722*a1bf3f78SToomas Soome int nWords = 0; 723*a1bf3f78SToomas Soome char *cp; 724*a1bf3f78SToomas Soome char *pPad; 725*a1bf3f78SToomas Soome int columns; 726*a1bf3f78SToomas Soome 727*a1bf3f78SToomas Soome cp = getenv("COLUMNS"); 728*a1bf3f78SToomas Soome /* 729*a1bf3f78SToomas Soome * using strtol for now. TODO: refactor number conversion from 730*a1bf3f78SToomas Soome * ficlPrimitiveToNumber() and use it instead. 731*a1bf3f78SToomas Soome */ 732*a1bf3f78SToomas Soome if (cp == NULL) 733*a1bf3f78SToomas Soome columns = 80; 734*a1bf3f78SToomas Soome else 735*a1bf3f78SToomas Soome columns = strtol(cp, NULL, 0); 736*a1bf3f78SToomas Soome 737*a1bf3f78SToomas Soome /* 738*a1bf3f78SToomas Soome * the pad is fixed size area, it's better to allocate 739*a1bf3f78SToomas Soome * dedicated buffer space to deal with custom terminal sizes. 740*a1bf3f78SToomas Soome */ 741*a1bf3f78SToomas Soome pPad = malloc(columns + 1); 742*a1bf3f78SToomas Soome if (pPad == NULL) 743*a1bf3f78SToomas Soome ficlVmThrowError(vm, "Error: out of memory"); 744*a1bf3f78SToomas Soome 745*a1bf3f78SToomas Soome pager_open(); 746*a1bf3f78SToomas Soome for (i = 0; i < hash->size; i++) { 747*a1bf3f78SToomas Soome for (wp = hash->table[i]; wp != NULL; wp = wp->link, nWords++) { 748*a1bf3f78SToomas Soome if (wp->length == 0) /* ignore :noname defs */ 749*a1bf3f78SToomas Soome continue; 750*a1bf3f78SToomas Soome 751*a1bf3f78SToomas Soome /* prevent line wrap due to long words */ 752*a1bf3f78SToomas Soome if (nChars + wp->length >= columns) { 753*a1bf3f78SToomas Soome pPad[nChars++] = '\n'; 754*a1bf3f78SToomas Soome pPad[nChars] = '\0'; 755*a1bf3f78SToomas Soome nChars = 0; 756*a1bf3f78SToomas Soome if (pager_output(pPad)) 757*a1bf3f78SToomas Soome goto pager_done; 758*a1bf3f78SToomas Soome } 759*a1bf3f78SToomas Soome 760*a1bf3f78SToomas Soome cp = wp->name; 761*a1bf3f78SToomas Soome nChars += sprintf(pPad + nChars, "%s", cp); 762*a1bf3f78SToomas Soome 763*a1bf3f78SToomas Soome if (nChars > columns - 10) { 764*a1bf3f78SToomas Soome pPad[nChars++] = '\n'; 765*a1bf3f78SToomas Soome pPad[nChars] = '\0'; 766*a1bf3f78SToomas Soome nChars = 0; 767*a1bf3f78SToomas Soome if (pager_output(pPad)) 768*a1bf3f78SToomas Soome goto pager_done; 769*a1bf3f78SToomas Soome } else { 770*a1bf3f78SToomas Soome len = nCOLWIDTH - nChars % nCOLWIDTH; 771*a1bf3f78SToomas Soome while (len-- > 0) 772*a1bf3f78SToomas Soome pPad[nChars++] = ' '; 773*a1bf3f78SToomas Soome } 774*a1bf3f78SToomas Soome 775*a1bf3f78SToomas Soome if (nChars > columns - 10) { 776*a1bf3f78SToomas Soome pPad[nChars++] = '\n'; 777*a1bf3f78SToomas Soome pPad[nChars] = '\0'; 778*a1bf3f78SToomas Soome nChars = 0; 779*a1bf3f78SToomas Soome if (pager_output(pPad)) 780*a1bf3f78SToomas Soome goto pager_done; 781*a1bf3f78SToomas Soome } 782*a1bf3f78SToomas Soome } 783*a1bf3f78SToomas Soome } 784*a1bf3f78SToomas Soome 785*a1bf3f78SToomas Soome if (nChars > 0) { 786*a1bf3f78SToomas Soome pPad[nChars++] = '\n'; 787*a1bf3f78SToomas Soome pPad[nChars] = '\0'; 788*a1bf3f78SToomas Soome nChars = 0; 789*a1bf3f78SToomas Soome ficlVmTextOut(vm, pPad); 790*a1bf3f78SToomas Soome } 791*a1bf3f78SToomas Soome 792*a1bf3f78SToomas Soome sprintf(pPad, "Dictionary: %d words, %ld cells used of %u total\n", 793*a1bf3f78SToomas Soome nWords, (long)(dictionary->here - dictionary->base), 794*a1bf3f78SToomas Soome dictionary->size); 795*a1bf3f78SToomas Soome pager_output(pPad); 796*a1bf3f78SToomas Soome 797*a1bf3f78SToomas Soome pager_done: 798*a1bf3f78SToomas Soome free(pPad); 799*a1bf3f78SToomas Soome pager_close(); 800*a1bf3f78SToomas Soome } 801*a1bf3f78SToomas Soome 802*a1bf3f78SToomas Soome /* 803*a1bf3f78SToomas Soome * l i s t E n v 804*a1bf3f78SToomas Soome * Print symbols defined in the environment 805*a1bf3f78SToomas Soome */ 806*a1bf3f78SToomas Soome static void 807*a1bf3f78SToomas Soome ficlPrimitiveListEnv(ficlVm *vm) 808*a1bf3f78SToomas Soome { 809*a1bf3f78SToomas Soome ficlDictionary *dictionary = vm->callback.system->environment; 810*a1bf3f78SToomas Soome ficlHash *hash = dictionary->forthWordlist; 811*a1bf3f78SToomas Soome ficlWord *word; 812*a1bf3f78SToomas Soome unsigned i; 813*a1bf3f78SToomas Soome int counter = 0; 814*a1bf3f78SToomas Soome 815*a1bf3f78SToomas Soome pager_open(); 816*a1bf3f78SToomas Soome for (i = 0; i < hash->size; i++) { 817*a1bf3f78SToomas Soome for (word = hash->table[i]; word != NULL; 818*a1bf3f78SToomas Soome word = word->link, counter++) { 819*a1bf3f78SToomas Soome sprintf(vm->pad, "%s\n", word->name); 820*a1bf3f78SToomas Soome if (pager_output(vm->pad)) 821*a1bf3f78SToomas Soome goto pager_done; 822*a1bf3f78SToomas Soome } 823*a1bf3f78SToomas Soome } 824*a1bf3f78SToomas Soome 825*a1bf3f78SToomas Soome sprintf(vm->pad, "Environment: %d words, %ld cells used of %u total\n", 826*a1bf3f78SToomas Soome counter, (long)(dictionary->here - dictionary->base), 827*a1bf3f78SToomas Soome dictionary->size); 828*a1bf3f78SToomas Soome pager_output(vm->pad); 829*a1bf3f78SToomas Soome 830*a1bf3f78SToomas Soome pager_done: 831*a1bf3f78SToomas Soome pager_close(); 832*a1bf3f78SToomas Soome } 833*a1bf3f78SToomas Soome 834*a1bf3f78SToomas Soome /* 835*a1bf3f78SToomas Soome * This word lists the parse steps in order 836*a1bf3f78SToomas Soome */ 837*a1bf3f78SToomas Soome void 838*a1bf3f78SToomas Soome ficlPrimitiveParseStepList(ficlVm *vm) 839*a1bf3f78SToomas Soome { 840*a1bf3f78SToomas Soome int i; 841*a1bf3f78SToomas Soome ficlSystem *system = vm->callback.system; 842*a1bf3f78SToomas Soome FICL_VM_ASSERT(vm, system); 843*a1bf3f78SToomas Soome 844*a1bf3f78SToomas Soome ficlVmTextOut(vm, "Parse steps:\n"); 845*a1bf3f78SToomas Soome ficlVmTextOut(vm, "lookup\n"); 846*a1bf3f78SToomas Soome 847*a1bf3f78SToomas Soome for (i = 0; i < FICL_MAX_PARSE_STEPS; i++) { 848*a1bf3f78SToomas Soome if (system->parseList[i] != NULL) { 849*a1bf3f78SToomas Soome ficlVmTextOut(vm, system->parseList[i]->name); 850*a1bf3f78SToomas Soome ficlVmTextOut(vm, "\n"); 851*a1bf3f78SToomas Soome } else 852*a1bf3f78SToomas Soome break; 853*a1bf3f78SToomas Soome } 854*a1bf3f78SToomas Soome } 855*a1bf3f78SToomas Soome 856*a1bf3f78SToomas Soome /* 857*a1bf3f78SToomas Soome * e n v C o n s t a n t 858*a1bf3f78SToomas Soome * Ficl interface to ficlSystemSetEnvironment and ficlSetEnvD - allow Ficl 859*a1bf3f78SToomas Soome * code to set environment constants... 860*a1bf3f78SToomas Soome */ 861*a1bf3f78SToomas Soome static void 862*a1bf3f78SToomas Soome ficlPrimitiveEnvConstant(ficlVm *vm) 863*a1bf3f78SToomas Soome { 864*a1bf3f78SToomas Soome unsigned value; 865*a1bf3f78SToomas Soome FICL_STACK_CHECK(vm->dataStack, 1, 0); 866*a1bf3f78SToomas Soome 867*a1bf3f78SToomas Soome ficlVmGetWordToPad(vm); 868*a1bf3f78SToomas Soome value = ficlStackPopUnsigned(vm->dataStack); 869*a1bf3f78SToomas Soome ficlDictionarySetConstant(ficlSystemGetEnvironment(vm->callback.system), 870*a1bf3f78SToomas Soome vm->pad, (ficlUnsigned)value); 871*a1bf3f78SToomas Soome } 872*a1bf3f78SToomas Soome 873*a1bf3f78SToomas Soome static void 874*a1bf3f78SToomas Soome ficlPrimitiveEnv2Constant(ficlVm *vm) 875*a1bf3f78SToomas Soome { 876*a1bf3f78SToomas Soome ficl2Integer value; 877*a1bf3f78SToomas Soome 878*a1bf3f78SToomas Soome FICL_STACK_CHECK(vm->dataStack, 2, 0); 879*a1bf3f78SToomas Soome 880*a1bf3f78SToomas Soome ficlVmGetWordToPad(vm); 881*a1bf3f78SToomas Soome value = ficlStackPop2Integer(vm->dataStack); 882*a1bf3f78SToomas Soome ficlDictionarySet2Constant( 883*a1bf3f78SToomas Soome ficlSystemGetEnvironment(vm->callback.system), vm->pad, value); 884*a1bf3f78SToomas Soome } 885*a1bf3f78SToomas Soome 886*a1bf3f78SToomas Soome 887*a1bf3f78SToomas Soome /* 888*a1bf3f78SToomas Soome * f i c l C o m p i l e T o o l s 889*a1bf3f78SToomas Soome * Builds wordset for debugger and TOOLS optional word set 890*a1bf3f78SToomas Soome */ 891*a1bf3f78SToomas Soome void 892*a1bf3f78SToomas Soome ficlSystemCompileTools(ficlSystem *system) 893*a1bf3f78SToomas Soome { 894*a1bf3f78SToomas Soome ficlDictionary *dictionary = ficlSystemGetDictionary(system); 895*a1bf3f78SToomas Soome ficlDictionary *environment = ficlSystemGetEnvironment(system); 896*a1bf3f78SToomas Soome 897*a1bf3f78SToomas Soome FICL_SYSTEM_ASSERT(system, dictionary); 898*a1bf3f78SToomas Soome FICL_SYSTEM_ASSERT(system, environment); 899*a1bf3f78SToomas Soome 900*a1bf3f78SToomas Soome 901*a1bf3f78SToomas Soome /* 902*a1bf3f78SToomas Soome * TOOLS and TOOLS EXT 903*a1bf3f78SToomas Soome */ 904*a1bf3f78SToomas Soome ficlDictionarySetPrimitive(dictionary, ".s", ficlVmDisplayDataStack, 905*a1bf3f78SToomas Soome FICL_WORD_DEFAULT); 906*a1bf3f78SToomas Soome ficlDictionarySetPrimitive(dictionary, ".s-simple", 907*a1bf3f78SToomas Soome ficlVmDisplayDataStackSimple, FICL_WORD_DEFAULT); 908*a1bf3f78SToomas Soome ficlDictionarySetPrimitive(dictionary, "bye", ficlPrimitiveBye, 909*a1bf3f78SToomas Soome FICL_WORD_DEFAULT); 910*a1bf3f78SToomas Soome ficlDictionarySetPrimitive(dictionary, "forget", ficlPrimitiveForget, 911*a1bf3f78SToomas Soome FICL_WORD_DEFAULT); 912*a1bf3f78SToomas Soome ficlDictionarySetPrimitive(dictionary, "see", ficlPrimitiveSee, 913*a1bf3f78SToomas Soome FICL_WORD_DEFAULT); 914*a1bf3f78SToomas Soome ficlDictionarySetPrimitive(dictionary, "words", ficlPrimitiveWords, 915*a1bf3f78SToomas Soome FICL_WORD_DEFAULT); 916*a1bf3f78SToomas Soome 917*a1bf3f78SToomas Soome /* 918*a1bf3f78SToomas Soome * Set TOOLS environment query values 919*a1bf3f78SToomas Soome */ 920*a1bf3f78SToomas Soome ficlDictionarySetConstant(environment, "tools", FICL_TRUE); 921*a1bf3f78SToomas Soome ficlDictionarySetConstant(environment, "tools-ext", FICL_FALSE); 922*a1bf3f78SToomas Soome 923*a1bf3f78SToomas Soome /* 924*a1bf3f78SToomas Soome * Ficl extras 925*a1bf3f78SToomas Soome */ 926*a1bf3f78SToomas Soome ficlDictionarySetPrimitive(dictionary, "r.s", ficlVmDisplayReturnStack, 927*a1bf3f78SToomas Soome FICL_WORD_DEFAULT); 928*a1bf3f78SToomas Soome ficlDictionarySetPrimitive(dictionary, ".env", ficlPrimitiveListEnv, 929*a1bf3f78SToomas Soome FICL_WORD_DEFAULT); 930*a1bf3f78SToomas Soome ficlDictionarySetPrimitive(dictionary, "env-constant", 931*a1bf3f78SToomas Soome ficlPrimitiveEnvConstant, FICL_WORD_DEFAULT); 932*a1bf3f78SToomas Soome ficlDictionarySetPrimitive(dictionary, "env-2constant", 933*a1bf3f78SToomas Soome ficlPrimitiveEnv2Constant, FICL_WORD_DEFAULT); 934*a1bf3f78SToomas Soome ficlDictionarySetPrimitive(dictionary, "debug-xt", ficlPrimitiveDebugXT, 935*a1bf3f78SToomas Soome FICL_WORD_DEFAULT); 936*a1bf3f78SToomas Soome ficlDictionarySetPrimitive(dictionary, "parse-order", 937*a1bf3f78SToomas Soome ficlPrimitiveParseStepList, FICL_WORD_DEFAULT); 938*a1bf3f78SToomas Soome ficlDictionarySetPrimitive(dictionary, "step-break", 939*a1bf3f78SToomas Soome ficlPrimitiveStepBreak, FICL_WORD_DEFAULT); 940*a1bf3f78SToomas Soome ficlDictionarySetPrimitive(dictionary, "forget-wid", 941*a1bf3f78SToomas Soome ficlPrimitiveForgetWid, FICL_WORD_DEFAULT); 942*a1bf3f78SToomas Soome ficlDictionarySetPrimitive(dictionary, "see-xt", ficlPrimitiveSeeXT, 943*a1bf3f78SToomas Soome FICL_WORD_DEFAULT); 944*a1bf3f78SToomas Soome 945*a1bf3f78SToomas Soome #if FICL_WANT_FLOAT 946*a1bf3f78SToomas Soome ficlDictionarySetPrimitive(dictionary, ".hash", 947*a1bf3f78SToomas Soome ficlPrimitiveHashSummary, FICL_WORD_DEFAULT); 948*a1bf3f78SToomas Soome #endif 949*a1bf3f78SToomas Soome } 950