1 /******************************************************************* 2 ** p r e f i x . c 3 ** Forth Inspired Command Language 4 ** Parser extensions for Ficl 5 ** Authors: Larry Hastings & John Sadler (john_sadler@alum.mit.edu) 6 ** Created: April 2001 7 ** $Id: prefix.c,v 1.6 2001/12/05 07:21:34 jsadler Exp $ 8 *******************************************************************/ 9 /* 10 ** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu) 11 ** All rights reserved. 12 ** 13 ** Get the latest Ficl release at http://ficl.sourceforge.net 14 ** 15 ** I am interested in hearing from anyone who uses ficl. If you have 16 ** a problem, a success story, a defect, an enhancement request, or 17 ** if you would like to contribute to the ficl release, please 18 ** contact me by email at the address above. 19 ** 20 ** L I C E N S E and D I S C L A I M E R 21 ** 22 ** Redistribution and use in source and binary forms, with or without 23 ** modification, are permitted provided that the following conditions 24 ** are met: 25 ** 1. Redistributions of source code must retain the above copyright 26 ** notice, this list of conditions and the following disclaimer. 27 ** 2. Redistributions in binary form must reproduce the above copyright 28 ** notice, this list of conditions and the following disclaimer in the 29 ** documentation and/or other materials provided with the distribution. 30 ** 31 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 32 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 33 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 34 ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 35 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 39 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 40 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 41 ** SUCH DAMAGE. 42 */ 43 44 /* $FreeBSD$ */ 45 46 #include <string.h> 47 #include <ctype.h> 48 #include "ficl.h" 49 #include "math64.h" 50 51 /* 52 ** (jws) revisions: 53 ** A prefix is a word in a dedicated wordlist (name stored in list_name below) 54 ** that is searched in a special way by the prefix parse step. When a prefix 55 ** matches the beginning of an incoming token, push the non-prefix part of the 56 ** token back onto the input stream and execute the prefix code. 57 ** 58 ** The parse step is called ficlParsePrefix. 59 ** Storing prefix entries in the dictionary greatly simplifies 60 ** the process of matching and dispatching prefixes, avoids the 61 ** need to clean up a dynamically allocated prefix list when the system 62 ** goes away, but still allows prefixes to be allocated at runtime. 63 */ 64 65 static char list_name[] = "<prefixes>"; 66 67 /************************************************************************** 68 f i c l P a r s e P r e f i x 69 ** This is the parse step for prefixes - it checks an incoming word 70 ** to see if it starts with a prefix, and if so runs the corrseponding 71 ** code against the remainder of the word and returns true. 72 **************************************************************************/ 73 int ficlParsePrefix(FICL_VM *pVM, STRINGINFO si) 74 { 75 int i; 76 FICL_HASH *pHash; 77 FICL_WORD *pFW = ficlLookup(pVM->pSys, list_name); 78 79 /* 80 ** Make sure we found the prefix dictionary - otherwise silently fail 81 ** If forth-wordlist is not in the search order, we won't find the prefixes. 82 */ 83 if (!pFW) 84 return FICL_FALSE; 85 86 pHash = (FICL_HASH *)(pFW->param[0].p); 87 /* 88 ** Walk the list looking for a match with the beginning of the incoming token 89 */ 90 for (i = 0; i < (int)pHash->size; i++) 91 { 92 pFW = pHash->table[i]; 93 while (pFW != NULL) 94 { 95 int n; 96 n = pFW->nName; 97 /* 98 ** If we find a match, adjust the TIB to give back the non-prefix characters 99 ** and execute the prefix word. 100 */ 101 if (!strincmp(SI_PTR(si), pFW->name, (FICL_UNS)n)) 102 { 103 /* (sadler) fixed off-by-one error when the token has no trailing space in the TIB */ 104 vmSetTibIndex(pVM, si.cp + n - pVM->tib.cp ); 105 vmExecute(pVM, pFW); 106 107 return (int)FICL_TRUE; 108 } 109 pFW = pFW->link; 110 } 111 } 112 113 return FICL_FALSE; 114 } 115 116 117 static void tempBase(FICL_VM *pVM, int base) 118 { 119 int oldbase = pVM->base; 120 STRINGINFO si = vmGetWord0(pVM); 121 122 pVM->base = base; 123 if (!ficlParseNumber(pVM, si)) 124 { 125 int i = SI_COUNT(si); 126 vmThrowErr(pVM, "%.*s not recognized", i, SI_PTR(si)); 127 } 128 129 pVM->base = oldbase; 130 return; 131 } 132 133 static void fTempBase(FICL_VM *pVM) 134 { 135 int base = stackPopINT(pVM->pStack); 136 tempBase(pVM, base); 137 return; 138 } 139 140 static void prefixHex(FICL_VM *pVM) 141 { 142 tempBase(pVM, 16); 143 } 144 145 static void prefixTen(FICL_VM *pVM) 146 { 147 tempBase(pVM, 10); 148 } 149 150 151 /************************************************************************** 152 f i c l C o m p i l e P r e f i x 153 ** Build prefix support into the dictionary and the parser 154 ** Note: since prefixes always execute, they are effectively IMMEDIATE. 155 ** If they need to generate code in compile state you must add 156 ** this code explicitly. 157 **************************************************************************/ 158 void ficlCompilePrefix(FICL_SYSTEM *pSys) 159 { 160 FICL_DICT *dp = pSys->dp; 161 FICL_HASH *pHash; 162 FICL_HASH *pPrevCompile = dp->pCompile; 163 #if (FICL_EXTENDED_PREFIX) 164 FICL_WORD *pFW; 165 #endif 166 167 /* 168 ** Create a named wordlist for prefixes to reside in... 169 ** Since we're doing a special kind of search, make it 170 ** a single bucket hashtable - hashing does not help here. 171 */ 172 pHash = dictCreateWordlist(dp, 1); 173 pHash->name = list_name; 174 dictAppendWord(dp, list_name, constantParen, FW_DEFAULT); 175 dictAppendCell(dp, LVALUEtoCELL(pHash)); 176 177 /* 178 ** Put __tempbase in the forth-wordlist 179 */ 180 dictAppendWord(dp, "__tempbase", fTempBase, FW_DEFAULT); 181 182 /* 183 ** Temporarily make the prefix list the compile wordlist so that 184 ** we can create some precompiled prefixes. 185 */ 186 dp->pCompile = pHash; 187 dictAppendWord(dp, "0x", prefixHex, FW_DEFAULT); 188 dictAppendWord(dp, "0d", prefixTen, FW_DEFAULT); 189 #if (FICL_EXTENDED_PREFIX) 190 pFW = ficlLookup(pSys, "\\"); 191 if (pFW) 192 { 193 dictAppendWord(dp, "//", pFW->code, FW_DEFAULT); 194 } 195 #endif 196 dp->pCompile = pPrevCompile; 197 198 return; 199 } 200