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