1*a1bf3f78SToomas Soome /*
2*a1bf3f78SToomas Soome * p r e f i x . c
3*a1bf3f78SToomas Soome * Forth Inspired Command Language
4*a1bf3f78SToomas Soome * Parser extensions for Ficl
5*a1bf3f78SToomas Soome * Authors: Larry Hastings & John Sadler (john_sadler@alum.mit.edu)
6*a1bf3f78SToomas Soome * Created: April 2001
7*a1bf3f78SToomas Soome * $Id: prefix.c,v 1.8 2010/09/13 18:43:04 asau Exp $
8*a1bf3f78SToomas Soome */
9*a1bf3f78SToomas Soome /*
10*a1bf3f78SToomas Soome * Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu)
11*a1bf3f78SToomas Soome * All rights reserved.
12*a1bf3f78SToomas Soome *
13*a1bf3f78SToomas Soome * Get the latest Ficl release at http://ficl.sourceforge.net
14*a1bf3f78SToomas Soome *
15*a1bf3f78SToomas Soome * I am interested in hearing from anyone who uses Ficl. If you have
16*a1bf3f78SToomas Soome * a problem, a success story, a defect, an enhancement request, or
17*a1bf3f78SToomas Soome * if you would like to contribute to the Ficl release, please
18*a1bf3f78SToomas Soome * contact me by email at the address above.
19*a1bf3f78SToomas Soome *
20*a1bf3f78SToomas Soome * L I C E N S E and D I S C L A I M E R
21*a1bf3f78SToomas Soome *
22*a1bf3f78SToomas Soome * Redistribution and use in source and binary forms, with or without
23*a1bf3f78SToomas Soome * modification, are permitted provided that the following conditions
24*a1bf3f78SToomas Soome * are met:
25*a1bf3f78SToomas Soome * 1. Redistributions of source code must retain the above copyright
26*a1bf3f78SToomas Soome * notice, this list of conditions and the following disclaimer.
27*a1bf3f78SToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
28*a1bf3f78SToomas Soome * notice, this list of conditions and the following disclaimer in the
29*a1bf3f78SToomas Soome * documentation and/or other materials provided with the distribution.
30*a1bf3f78SToomas Soome *
31*a1bf3f78SToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
32*a1bf3f78SToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33*a1bf3f78SToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34*a1bf3f78SToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
35*a1bf3f78SToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36*a1bf3f78SToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37*a1bf3f78SToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38*a1bf3f78SToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39*a1bf3f78SToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
40*a1bf3f78SToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41*a1bf3f78SToomas Soome * SUCH DAMAGE.
42*a1bf3f78SToomas Soome */
43*a1bf3f78SToomas Soome
44*a1bf3f78SToomas Soome #include "ficl.h"
45*a1bf3f78SToomas Soome
46*a1bf3f78SToomas Soome /*
47*a1bf3f78SToomas Soome * (jws) revisions:
48*a1bf3f78SToomas Soome * A prefix is a word in a dedicated wordlist (name stored in list_name below)
49*a1bf3f78SToomas Soome * that is searched in a special way by the prefix parse step. When a prefix
50*a1bf3f78SToomas Soome * matches the beginning of an incoming token, push the non-prefix part of the
51*a1bf3f78SToomas Soome * token back onto the input stream and execute the prefix code.
52*a1bf3f78SToomas Soome *
53*a1bf3f78SToomas Soome * The parse step is called ficlParsePrefix.
54*a1bf3f78SToomas Soome * Storing prefix entries in the dictionary greatly simplifies
55*a1bf3f78SToomas Soome * the process of matching and dispatching prefixes, avoids the
56*a1bf3f78SToomas Soome * need to clean up a dynamically allocated prefix list when the system
57*a1bf3f78SToomas Soome * goes away, but still allows prefixes to be allocated at runtime.
58*a1bf3f78SToomas Soome */
59*a1bf3f78SToomas Soome
60*a1bf3f78SToomas Soome static char list_name[] = "<prefixes>";
61*a1bf3f78SToomas Soome
62*a1bf3f78SToomas Soome /*
63*a1bf3f78SToomas Soome * f i c l P a r s e P r e f i x
64*a1bf3f78SToomas Soome * This is the parse step for prefixes - it checks an incoming word
65*a1bf3f78SToomas Soome * to see if it starts with a prefix, and if so runs the corresponding
66*a1bf3f78SToomas Soome * code against the remainder of the word and returns true.
67*a1bf3f78SToomas Soome */
68*a1bf3f78SToomas Soome int
ficlVmParsePrefix(ficlVm * vm,ficlString s)69*a1bf3f78SToomas Soome ficlVmParsePrefix(ficlVm *vm, ficlString s)
70*a1bf3f78SToomas Soome {
71*a1bf3f78SToomas Soome int i;
72*a1bf3f78SToomas Soome ficlHash *hash;
73*a1bf3f78SToomas Soome ficlWord *word = ficlSystemLookup(vm->callback.system, list_name);
74*a1bf3f78SToomas Soome
75*a1bf3f78SToomas Soome /*
76*a1bf3f78SToomas Soome * Make sure we found the prefix dictionary - otherwise silently fail
77*a1bf3f78SToomas Soome * If forth-wordlist is not in the search order, we won't find the
78*a1bf3f78SToomas Soome * prefixes.
79*a1bf3f78SToomas Soome */
80*a1bf3f78SToomas Soome if (!word)
81*a1bf3f78SToomas Soome return (0); /* false */
82*a1bf3f78SToomas Soome
83*a1bf3f78SToomas Soome hash = (ficlHash *)(word->param[0].p);
84*a1bf3f78SToomas Soome /*
85*a1bf3f78SToomas Soome * Walk the list looking for a match with the beginning of the
86*a1bf3f78SToomas Soome * incoming token
87*a1bf3f78SToomas Soome */
88*a1bf3f78SToomas Soome for (i = 0; i < (int)hash->size; i++) {
89*a1bf3f78SToomas Soome word = hash->table[i];
90*a1bf3f78SToomas Soome while (word != NULL) {
91*a1bf3f78SToomas Soome int n;
92*a1bf3f78SToomas Soome n = word->length;
93*a1bf3f78SToomas Soome /*
94*a1bf3f78SToomas Soome * If we find a match, adjust the TIB to give back
95*a1bf3f78SToomas Soome * the non-prefix characters and execute the prefix
96*a1bf3f78SToomas Soome * word.
97*a1bf3f78SToomas Soome */
98*a1bf3f78SToomas Soome if (!ficlStrincmp(FICL_STRING_GET_POINTER(s),
99*a1bf3f78SToomas Soome word->name, (ficlUnsigned)n)) {
100*a1bf3f78SToomas Soome /*
101*a1bf3f78SToomas Soome * (sadler) fixed off-by-one error when the
102*a1bf3f78SToomas Soome * token has no trailing space in the TIB
103*a1bf3f78SToomas Soome */
104*a1bf3f78SToomas Soome ficlVmSetTibIndex(vm,
105*a1bf3f78SToomas Soome s.text + n - vm->tib.text);
106*a1bf3f78SToomas Soome ficlVmExecuteWord(vm, word);
107*a1bf3f78SToomas Soome
108*a1bf3f78SToomas Soome return (1); /* true */
109*a1bf3f78SToomas Soome }
110*a1bf3f78SToomas Soome word = word->link;
111*a1bf3f78SToomas Soome }
112*a1bf3f78SToomas Soome }
113*a1bf3f78SToomas Soome
114*a1bf3f78SToomas Soome return (0); /* false */
115*a1bf3f78SToomas Soome }
116*a1bf3f78SToomas Soome
117*a1bf3f78SToomas Soome static void
ficlPrimitiveTempBase(ficlVm * vm)118*a1bf3f78SToomas Soome ficlPrimitiveTempBase(ficlVm *vm)
119*a1bf3f78SToomas Soome {
120*a1bf3f78SToomas Soome int oldbase = vm->base;
121*a1bf3f78SToomas Soome ficlString number = ficlVmGetWord0(vm);
122*a1bf3f78SToomas Soome int base = ficlStackPopInteger(vm->dataStack);
123*a1bf3f78SToomas Soome
124*a1bf3f78SToomas Soome vm->base = base;
125*a1bf3f78SToomas Soome if (!ficlVmParseNumber(vm, number))
126*a1bf3f78SToomas Soome ficlVmThrowError(vm, "%.*s not recognized",
127*a1bf3f78SToomas Soome FICL_STRING_GET_LENGTH(number),
128*a1bf3f78SToomas Soome FICL_STRING_GET_POINTER(number));
129*a1bf3f78SToomas Soome
130*a1bf3f78SToomas Soome vm->base = oldbase;
131*a1bf3f78SToomas Soome }
132*a1bf3f78SToomas Soome
133*a1bf3f78SToomas Soome /*
134*a1bf3f78SToomas Soome * f i c l C o m p i l e P r e f i x
135*a1bf3f78SToomas Soome * Build prefix support into the dictionary and the parser
136*a1bf3f78SToomas Soome * Note: since prefixes always execute, they are effectively IMMEDIATE.
137*a1bf3f78SToomas Soome * If they need to generate code in compile state you must add
138*a1bf3f78SToomas Soome * this code explicitly.
139*a1bf3f78SToomas Soome */
140*a1bf3f78SToomas Soome void
ficlSystemCompilePrefix(ficlSystem * system)141*a1bf3f78SToomas Soome ficlSystemCompilePrefix(ficlSystem *system)
142*a1bf3f78SToomas Soome {
143*a1bf3f78SToomas Soome ficlDictionary *dictionary = system->dictionary;
144*a1bf3f78SToomas Soome ficlHash *hash;
145*a1bf3f78SToomas Soome
146*a1bf3f78SToomas Soome /*
147*a1bf3f78SToomas Soome * Create a named wordlist for prefixes to reside in...
148*a1bf3f78SToomas Soome * Since we're doing a special kind of search, make it
149*a1bf3f78SToomas Soome * a single bucket hashtable - hashing does not help here.
150*a1bf3f78SToomas Soome */
151*a1bf3f78SToomas Soome hash = ficlDictionaryCreateWordlist(dictionary, 1);
152*a1bf3f78SToomas Soome hash->name = list_name;
153*a1bf3f78SToomas Soome ficlDictionaryAppendConstantPointer(dictionary, list_name, hash);
154*a1bf3f78SToomas Soome
155*a1bf3f78SToomas Soome /*
156*a1bf3f78SToomas Soome * Put __tempbase in the forth-wordlist
157*a1bf3f78SToomas Soome */
158*a1bf3f78SToomas Soome ficlDictionarySetPrimitive(dictionary, "__tempbase",
159*a1bf3f78SToomas Soome ficlPrimitiveTempBase, FICL_WORD_DEFAULT);
160*a1bf3f78SToomas Soome
161*a1bf3f78SToomas Soome /*
162*a1bf3f78SToomas Soome * If you want to add some prefixes at compilation-time, copy this
163*a1bf3f78SToomas Soome * line to the top of this function:
164*a1bf3f78SToomas Soome *
165*a1bf3f78SToomas Soome * ficlHash *oldCompilationWordlist;
166*a1bf3f78SToomas Soome *
167*a1bf3f78SToomas Soome * then copy this code to the bottom, just above the return:
168*a1bf3f78SToomas Soome *
169*a1bf3f78SToomas Soome *
170*a1bf3f78SToomas Soome * oldCompilationWordlist = dictionary->compilationWordlist;
171*a1bf3f78SToomas Soome * dictionary->compilationWordlist = hash;
172*a1bf3f78SToomas Soome * ficlDictionarySetPrimitive(dictionary, YOUR WORD HERE,
173*a1bf3f78SToomas Soome * FICL_WORD_DEFAULT);
174*a1bf3f78SToomas Soome * dictionary->compilationWordlist = oldCompilationWordlist;
175*a1bf3f78SToomas Soome *
176*a1bf3f78SToomas Soome * and substitute in your own actual calls to
177*a1bf3f78SToomas Soome * ficlDictionarySetPrimitive() as needed.
178*a1bf3f78SToomas Soome *
179*a1bf3f78SToomas Soome * Or--better yet--do it in your own code, so you don't have
180*a1bf3f78SToomas Soome * to re-modify the Ficl source code every time we cut a new release!
181*a1bf3f78SToomas Soome */
182*a1bf3f78SToomas Soome }
183