/* * s e a r c h . c * Forth Inspired Command Language * ANS Forth SEARCH and SEARCH-EXT word-set written in C * Author: John Sadler (john_sadler@alum.mit.edu) * Created: 6 June 2000 * $Id: search.c,v 1.10 2010/08/12 13:57:22 asau Exp $ */ /* * Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu) * All rights reserved. * * Get the latest Ficl release at http://ficl.sourceforge.net * * I am interested in hearing from anyone who uses Ficl. If you have * a problem, a success story, a defect, an enhancement request, or * if you would like to contribute to the Ficl release, please * contact me by email at the address above. * * L I C E N S E and D I S C L A I M E R * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include "ficl.h" /* * d e f i n i t i o n s * SEARCH ( -- ) * Make the compilation word list the same as the first word list in the * search order. Specifies that the names of subsequent definitions will * be placed in the compilation word list. Subsequent changes in the search * order will not affect the compilation word list. */ static void ficlPrimitiveDefinitions(ficlVm *vm) { ficlDictionary *dictionary = ficlVmGetDictionary(vm); FICL_VM_ASSERT(vm, dictionary); if (dictionary->wordlistCount < 1) { ficlVmThrowError(vm, "DEFINITIONS error - empty search order"); } dictionary->compilationWordlist = dictionary->wordlists[dictionary->wordlistCount-1]; } /* * f o r t h - w o r d l i s t * SEARCH ( -- wid ) * Return wid, the identifier of the word list that includes all standard * words provided by the implementation. This word list is initially the * compilation word list and is part of the initial search order. */ static void ficlPrimitiveForthWordlist(ficlVm *vm) { ficlHash *hash = ficlVmGetDictionary(vm)->forthWordlist; ficlStackPushPointer(vm->dataStack, hash); } /* * g e t - c u r r e n t * SEARCH ( -- wid ) * Return wid, the identifier of the compilation word list. */ static void ficlPrimitiveGetCurrent(ficlVm *vm) { ficlDictionary *dictionary = ficlVmGetDictionary(vm); ficlDictionaryLock(dictionary, FICL_TRUE); ficlStackPushPointer(vm->dataStack, dictionary->compilationWordlist); ficlDictionaryLock(dictionary, FICL_FALSE); } /* * g e t - o r d e r * SEARCH ( -- widn ... wid1 n ) * Returns the number of word lists n in the search order and the word list * identifiers widn ... wid1 identifying these word lists. wid1 identifies * the word list that is searched first, and widn the word list that is * searched last. The search order is unaffected. */ static void ficlPrimitiveGetOrder(ficlVm *vm) { ficlDictionary *dictionary = ficlVmGetDictionary(vm); int wordlistCount = dictionary->wordlistCount; int i; ficlDictionaryLock(dictionary, FICL_TRUE); for (i = 0; i < wordlistCount; i++) { ficlStackPushPointer(vm->dataStack, dictionary->wordlists[i]); } ficlStackPushUnsigned(vm->dataStack, wordlistCount); ficlDictionaryLock(dictionary, FICL_FALSE); } /* * s e a r c h - w o r d l i s t * SEARCH ( c-addr u wid -- 0 | xt 1 | xt -1 ) * Find the definition identified by the string c-addr u in the word list * identified by wid. If the definition is not found, return zero. If the * definition is found, return its execution token xt and one (1) if the * definition is immediate, minus-one (-1) otherwise. */ static void ficlPrimitiveSearchWordlist(ficlVm *vm) { ficlString name; ficlUnsigned16 hashCode; ficlWord *word; ficlHash *hash = ficlStackPopPointer(vm->dataStack); name.length = (ficlUnsigned8)ficlStackPopUnsigned(vm->dataStack); name.text = ficlStackPopPointer(vm->dataStack); hashCode = ficlHashCode(name); ficlDictionaryLock(ficlVmGetDictionary(vm), FICL_TRUE); word = ficlHashLookup(hash, name, hashCode); ficlDictionaryLock(ficlVmGetDictionary(vm), FICL_FALSE); if (word) { ficlStackPushPointer(vm->dataStack, word); ficlStackPushInteger(vm->dataStack, (ficlWordIsImmediate(word) ? 1 : -1)); } else { ficlStackPushUnsigned(vm->dataStack, 0); } } /* * s e t - c u r r e n t * SEARCH ( wid -- ) * Set the compilation word list to the word list identified by wid. */ static void ficlPrimitiveSetCurrent(ficlVm *vm) { ficlHash *hash = ficlStackPopPointer(vm->dataStack); ficlDictionary *dictionary = ficlVmGetDictionary(vm); ficlDictionaryLock(dictionary, FICL_TRUE); dictionary->compilationWordlist = hash; ficlDictionaryLock(dictionary, FICL_FALSE); } /* * s e t - o r d e r * SEARCH ( widn ... wid1 n -- ) * Set the search order to the word lists identified by widn ... wid1. * Subsequently, word list wid1 will be searched first, and word list * widn searched last. If n is zero, empty the search order. If n is minus * one, set the search order to the implementation-defined minimum * search order. The minimum search order shall include the words * FORTH-WORDLIST and SET-ORDER. A system shall allow n to * be at least eight. */ static void ficlPrimitiveSetOrder(ficlVm *vm) { int i; int wordlistCount = ficlStackPopInteger(vm->dataStack); ficlDictionary *dictionary = ficlVmGetDictionary(vm); if (wordlistCount > FICL_MAX_WORDLISTS) { ficlVmThrowError(vm, "set-order error: list would be too large"); } ficlDictionaryLock(dictionary, FICL_TRUE); if (wordlistCount >= 0) { dictionary->wordlistCount = wordlistCount; for (i = wordlistCount-1; i >= 0; --i) { dictionary->wordlists[i] = ficlStackPopPointer(vm->dataStack); } } else { ficlDictionaryResetSearchOrder(dictionary); } ficlDictionaryLock(dictionary, FICL_FALSE); } /* * f i c l - w o r d l i s t * SEARCH ( -- wid ) * Create a new empty word list, returning its word list identifier wid. * The new word list may be returned from a pool of preallocated word * lists or may be dynamically allocated in data space. A system shall * allow the creation of at least 8 new word lists in addition to any * provided as part of the system. * Notes: * 1. Ficl creates a new single-list hash in the dictionary and returns * its address. * 2. ficl-wordlist takes an arg off the stack indicating the number of * hash entries in the wordlist. Ficl 2.02 and later define WORDLIST as * : wordlist 1 ficl-wordlist ; */ static void ficlPrimitiveFiclWordlist(ficlVm *vm) { ficlDictionary *dictionary = ficlVmGetDictionary(vm); ficlHash *hash; ficlUnsigned nBuckets; FICL_STACK_CHECK(vm->dataStack, 1, 1); nBuckets = ficlStackPopUnsigned(vm->dataStack); hash = ficlDictionaryCreateWordlist(dictionary, nBuckets); ficlStackPushPointer(vm->dataStack, hash); } /* * S E A R C H > * Ficl ( -- wid ) * Pop wid off the search order. Error if the search order is empty */ static void ficlPrimitiveSearchPop(ficlVm *vm) { ficlDictionary *dictionary = ficlVmGetDictionary(vm); int wordlistCount; ficlDictionaryLock(dictionary, FICL_TRUE); wordlistCount = dictionary->wordlistCount; if (wordlistCount == 0) { ficlVmThrowError(vm, "search> error: empty search order"); } ficlStackPushPointer(vm->dataStack, dictionary->wordlists[--dictionary->wordlistCount]); ficlDictionaryLock(dictionary, FICL_FALSE); } /* * > S E A R C H * Ficl ( wid -- ) * Push wid onto the search order. Error if the search order is full. */ static void ficlPrimitiveSearchPush(ficlVm *vm) { ficlDictionary *dictionary = ficlVmGetDictionary(vm); ficlDictionaryLock(dictionary, FICL_TRUE); if (dictionary->wordlistCount > FICL_MAX_WORDLISTS) { ficlVmThrowError(vm, ">search error: search order overflow"); } dictionary->wordlists[dictionary->wordlistCount++] = ficlStackPopPointer(vm->dataStack); ficlDictionaryLock(dictionary, FICL_FALSE); } /* * W I D - G E T - N A M E * Ficl ( wid -- c-addr u ) * Get wid's (optional) name and push onto stack as a counted string */ static void ficlPrimitiveWidGetName(ficlVm *vm) { ficlHash *hash; char *name; ficlInteger length; ficlCell c; hash = ficlVmPop(vm).p; name = hash->name; if (name != NULL) length = strlen(name); else length = 0; c.p = name; ficlVmPush(vm, c); c.i = length; ficlVmPush(vm, c); } /* * W I D - S E T - N A M E * Ficl ( wid c-addr -- ) * Set wid's name pointer to the \0 terminated string address supplied */ static void ficlPrimitiveWidSetName(ficlVm *vm) { char *name = (char *)ficlVmPop(vm).p; ficlHash *hash = ficlVmPop(vm).p; hash->name = name; } /* * setParentWid * Ficl * setparentwid ( parent-wid wid -- ) * Set WID's link field to the parent-wid. search-wordlist will * iterate through all the links when finding words in the child wid. */ static void ficlPrimitiveSetParentWid(ficlVm *vm) { ficlHash *parent, *child; FICL_STACK_CHECK(vm->dataStack, 2, 0); child = (ficlHash *)ficlStackPopPointer(vm->dataStack); parent = (ficlHash *)ficlStackPopPointer(vm->dataStack); child->link = parent; } /* * f i c l C o m p i l e S e a r c h * Builds the primitive wordset and the environment-query namespace. */ void ficlSystemCompileSearch(ficlSystem *system) { ficlDictionary *dictionary = ficlSystemGetDictionary(system); ficlDictionary *environment = ficlSystemGetEnvironment(system); FICL_SYSTEM_ASSERT(system, dictionary); FICL_SYSTEM_ASSERT(system, environment); /* * optional SEARCH-ORDER word set */ (void) ficlDictionarySetPrimitive(dictionary, ">search", ficlPrimitiveSearchPush, FICL_WORD_DEFAULT); (void) ficlDictionarySetPrimitive(dictionary, "search>", ficlPrimitiveSearchPop, FICL_WORD_DEFAULT); (void) ficlDictionarySetPrimitive(dictionary, "definitions", ficlPrimitiveDefinitions, FICL_WORD_DEFAULT); (void) ficlDictionarySetPrimitive(dictionary, "forth-wordlist", ficlPrimitiveForthWordlist, FICL_WORD_DEFAULT); (void) ficlDictionarySetPrimitive(dictionary, "get-current", ficlPrimitiveGetCurrent, FICL_WORD_DEFAULT); (void) ficlDictionarySetPrimitive(dictionary, "get-order", ficlPrimitiveGetOrder, FICL_WORD_DEFAULT); (void) ficlDictionarySetPrimitive(dictionary, "search-wordlist", ficlPrimitiveSearchWordlist, FICL_WORD_DEFAULT); (void) ficlDictionarySetPrimitive(dictionary, "set-current", ficlPrimitiveSetCurrent, FICL_WORD_DEFAULT); (void) ficlDictionarySetPrimitive(dictionary, "set-order", ficlPrimitiveSetOrder, FICL_WORD_DEFAULT); (void) ficlDictionarySetPrimitive(dictionary, "ficl-wordlist", ficlPrimitiveFiclWordlist, FICL_WORD_DEFAULT); /* * Set SEARCH environment query values */ (void) ficlDictionarySetConstant(environment, "search-order", FICL_TRUE); (void) ficlDictionarySetConstant(environment, "search-order-ext", FICL_TRUE); (void) ficlDictionarySetConstant(environment, "wordlists", FICL_MAX_WORDLISTS); (void) ficlDictionarySetPrimitive(dictionary, "wid-get-name", ficlPrimitiveWidGetName, FICL_WORD_DEFAULT); (void) ficlDictionarySetPrimitive(dictionary, "wid-set-name", ficlPrimitiveWidSetName, FICL_WORD_DEFAULT); (void) ficlDictionarySetPrimitive(dictionary, "wid-set-super", ficlPrimitiveSetParentWid, FICL_WORD_DEFAULT); }