| /* |
| * 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 <string.h> |
| #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 |
| */ |
| ficlDictionarySetPrimitive(dictionary, ">search", |
| ficlPrimitiveSearchPush, FICL_WORD_DEFAULT); |
| ficlDictionarySetPrimitive(dictionary, "search>", |
| ficlPrimitiveSearchPop, FICL_WORD_DEFAULT); |
| ficlDictionarySetPrimitive(dictionary, "definitions", |
| ficlPrimitiveDefinitions, FICL_WORD_DEFAULT); |
| ficlDictionarySetPrimitive(dictionary, "forth-wordlist", |
| ficlPrimitiveForthWordlist, FICL_WORD_DEFAULT); |
| ficlDictionarySetPrimitive(dictionary, "get-current", |
| ficlPrimitiveGetCurrent, FICL_WORD_DEFAULT); |
| ficlDictionarySetPrimitive(dictionary, "get-order", |
| ficlPrimitiveGetOrder, FICL_WORD_DEFAULT); |
| ficlDictionarySetPrimitive(dictionary, "search-wordlist", |
| ficlPrimitiveSearchWordlist, FICL_WORD_DEFAULT); |
| ficlDictionarySetPrimitive(dictionary, "set-current", |
| ficlPrimitiveSetCurrent, FICL_WORD_DEFAULT); |
| ficlDictionarySetPrimitive(dictionary, "set-order", |
| ficlPrimitiveSetOrder, FICL_WORD_DEFAULT); |
| ficlDictionarySetPrimitive(dictionary, "ficl-wordlist", |
| ficlPrimitiveFiclWordlist, FICL_WORD_DEFAULT); |
| |
| /* |
| * Set SEARCH environment query values |
| */ |
| ficlDictionarySetConstant(environment, "search-order", FICL_TRUE); |
| ficlDictionarySetConstant(environment, "search-order-ext", FICL_TRUE); |
| ficlDictionarySetConstant(environment, "wordlists", FICL_MAX_WORDLISTS); |
| ficlDictionarySetPrimitive(dictionary, "wid-get-name", |
| ficlPrimitiveWidGetName, FICL_WORD_DEFAULT); |
| ficlDictionarySetPrimitive(dictionary, "wid-set-name", |
| ficlPrimitiveWidSetName, FICL_WORD_DEFAULT); |
| ficlDictionarySetPrimitive(dictionary, "wid-set-super", |
| ficlPrimitiveSetParentWid, FICL_WORD_DEFAULT); |
| } |