176116Sdcs/*******************************************************************
276116Sdcs** p r e f i x . c
376116Sdcs** Forth Inspired Command Language
476116Sdcs** Parser extensions for Ficl
576116Sdcs** Authors: Larry Hastings & John Sadler (john_sadler@alum.mit.edu)
676116Sdcs** Created: April 2001
794290Sdcs** $Id: prefix.c,v 1.6 2001/12/05 07:21:34 jsadler Exp $
876116Sdcs*******************************************************************/
976116Sdcs/*
1076116Sdcs** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu)
1176116Sdcs** All rights reserved.
1276116Sdcs**
1376116Sdcs** Get the latest Ficl release at http://ficl.sourceforge.net
1476116Sdcs**
1594290Sdcs** I am interested in hearing from anyone who uses ficl. If you have
1694290Sdcs** a problem, a success story, a defect, an enhancement request, or
1794290Sdcs** if you would like to contribute to the ficl release, please
1894290Sdcs** contact me by email at the address above.
1994290Sdcs**
2076116Sdcs** L I C E N S E  and  D I S C L A I M E R
2176116Sdcs**
2276116Sdcs** Redistribution and use in source and binary forms, with or without
2376116Sdcs** modification, are permitted provided that the following conditions
2476116Sdcs** are met:
2576116Sdcs** 1. Redistributions of source code must retain the above copyright
2676116Sdcs**    notice, this list of conditions and the following disclaimer.
2776116Sdcs** 2. Redistributions in binary form must reproduce the above copyright
2876116Sdcs**    notice, this list of conditions and the following disclaimer in the
2976116Sdcs**    documentation and/or other materials provided with the distribution.
3076116Sdcs**
3176116Sdcs** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
3276116Sdcs** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3376116Sdcs** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3476116Sdcs** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
3576116Sdcs** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3676116Sdcs** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3776116Sdcs** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3876116Sdcs** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3976116Sdcs** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4076116Sdcs** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4176116Sdcs** SUCH DAMAGE.
4276116Sdcs*/
4376116Sdcs
4476116Sdcs/* $FreeBSD$ */
4576116Sdcs
4676116Sdcs#include <string.h>
4776116Sdcs#include <ctype.h>
4876116Sdcs#include "ficl.h"
4976116Sdcs#include "math64.h"
5076116Sdcs
5176116Sdcs/*
5276116Sdcs** (jws) revisions:
5376116Sdcs** A prefix is a word in a dedicated wordlist (name stored in list_name below)
5476116Sdcs** that is searched in a special way by the prefix parse step. When a prefix
5576116Sdcs** matches the beginning of an incoming token, push the non-prefix part of the
5676116Sdcs** token back onto the input stream and execute the prefix code.
5776116Sdcs**
5876116Sdcs** The parse step is called ficlParsePrefix.
5976116Sdcs** Storing prefix entries in the dictionary greatly simplifies
6076116Sdcs** the process of matching and dispatching prefixes, avoids the
6176116Sdcs** need to clean up a dynamically allocated prefix list when the system
6276116Sdcs** goes away, but still allows prefixes to be allocated at runtime.
6376116Sdcs*/
6476116Sdcs
6576116Sdcsstatic char list_name[] = "<prefixes>";
6676116Sdcs
6776116Sdcs/**************************************************************************
6876116Sdcs                        f i c l P a r s e P r e f i x
6976116Sdcs** This is the parse step for prefixes - it checks an incoming word
7076116Sdcs** to see if it starts with a prefix, and if so runs the corrseponding
7176116Sdcs** code against the remainder of the word and returns true.
7276116Sdcs**************************************************************************/
7376116Sdcsint ficlParsePrefix(FICL_VM *pVM, STRINGINFO si)
7476116Sdcs{
7576116Sdcs    int i;
7676116Sdcs    FICL_HASH *pHash;
7794290Sdcs    FICL_WORD *pFW = ficlLookup(pVM->pSys, list_name);
7876116Sdcs
7994290Sdcs    /*
8094290Sdcs    ** Make sure we found the prefix dictionary - otherwise silently fail
8194290Sdcs    ** If forth-wordlist is not in the search order, we won't find the prefixes.
8294290Sdcs    */
8394290Sdcs    if (!pFW)
8494290Sdcs        return FICL_FALSE;
8594290Sdcs
8676116Sdcs    pHash = (FICL_HASH *)(pFW->param[0].p);
8776116Sdcs    /*
8876116Sdcs    ** Walk the list looking for a match with the beginning of the incoming token
8976116Sdcs    */
9076116Sdcs    for (i = 0; i < (int)pHash->size; i++)
9176116Sdcs    {
9276116Sdcs        pFW = pHash->table[i];
9376116Sdcs        while (pFW != NULL)
9476116Sdcs        {
9576116Sdcs            int n;
9676116Sdcs            n = pFW->nName;
9776116Sdcs            /*
9876116Sdcs            ** If we find a match, adjust the TIB to give back the non-prefix characters
9976116Sdcs            ** and execute the prefix word.
10076116Sdcs            */
10176116Sdcs            if (!strincmp(SI_PTR(si), pFW->name, (FICL_UNS)n))
10276116Sdcs            {
10394290Sdcs                /* (sadler) fixed off-by-one error when the token has no trailing space in the TIB */
10494290Sdcs				vmSetTibIndex(pVM, si.cp + n - pVM->tib.cp );
10576116Sdcs                vmExecute(pVM, pFW);
10676116Sdcs
107102657Sscottl                return (int)FICL_TRUE;
10876116Sdcs            }
10976116Sdcs            pFW = pFW->link;
11076116Sdcs        }
11176116Sdcs    }
11276116Sdcs
11376116Sdcs    return FICL_FALSE;
11476116Sdcs}
11576116Sdcs
11676116Sdcs
11776116Sdcsstatic void tempBase(FICL_VM *pVM, int base)
11876116Sdcs{
11976116Sdcs    int oldbase = pVM->base;
12076116Sdcs    STRINGINFO si = vmGetWord0(pVM);
12176116Sdcs
12276116Sdcs    pVM->base = base;
12376116Sdcs    if (!ficlParseNumber(pVM, si))
12476116Sdcs    {
12576116Sdcs        int i = SI_COUNT(si);
12694290Sdcs        vmThrowErr(pVM, "%.*s not recognized", i, SI_PTR(si));
12776116Sdcs    }
12876116Sdcs
12976116Sdcs    pVM->base = oldbase;
13076116Sdcs    return;
13176116Sdcs}
13276116Sdcs
13376116Sdcsstatic void fTempBase(FICL_VM *pVM)
13476116Sdcs{
13576116Sdcs    int base = stackPopINT(pVM->pStack);
13676116Sdcs    tempBase(pVM, base);
13776116Sdcs    return;
13876116Sdcs}
13976116Sdcs
14076116Sdcsstatic void prefixHex(FICL_VM *pVM)
14176116Sdcs{
14276116Sdcs    tempBase(pVM, 16);
14376116Sdcs}
14476116Sdcs
14576116Sdcsstatic void prefixTen(FICL_VM *pVM)
14676116Sdcs{
14776116Sdcs    tempBase(pVM, 10);
14876116Sdcs}
14976116Sdcs
15076116Sdcs
15176116Sdcs/**************************************************************************
15276116Sdcs                        f i c l C o m p i l e P r e f i x
15376116Sdcs** Build prefix support into the dictionary and the parser
15476116Sdcs** Note: since prefixes always execute, they are effectively IMMEDIATE.
15576116Sdcs** If they need to generate code in compile state you must add
15676116Sdcs** this code explicitly.
15776116Sdcs**************************************************************************/
15876116Sdcsvoid ficlCompilePrefix(FICL_SYSTEM *pSys)
15976116Sdcs{
16076116Sdcs    FICL_DICT *dp = pSys->dp;
16176116Sdcs    FICL_HASH *pHash;
16276116Sdcs    FICL_HASH *pPrevCompile = dp->pCompile;
16376116Sdcs#if (FICL_EXTENDED_PREFIX)
16476116Sdcs    FICL_WORD *pFW;
16576116Sdcs#endif
16676116Sdcs
16776116Sdcs    /*
16876116Sdcs    ** Create a named wordlist for prefixes to reside in...
16976116Sdcs    ** Since we're doing a special kind of search, make it
17076116Sdcs    ** a single bucket hashtable - hashing does not help here.
17176116Sdcs    */
17276116Sdcs    pHash = dictCreateWordlist(dp, 1);
17376116Sdcs    pHash->name = list_name;
17476116Sdcs    dictAppendWord(dp, list_name, constantParen, FW_DEFAULT);
17576116Sdcs    dictAppendCell(dp, LVALUEtoCELL(pHash));
17694290Sdcs
17794290Sdcs	/*
17894290Sdcs	** Put __tempbase in the forth-wordlist
17994290Sdcs	*/
18076116Sdcs    dictAppendWord(dp, "__tempbase", fTempBase, FW_DEFAULT);
18176116Sdcs
18276116Sdcs    /*
18376116Sdcs    ** Temporarily make the prefix list the compile wordlist so that
18476116Sdcs    ** we can create some precompiled prefixes.
18576116Sdcs    */
18676116Sdcs    dp->pCompile = pHash;
18776116Sdcs    dictAppendWord(dp, "0x", prefixHex, FW_DEFAULT);
18876116Sdcs    dictAppendWord(dp, "0d", prefixTen, FW_DEFAULT);
18976116Sdcs#if (FICL_EXTENDED_PREFIX)
19094290Sdcs    pFW = ficlLookup(pSys, "\\");
19176116Sdcs    if (pFW)
19276116Sdcs    {
19376116Sdcs        dictAppendWord(dp, "//", pFW->code, FW_DEFAULT);
19476116Sdcs    }
19576116Sdcs#endif
19676116Sdcs    dp->pCompile = pPrevCompile;
19776116Sdcs
19876116Sdcs    return;
19976116Sdcs}
200