/* * p r e f i x . c * Forth Inspired Command Language * Parser extensions for Ficl * Authors: Larry Hastings & John Sadler (john_sadler@alum.mit.edu) * Created: April 2001 * $Id: prefix.c,v 1.8 2010/09/13 18:43:04 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 "ficl.h" /* * (jws) revisions: * A prefix is a word in a dedicated wordlist (name stored in list_name below) * that is searched in a special way by the prefix parse step. When a prefix * matches the beginning of an incoming token, push the non-prefix part of the * token back onto the input stream and execute the prefix code. * * The parse step is called ficlParsePrefix. * Storing prefix entries in the dictionary greatly simplifies * the process of matching and dispatching prefixes, avoids the * need to clean up a dynamically allocated prefix list when the system * goes away, but still allows prefixes to be allocated at runtime. */ static char list_name[] = ""; /* * f i c l P a r s e P r e f i x * This is the parse step for prefixes - it checks an incoming word * to see if it starts with a prefix, and if so runs the corresponding * code against the remainder of the word and returns true. */ int ficlVmParsePrefix(ficlVm *vm, ficlString s) { int i; ficlHash *hash; ficlWord *word = ficlSystemLookup(vm->callback.system, list_name); /* * Make sure we found the prefix dictionary - otherwise silently fail * If forth-wordlist is not in the search order, we won't find the * prefixes. */ if (!word) return (0); /* false */ hash = (ficlHash *)(word->param[0].p); /* * Walk the list looking for a match with the beginning of the * incoming token */ for (i = 0; i < (int)hash->size; i++) { word = hash->table[i]; while (word != NULL) { int n; n = word->length; /* * If we find a match, adjust the TIB to give back * the non-prefix characters and execute the prefix * word. */ if (!ficlStrincmp(FICL_STRING_GET_POINTER(s), word->name, (ficlUnsigned)n)) { /* * (sadler) fixed off-by-one error when the * token has no trailing space in the TIB */ ficlVmSetTibIndex(vm, s.text + n - vm->tib.text); ficlVmExecuteWord(vm, word); return (1); /* true */ } word = word->link; } } return (0); /* false */ } static void ficlPrimitiveTempBase(ficlVm *vm) { int oldbase = vm->base; ficlString number = ficlVmGetWord0(vm); int base = ficlStackPopInteger(vm->dataStack); vm->base = base; if (!ficlVmParseNumber(vm, number)) ficlVmThrowError(vm, "%.*s not recognized", FICL_STRING_GET_LENGTH(number), FICL_STRING_GET_POINTER(number)); vm->base = oldbase; } /* * f i c l C o m p i l e P r e f i x * Build prefix support into the dictionary and the parser * Note: since prefixes always execute, they are effectively IMMEDIATE. * If they need to generate code in compile state you must add * this code explicitly. */ void ficlSystemCompilePrefix(ficlSystem *system) { ficlDictionary *dictionary = system->dictionary; ficlHash *hash; /* * Create a named wordlist for prefixes to reside in... * Since we're doing a special kind of search, make it * a single bucket hashtable - hashing does not help here. */ hash = ficlDictionaryCreateWordlist(dictionary, 1); hash->name = list_name; ficlDictionaryAppendConstantPointer(dictionary, list_name, hash); /* * Put __tempbase in the forth-wordlist */ (void) ficlDictionarySetPrimitive(dictionary, "__tempbase", ficlPrimitiveTempBase, FICL_WORD_DEFAULT); /* * If you want to add some prefixes at compilation-time, copy this * line to the top of this function: * * ficlHash *oldCompilationWordlist; * * then copy this code to the bottom, just above the return: * * * oldCompilationWordlist = dictionary->compilationWordlist; * dictionary->compilationWordlist = hash; * ficlDictionarySetPrimitive(dictionary, YOUR WORD HERE, * FICL_WORD_DEFAULT); * dictionary->compilationWordlist = oldCompilationWordlist; * * and substitute in your own actual calls to * ficlDictionarySetPrimitive() as needed. * * Or--better yet--do it in your own code, so you don't have * to re-modify the Ficl source code every time we cut a new release! */ }