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