1*ca987d46SWarner Losh /*******************************************************************
2*ca987d46SWarner Losh ** v m . c
3*ca987d46SWarner Losh ** Forth Inspired Command Language - virtual machine methods
4*ca987d46SWarner Losh ** Author: John Sadler (john_sadler@alum.mit.edu)
5*ca987d46SWarner Losh ** Created: 19 July 1997
6*ca987d46SWarner Losh ** $Id: vm.c,v 1.13 2001/12/05 07:21:34 jsadler Exp $
7*ca987d46SWarner Losh *******************************************************************/
8*ca987d46SWarner Losh /*
9*ca987d46SWarner Losh ** This file implements the virtual machine of FICL. Each virtual
10*ca987d46SWarner Losh ** machine retains the state of an interpreter. A virtual machine
11*ca987d46SWarner Losh ** owns a pair of stacks for parameters and return addresses, as
12*ca987d46SWarner Losh ** well as a pile of state variables and the two dedicated registers
13*ca987d46SWarner Losh ** of the interp.
14*ca987d46SWarner Losh */
15*ca987d46SWarner Losh /*
16*ca987d46SWarner Losh ** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu)
17*ca987d46SWarner Losh ** All rights reserved.
18*ca987d46SWarner Losh **
19*ca987d46SWarner Losh ** Get the latest Ficl release at http://ficl.sourceforge.net
20*ca987d46SWarner Losh **
21*ca987d46SWarner Losh ** I am interested in hearing from anyone who uses ficl. If you have
22*ca987d46SWarner Losh ** a problem, a success story, a defect, an enhancement request, or
23*ca987d46SWarner Losh ** if you would like to contribute to the ficl release, please
24*ca987d46SWarner Losh ** contact me by email at the address above.
25*ca987d46SWarner Losh **
26*ca987d46SWarner Losh ** L I C E N S E and D I S C L A I M E R
27*ca987d46SWarner Losh **
28*ca987d46SWarner Losh ** Redistribution and use in source and binary forms, with or without
29*ca987d46SWarner Losh ** modification, are permitted provided that the following conditions
30*ca987d46SWarner Losh ** are met:
31*ca987d46SWarner Losh ** 1. Redistributions of source code must retain the above copyright
32*ca987d46SWarner Losh ** notice, this list of conditions and the following disclaimer.
33*ca987d46SWarner Losh ** 2. Redistributions in binary form must reproduce the above copyright
34*ca987d46SWarner Losh ** notice, this list of conditions and the following disclaimer in the
35*ca987d46SWarner Losh ** documentation and/or other materials provided with the distribution.
36*ca987d46SWarner Losh **
37*ca987d46SWarner Losh ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
38*ca987d46SWarner Losh ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39*ca987d46SWarner Losh ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40*ca987d46SWarner Losh ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
41*ca987d46SWarner Losh ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42*ca987d46SWarner Losh ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43*ca987d46SWarner Losh ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44*ca987d46SWarner Losh ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45*ca987d46SWarner Losh ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46*ca987d46SWarner Losh ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47*ca987d46SWarner Losh ** SUCH DAMAGE.
48*ca987d46SWarner Losh */
49*ca987d46SWarner Losh
50*ca987d46SWarner Losh
51*ca987d46SWarner Losh #ifdef TESTMAIN
52*ca987d46SWarner Losh #include <stdlib.h>
53*ca987d46SWarner Losh #include <stdio.h>
54*ca987d46SWarner Losh #include <ctype.h>
55*ca987d46SWarner Losh #else
56*ca987d46SWarner Losh #include <stand.h>
57*ca987d46SWarner Losh #endif
58*ca987d46SWarner Losh #include <stdarg.h>
59*ca987d46SWarner Losh #include <string.h>
60*ca987d46SWarner Losh #include "ficl.h"
61*ca987d46SWarner Losh
62*ca987d46SWarner Losh static char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
63*ca987d46SWarner Losh
64*ca987d46SWarner Losh
65*ca987d46SWarner Losh /**************************************************************************
66*ca987d46SWarner Losh v m B r a n c h R e l a t i v e
67*ca987d46SWarner Losh **
68*ca987d46SWarner Losh **************************************************************************/
vmBranchRelative(FICL_VM * pVM,int offset)69*ca987d46SWarner Losh void vmBranchRelative(FICL_VM *pVM, int offset)
70*ca987d46SWarner Losh {
71*ca987d46SWarner Losh pVM->ip += offset;
72*ca987d46SWarner Losh return;
73*ca987d46SWarner Losh }
74*ca987d46SWarner Losh
75*ca987d46SWarner Losh
76*ca987d46SWarner Losh /**************************************************************************
77*ca987d46SWarner Losh v m C r e a t e
78*ca987d46SWarner Losh ** Creates a virtual machine either from scratch (if pVM is NULL on entry)
79*ca987d46SWarner Losh ** or by resizing and reinitializing an existing VM to the specified stack
80*ca987d46SWarner Losh ** sizes.
81*ca987d46SWarner Losh **************************************************************************/
vmCreate(FICL_VM * pVM,unsigned nPStack,unsigned nRStack)82*ca987d46SWarner Losh FICL_VM *vmCreate(FICL_VM *pVM, unsigned nPStack, unsigned nRStack)
83*ca987d46SWarner Losh {
84*ca987d46SWarner Losh if (pVM == NULL)
85*ca987d46SWarner Losh {
86*ca987d46SWarner Losh pVM = (FICL_VM *)ficlMalloc(sizeof (FICL_VM));
87*ca987d46SWarner Losh assert (pVM);
88*ca987d46SWarner Losh memset(pVM, 0, sizeof (FICL_VM));
89*ca987d46SWarner Losh }
90*ca987d46SWarner Losh
91*ca987d46SWarner Losh if (pVM->pStack)
92*ca987d46SWarner Losh stackDelete(pVM->pStack);
93*ca987d46SWarner Losh pVM->pStack = stackCreate(nPStack);
94*ca987d46SWarner Losh
95*ca987d46SWarner Losh if (pVM->rStack)
96*ca987d46SWarner Losh stackDelete(pVM->rStack);
97*ca987d46SWarner Losh pVM->rStack = stackCreate(nRStack);
98*ca987d46SWarner Losh
99*ca987d46SWarner Losh #if FICL_WANT_FLOAT
100*ca987d46SWarner Losh if (pVM->fStack)
101*ca987d46SWarner Losh stackDelete(pVM->fStack);
102*ca987d46SWarner Losh pVM->fStack = stackCreate(nPStack);
103*ca987d46SWarner Losh #endif
104*ca987d46SWarner Losh
105*ca987d46SWarner Losh pVM->textOut = ficlTextOut;
106*ca987d46SWarner Losh
107*ca987d46SWarner Losh vmReset(pVM);
108*ca987d46SWarner Losh return pVM;
109*ca987d46SWarner Losh }
110*ca987d46SWarner Losh
111*ca987d46SWarner Losh
112*ca987d46SWarner Losh /**************************************************************************
113*ca987d46SWarner Losh v m D e l e t e
114*ca987d46SWarner Losh ** Free all memory allocated to the specified VM and its subordinate
115*ca987d46SWarner Losh ** structures.
116*ca987d46SWarner Losh **************************************************************************/
vmDelete(FICL_VM * pVM)117*ca987d46SWarner Losh void vmDelete (FICL_VM *pVM)
118*ca987d46SWarner Losh {
119*ca987d46SWarner Losh if (pVM)
120*ca987d46SWarner Losh {
121*ca987d46SWarner Losh ficlFree(pVM->pStack);
122*ca987d46SWarner Losh ficlFree(pVM->rStack);
123*ca987d46SWarner Losh #if FICL_WANT_FLOAT
124*ca987d46SWarner Losh ficlFree(pVM->fStack);
125*ca987d46SWarner Losh #endif
126*ca987d46SWarner Losh ficlFree(pVM);
127*ca987d46SWarner Losh }
128*ca987d46SWarner Losh
129*ca987d46SWarner Losh return;
130*ca987d46SWarner Losh }
131*ca987d46SWarner Losh
132*ca987d46SWarner Losh
133*ca987d46SWarner Losh /**************************************************************************
134*ca987d46SWarner Losh v m E x e c u t e
135*ca987d46SWarner Losh ** Sets up the specified word to be run by the inner interpreter.
136*ca987d46SWarner Losh ** Executes the word's code part immediately, but in the case of
137*ca987d46SWarner Losh ** colon definition, the definition itself needs the inner interp
138*ca987d46SWarner Losh ** to complete. This does not happen until control reaches ficlExec
139*ca987d46SWarner Losh **************************************************************************/
vmExecute(FICL_VM * pVM,FICL_WORD * pWord)140*ca987d46SWarner Losh void vmExecute(FICL_VM *pVM, FICL_WORD *pWord)
141*ca987d46SWarner Losh {
142*ca987d46SWarner Losh pVM->runningWord = pWord;
143*ca987d46SWarner Losh pWord->code(pVM);
144*ca987d46SWarner Losh return;
145*ca987d46SWarner Losh }
146*ca987d46SWarner Losh
147*ca987d46SWarner Losh
148*ca987d46SWarner Losh /**************************************************************************
149*ca987d46SWarner Losh v m I n n e r L o o p
150*ca987d46SWarner Losh ** the mysterious inner interpreter...
151*ca987d46SWarner Losh ** This loop is the address interpreter that makes colon definitions
152*ca987d46SWarner Losh ** work. Upon entry, it assumes that the IP points to an entry in
153*ca987d46SWarner Losh ** a definition (the body of a colon word). It runs one word at a time
154*ca987d46SWarner Losh ** until something does vmThrow. The catcher for this is expected to exist
155*ca987d46SWarner Losh ** in the calling code.
156*ca987d46SWarner Losh ** vmThrow gets you out of this loop with a longjmp()
157*ca987d46SWarner Losh ** Visual C++ 5 chokes on this loop in Release mode. Aargh.
158*ca987d46SWarner Losh **************************************************************************/
159*ca987d46SWarner Losh #if INLINE_INNER_LOOP == 0
vmInnerLoop(FICL_VM * pVM)160*ca987d46SWarner Losh void vmInnerLoop(FICL_VM *pVM)
161*ca987d46SWarner Losh {
162*ca987d46SWarner Losh M_INNER_LOOP(pVM);
163*ca987d46SWarner Losh }
164*ca987d46SWarner Losh #endif
165*ca987d46SWarner Losh #if 0
166*ca987d46SWarner Losh /*
167*ca987d46SWarner Losh ** Recast inner loop that inlines tokens for control structures, arithmetic and stack operations,
168*ca987d46SWarner Losh ** as well as create does> : ; and various literals
169*ca987d46SWarner Losh */
170*ca987d46SWarner Losh typedef enum
171*ca987d46SWarner Losh {
172*ca987d46SWarner Losh PATCH = 0,
173*ca987d46SWarner Losh L0,
174*ca987d46SWarner Losh L1,
175*ca987d46SWarner Losh L2,
176*ca987d46SWarner Losh LMINUS1,
177*ca987d46SWarner Losh LMINUS2,
178*ca987d46SWarner Losh DROP,
179*ca987d46SWarner Losh SWAP,
180*ca987d46SWarner Losh DUP,
181*ca987d46SWarner Losh PICK,
182*ca987d46SWarner Losh ROLL,
183*ca987d46SWarner Losh FETCH,
184*ca987d46SWarner Losh STORE,
185*ca987d46SWarner Losh BRANCH,
186*ca987d46SWarner Losh CBRANCH,
187*ca987d46SWarner Losh LEAVE,
188*ca987d46SWarner Losh TO_R,
189*ca987d46SWarner Losh R_FROM,
190*ca987d46SWarner Losh EXIT;
191*ca987d46SWarner Losh } OPCODE;
192*ca987d46SWarner Losh
193*ca987d46SWarner Losh typedef CELL *IPTYPE;
194*ca987d46SWarner Losh
195*ca987d46SWarner Losh void vmInnerLoop(FICL_VM *pVM)
196*ca987d46SWarner Losh {
197*ca987d46SWarner Losh IPTYPE ip = pVM->ip;
198*ca987d46SWarner Losh FICL_STACK *pStack = pVM->pStack;
199*ca987d46SWarner Losh
200*ca987d46SWarner Losh for (;;)
201*ca987d46SWarner Losh {
202*ca987d46SWarner Losh OPCODE o = (*ip++).i;
203*ca987d46SWarner Losh CELL c;
204*ca987d46SWarner Losh switch (o)
205*ca987d46SWarner Losh {
206*ca987d46SWarner Losh case L0:
207*ca987d46SWarner Losh stackPushINT(pStack, 0);
208*ca987d46SWarner Losh break;
209*ca987d46SWarner Losh case L1:
210*ca987d46SWarner Losh stackPushINT(pStack, 1);
211*ca987d46SWarner Losh break;
212*ca987d46SWarner Losh case L2:
213*ca987d46SWarner Losh stackPushINT(pStack, 2);
214*ca987d46SWarner Losh break;
215*ca987d46SWarner Losh case LMINUS1:
216*ca987d46SWarner Losh stackPushINT(pStack, -1);
217*ca987d46SWarner Losh break;
218*ca987d46SWarner Losh case LMINUS2:
219*ca987d46SWarner Losh stackPushINT(pStack, -2);
220*ca987d46SWarner Losh break;
221*ca987d46SWarner Losh case DROP:
222*ca987d46SWarner Losh stackDrop(pStack, 1);
223*ca987d46SWarner Losh break;
224*ca987d46SWarner Losh case SWAP:
225*ca987d46SWarner Losh stackRoll(pStack, 1);
226*ca987d46SWarner Losh break;
227*ca987d46SWarner Losh case DUP:
228*ca987d46SWarner Losh stackPick(pStack, 0);
229*ca987d46SWarner Losh break;
230*ca987d46SWarner Losh case PICK:
231*ca987d46SWarner Losh c = *ip++;
232*ca987d46SWarner Losh stackPick(pStack, c.i);
233*ca987d46SWarner Losh break;
234*ca987d46SWarner Losh case ROLL:
235*ca987d46SWarner Losh c = *ip++;
236*ca987d46SWarner Losh stackRoll(pStack, c.i);
237*ca987d46SWarner Losh break;
238*ca987d46SWarner Losh case EXIT:
239*ca987d46SWarner Losh return;
240*ca987d46SWarner Losh }
241*ca987d46SWarner Losh }
242*ca987d46SWarner Losh
243*ca987d46SWarner Losh return;
244*ca987d46SWarner Losh }
245*ca987d46SWarner Losh #endif
246*ca987d46SWarner Losh
247*ca987d46SWarner Losh
248*ca987d46SWarner Losh
249*ca987d46SWarner Losh /**************************************************************************
250*ca987d46SWarner Losh v m G e t D i c t
251*ca987d46SWarner Losh ** Returns the address dictionary for this VM's system
252*ca987d46SWarner Losh **************************************************************************/
vmGetDict(FICL_VM * pVM)253*ca987d46SWarner Losh FICL_DICT *vmGetDict(FICL_VM *pVM)
254*ca987d46SWarner Losh {
255*ca987d46SWarner Losh assert(pVM);
256*ca987d46SWarner Losh return pVM->pSys->dp;
257*ca987d46SWarner Losh }
258*ca987d46SWarner Losh
259*ca987d46SWarner Losh
260*ca987d46SWarner Losh /**************************************************************************
261*ca987d46SWarner Losh v m G e t S t r i n g
262*ca987d46SWarner Losh ** Parses a string out of the VM input buffer and copies up to the first
263*ca987d46SWarner Losh ** FICL_STRING_MAX characters to the supplied destination buffer, a
264*ca987d46SWarner Losh ** FICL_STRING. The destination string is NULL terminated.
265*ca987d46SWarner Losh **
266*ca987d46SWarner Losh ** Returns the address of the first unused character in the dest buffer.
267*ca987d46SWarner Losh **************************************************************************/
vmGetString(FICL_VM * pVM,FICL_STRING * spDest,char delimiter)268*ca987d46SWarner Losh char *vmGetString(FICL_VM *pVM, FICL_STRING *spDest, char delimiter)
269*ca987d46SWarner Losh {
270*ca987d46SWarner Losh STRINGINFO si = vmParseStringEx(pVM, delimiter, 0);
271*ca987d46SWarner Losh
272*ca987d46SWarner Losh if (SI_COUNT(si) > FICL_STRING_MAX)
273*ca987d46SWarner Losh {
274*ca987d46SWarner Losh SI_SETLEN(si, FICL_STRING_MAX);
275*ca987d46SWarner Losh }
276*ca987d46SWarner Losh
277*ca987d46SWarner Losh strncpy(spDest->text, SI_PTR(si), SI_COUNT(si));
278*ca987d46SWarner Losh spDest->text[SI_COUNT(si)] = '\0';
279*ca987d46SWarner Losh spDest->count = (FICL_COUNT)SI_COUNT(si);
280*ca987d46SWarner Losh
281*ca987d46SWarner Losh return spDest->text + SI_COUNT(si) + 1;
282*ca987d46SWarner Losh }
283*ca987d46SWarner Losh
284*ca987d46SWarner Losh
285*ca987d46SWarner Losh /**************************************************************************
286*ca987d46SWarner Losh v m G e t W o r d
287*ca987d46SWarner Losh ** vmGetWord calls vmGetWord0 repeatedly until it gets a string with
288*ca987d46SWarner Losh ** non-zero length.
289*ca987d46SWarner Losh **************************************************************************/
vmGetWord(FICL_VM * pVM)290*ca987d46SWarner Losh STRINGINFO vmGetWord(FICL_VM *pVM)
291*ca987d46SWarner Losh {
292*ca987d46SWarner Losh STRINGINFO si = vmGetWord0(pVM);
293*ca987d46SWarner Losh
294*ca987d46SWarner Losh if (SI_COUNT(si) == 0)
295*ca987d46SWarner Losh {
296*ca987d46SWarner Losh vmThrow(pVM, VM_RESTART);
297*ca987d46SWarner Losh }
298*ca987d46SWarner Losh
299*ca987d46SWarner Losh return si;
300*ca987d46SWarner Losh }
301*ca987d46SWarner Losh
302*ca987d46SWarner Losh
303*ca987d46SWarner Losh /**************************************************************************
304*ca987d46SWarner Losh v m G e t W o r d 0
305*ca987d46SWarner Losh ** Skip leading whitespace and parse a space delimited word from the tib.
306*ca987d46SWarner Losh ** Returns the start address and length of the word. Updates the tib
307*ca987d46SWarner Losh ** to reflect characters consumed, including the trailing delimiter.
308*ca987d46SWarner Losh ** If there's nothing of interest in the tib, returns zero. This function
309*ca987d46SWarner Losh ** does not use vmParseString because it uses isspace() rather than a
310*ca987d46SWarner Losh ** single delimiter character.
311*ca987d46SWarner Losh **************************************************************************/
vmGetWord0(FICL_VM * pVM)312*ca987d46SWarner Losh STRINGINFO vmGetWord0(FICL_VM *pVM)
313*ca987d46SWarner Losh {
314*ca987d46SWarner Losh char *pSrc = vmGetInBuf(pVM);
315*ca987d46SWarner Losh char *pEnd = vmGetInBufEnd(pVM);
316*ca987d46SWarner Losh STRINGINFO si;
317*ca987d46SWarner Losh FICL_UNS count = 0;
318*ca987d46SWarner Losh char ch = 0;
319*ca987d46SWarner Losh
320*ca987d46SWarner Losh pSrc = skipSpace(pSrc, pEnd);
321*ca987d46SWarner Losh SI_SETPTR(si, pSrc);
322*ca987d46SWarner Losh
323*ca987d46SWarner Losh /*
324*ca987d46SWarner Losh for (ch = *pSrc; (pEnd != pSrc) && !isspace(ch); ch = *++pSrc)
325*ca987d46SWarner Losh {
326*ca987d46SWarner Losh count++;
327*ca987d46SWarner Losh }
328*ca987d46SWarner Losh */
329*ca987d46SWarner Losh
330*ca987d46SWarner Losh /* Changed to make Purify happier. --lch */
331*ca987d46SWarner Losh for (;;)
332*ca987d46SWarner Losh {
333*ca987d46SWarner Losh if (pEnd == pSrc)
334*ca987d46SWarner Losh break;
335*ca987d46SWarner Losh ch = *pSrc;
336*ca987d46SWarner Losh if (isspace(ch))
337*ca987d46SWarner Losh break;
338*ca987d46SWarner Losh count++;
339*ca987d46SWarner Losh pSrc++;
340*ca987d46SWarner Losh }
341*ca987d46SWarner Losh
342*ca987d46SWarner Losh SI_SETLEN(si, count);
343*ca987d46SWarner Losh
344*ca987d46SWarner Losh if ((pEnd != pSrc) && isspace(ch)) /* skip one trailing delimiter */
345*ca987d46SWarner Losh pSrc++;
346*ca987d46SWarner Losh
347*ca987d46SWarner Losh vmUpdateTib(pVM, pSrc);
348*ca987d46SWarner Losh
349*ca987d46SWarner Losh return si;
350*ca987d46SWarner Losh }
351*ca987d46SWarner Losh
352*ca987d46SWarner Losh
353*ca987d46SWarner Losh /**************************************************************************
354*ca987d46SWarner Losh v m G e t W o r d T o P a d
355*ca987d46SWarner Losh ** Does vmGetWord and copies the result to the pad as a NULL terminated
356*ca987d46SWarner Losh ** string. Returns the length of the string. If the string is too long
357*ca987d46SWarner Losh ** to fit in the pad, it is truncated.
358*ca987d46SWarner Losh **************************************************************************/
vmGetWordToPad(FICL_VM * pVM)359*ca987d46SWarner Losh int vmGetWordToPad(FICL_VM *pVM)
360*ca987d46SWarner Losh {
361*ca987d46SWarner Losh STRINGINFO si;
362*ca987d46SWarner Losh char *cp = (char *)pVM->pad;
363*ca987d46SWarner Losh si = vmGetWord(pVM);
364*ca987d46SWarner Losh
365*ca987d46SWarner Losh if (SI_COUNT(si) > nPAD)
366*ca987d46SWarner Losh SI_SETLEN(si, nPAD);
367*ca987d46SWarner Losh
368*ca987d46SWarner Losh strncpy(cp, SI_PTR(si), SI_COUNT(si));
369*ca987d46SWarner Losh cp[SI_COUNT(si)] = '\0';
370*ca987d46SWarner Losh return (int)(SI_COUNT(si));
371*ca987d46SWarner Losh }
372*ca987d46SWarner Losh
373*ca987d46SWarner Losh
374*ca987d46SWarner Losh /**************************************************************************
375*ca987d46SWarner Losh v m P a r s e S t r i n g
376*ca987d46SWarner Losh ** Parses a string out of the input buffer using the delimiter
377*ca987d46SWarner Losh ** specified. Skips leading delimiters, marks the start of the string,
378*ca987d46SWarner Losh ** and counts characters to the next delimiter it encounters. It then
379*ca987d46SWarner Losh ** updates the vm input buffer to consume all these chars, including the
380*ca987d46SWarner Losh ** trailing delimiter.
381*ca987d46SWarner Losh ** Returns the address and length of the parsed string, not including the
382*ca987d46SWarner Losh ** trailing delimiter.
383*ca987d46SWarner Losh **************************************************************************/
vmParseString(FICL_VM * pVM,char delim)384*ca987d46SWarner Losh STRINGINFO vmParseString(FICL_VM *pVM, char delim)
385*ca987d46SWarner Losh {
386*ca987d46SWarner Losh return vmParseStringEx(pVM, delim, 1);
387*ca987d46SWarner Losh }
388*ca987d46SWarner Losh
vmParseStringEx(FICL_VM * pVM,char delim,char fSkipLeading)389*ca987d46SWarner Losh STRINGINFO vmParseStringEx(FICL_VM *pVM, char delim, char fSkipLeading)
390*ca987d46SWarner Losh {
391*ca987d46SWarner Losh STRINGINFO si;
392*ca987d46SWarner Losh char *pSrc = vmGetInBuf(pVM);
393*ca987d46SWarner Losh char *pEnd = vmGetInBufEnd(pVM);
394*ca987d46SWarner Losh char ch;
395*ca987d46SWarner Losh
396*ca987d46SWarner Losh if (fSkipLeading)
397*ca987d46SWarner Losh { /* skip lead delimiters */
398*ca987d46SWarner Losh while ((pSrc != pEnd) && (*pSrc == delim))
399*ca987d46SWarner Losh pSrc++;
400*ca987d46SWarner Losh }
401*ca987d46SWarner Losh
402*ca987d46SWarner Losh SI_SETPTR(si, pSrc); /* mark start of text */
403*ca987d46SWarner Losh
404*ca987d46SWarner Losh for (ch = *pSrc; (pSrc != pEnd)
405*ca987d46SWarner Losh && (ch != delim)
406*ca987d46SWarner Losh && (ch != '\r')
407*ca987d46SWarner Losh && (ch != '\n'); ch = *++pSrc)
408*ca987d46SWarner Losh {
409*ca987d46SWarner Losh ; /* find next delimiter or end of line */
410*ca987d46SWarner Losh }
411*ca987d46SWarner Losh
412*ca987d46SWarner Losh /* set length of result */
413*ca987d46SWarner Losh SI_SETLEN(si, pSrc - SI_PTR(si));
414*ca987d46SWarner Losh
415*ca987d46SWarner Losh if ((pSrc != pEnd) && (*pSrc == delim)) /* gobble trailing delimiter */
416*ca987d46SWarner Losh pSrc++;
417*ca987d46SWarner Losh
418*ca987d46SWarner Losh vmUpdateTib(pVM, pSrc);
419*ca987d46SWarner Losh return si;
420*ca987d46SWarner Losh }
421*ca987d46SWarner Losh
422*ca987d46SWarner Losh
423*ca987d46SWarner Losh /**************************************************************************
424*ca987d46SWarner Losh v m P o p
425*ca987d46SWarner Losh **
426*ca987d46SWarner Losh **************************************************************************/
vmPop(FICL_VM * pVM)427*ca987d46SWarner Losh CELL vmPop(FICL_VM *pVM)
428*ca987d46SWarner Losh {
429*ca987d46SWarner Losh return stackPop(pVM->pStack);
430*ca987d46SWarner Losh }
431*ca987d46SWarner Losh
432*ca987d46SWarner Losh
433*ca987d46SWarner Losh /**************************************************************************
434*ca987d46SWarner Losh v m P u s h
435*ca987d46SWarner Losh **
436*ca987d46SWarner Losh **************************************************************************/
vmPush(FICL_VM * pVM,CELL c)437*ca987d46SWarner Losh void vmPush(FICL_VM *pVM, CELL c)
438*ca987d46SWarner Losh {
439*ca987d46SWarner Losh stackPush(pVM->pStack, c);
440*ca987d46SWarner Losh return;
441*ca987d46SWarner Losh }
442*ca987d46SWarner Losh
443*ca987d46SWarner Losh
444*ca987d46SWarner Losh /**************************************************************************
445*ca987d46SWarner Losh v m P o p I P
446*ca987d46SWarner Losh **
447*ca987d46SWarner Losh **************************************************************************/
vmPopIP(FICL_VM * pVM)448*ca987d46SWarner Losh void vmPopIP(FICL_VM *pVM)
449*ca987d46SWarner Losh {
450*ca987d46SWarner Losh pVM->ip = (IPTYPE)(stackPopPtr(pVM->rStack));
451*ca987d46SWarner Losh return;
452*ca987d46SWarner Losh }
453*ca987d46SWarner Losh
454*ca987d46SWarner Losh
455*ca987d46SWarner Losh /**************************************************************************
456*ca987d46SWarner Losh v m P u s h I P
457*ca987d46SWarner Losh **
458*ca987d46SWarner Losh **************************************************************************/
vmPushIP(FICL_VM * pVM,IPTYPE newIP)459*ca987d46SWarner Losh void vmPushIP(FICL_VM *pVM, IPTYPE newIP)
460*ca987d46SWarner Losh {
461*ca987d46SWarner Losh stackPushPtr(pVM->rStack, (void *)pVM->ip);
462*ca987d46SWarner Losh pVM->ip = newIP;
463*ca987d46SWarner Losh return;
464*ca987d46SWarner Losh }
465*ca987d46SWarner Losh
466*ca987d46SWarner Losh
467*ca987d46SWarner Losh /**************************************************************************
468*ca987d46SWarner Losh v m P u s h T i b
469*ca987d46SWarner Losh ** Binds the specified input string to the VM and clears >IN (the index)
470*ca987d46SWarner Losh **************************************************************************/
vmPushTib(FICL_VM * pVM,char * text,FICL_INT nChars,TIB * pSaveTib)471*ca987d46SWarner Losh void vmPushTib(FICL_VM *pVM, char *text, FICL_INT nChars, TIB *pSaveTib)
472*ca987d46SWarner Losh {
473*ca987d46SWarner Losh if (pSaveTib)
474*ca987d46SWarner Losh {
475*ca987d46SWarner Losh *pSaveTib = pVM->tib;
476*ca987d46SWarner Losh }
477*ca987d46SWarner Losh
478*ca987d46SWarner Losh pVM->tib.cp = text;
479*ca987d46SWarner Losh pVM->tib.end = text + nChars;
480*ca987d46SWarner Losh pVM->tib.index = 0;
481*ca987d46SWarner Losh }
482*ca987d46SWarner Losh
483*ca987d46SWarner Losh
vmPopTib(FICL_VM * pVM,TIB * pTib)484*ca987d46SWarner Losh void vmPopTib(FICL_VM *pVM, TIB *pTib)
485*ca987d46SWarner Losh {
486*ca987d46SWarner Losh if (pTib)
487*ca987d46SWarner Losh {
488*ca987d46SWarner Losh pVM->tib = *pTib;
489*ca987d46SWarner Losh }
490*ca987d46SWarner Losh return;
491*ca987d46SWarner Losh }
492*ca987d46SWarner Losh
493*ca987d46SWarner Losh
494*ca987d46SWarner Losh /**************************************************************************
495*ca987d46SWarner Losh v m Q u i t
496*ca987d46SWarner Losh **
497*ca987d46SWarner Losh **************************************************************************/
vmQuit(FICL_VM * pVM)498*ca987d46SWarner Losh void vmQuit(FICL_VM *pVM)
499*ca987d46SWarner Losh {
500*ca987d46SWarner Losh stackReset(pVM->rStack);
501*ca987d46SWarner Losh pVM->fRestart = 0;
502*ca987d46SWarner Losh pVM->ip = NULL;
503*ca987d46SWarner Losh pVM->runningWord = NULL;
504*ca987d46SWarner Losh pVM->state = INTERPRET;
505*ca987d46SWarner Losh pVM->tib.cp = NULL;
506*ca987d46SWarner Losh pVM->tib.end = NULL;
507*ca987d46SWarner Losh pVM->tib.index = 0;
508*ca987d46SWarner Losh pVM->pad[0] = '\0';
509*ca987d46SWarner Losh pVM->sourceID.i = 0;
510*ca987d46SWarner Losh return;
511*ca987d46SWarner Losh }
512*ca987d46SWarner Losh
513*ca987d46SWarner Losh
514*ca987d46SWarner Losh /**************************************************************************
515*ca987d46SWarner Losh v m R e s e t
516*ca987d46SWarner Losh **
517*ca987d46SWarner Losh **************************************************************************/
vmReset(FICL_VM * pVM)518*ca987d46SWarner Losh void vmReset(FICL_VM *pVM)
519*ca987d46SWarner Losh {
520*ca987d46SWarner Losh vmQuit(pVM);
521*ca987d46SWarner Losh stackReset(pVM->pStack);
522*ca987d46SWarner Losh #if FICL_WANT_FLOAT
523*ca987d46SWarner Losh stackReset(pVM->fStack);
524*ca987d46SWarner Losh #endif
525*ca987d46SWarner Losh pVM->base = 10;
526*ca987d46SWarner Losh return;
527*ca987d46SWarner Losh }
528*ca987d46SWarner Losh
529*ca987d46SWarner Losh
530*ca987d46SWarner Losh /**************************************************************************
531*ca987d46SWarner Losh v m S e t T e x t O u t
532*ca987d46SWarner Losh ** Binds the specified output callback to the vm. If you pass NULL,
533*ca987d46SWarner Losh ** binds the default output function (ficlTextOut)
534*ca987d46SWarner Losh **************************************************************************/
vmSetTextOut(FICL_VM * pVM,OUTFUNC textOut)535*ca987d46SWarner Losh void vmSetTextOut(FICL_VM *pVM, OUTFUNC textOut)
536*ca987d46SWarner Losh {
537*ca987d46SWarner Losh if (textOut)
538*ca987d46SWarner Losh pVM->textOut = textOut;
539*ca987d46SWarner Losh else
540*ca987d46SWarner Losh pVM->textOut = ficlTextOut;
541*ca987d46SWarner Losh
542*ca987d46SWarner Losh return;
543*ca987d46SWarner Losh }
544*ca987d46SWarner Losh
545*ca987d46SWarner Losh
546*ca987d46SWarner Losh /**************************************************************************
547*ca987d46SWarner Losh v m T e x t O u t
548*ca987d46SWarner Losh ** Feeds text to the vm's output callback
549*ca987d46SWarner Losh **************************************************************************/
vmTextOut(FICL_VM * pVM,char * text,int fNewline)550*ca987d46SWarner Losh void vmTextOut(FICL_VM *pVM, char *text, int fNewline)
551*ca987d46SWarner Losh {
552*ca987d46SWarner Losh assert(pVM);
553*ca987d46SWarner Losh assert(pVM->textOut);
554*ca987d46SWarner Losh (pVM->textOut)(pVM, text, fNewline);
555*ca987d46SWarner Losh
556*ca987d46SWarner Losh return;
557*ca987d46SWarner Losh }
558*ca987d46SWarner Losh
559*ca987d46SWarner Losh
560*ca987d46SWarner Losh /**************************************************************************
561*ca987d46SWarner Losh v m T h r o w
562*ca987d46SWarner Losh **
563*ca987d46SWarner Losh **************************************************************************/
vmThrow(FICL_VM * pVM,int except)564*ca987d46SWarner Losh void vmThrow(FICL_VM *pVM, int except)
565*ca987d46SWarner Losh {
566*ca987d46SWarner Losh if (pVM->pState)
567*ca987d46SWarner Losh longjmp(*(pVM->pState), except);
568*ca987d46SWarner Losh }
569*ca987d46SWarner Losh
570*ca987d46SWarner Losh
vmThrowErr(FICL_VM * pVM,char * fmt,...)571*ca987d46SWarner Losh void vmThrowErr(FICL_VM *pVM, char *fmt, ...)
572*ca987d46SWarner Losh {
573*ca987d46SWarner Losh va_list va;
574*ca987d46SWarner Losh va_start(va, fmt);
575*ca987d46SWarner Losh vsprintf(pVM->pad, fmt, va);
576*ca987d46SWarner Losh vmTextOut(pVM, pVM->pad, 1);
577*ca987d46SWarner Losh va_end(va);
578*ca987d46SWarner Losh longjmp(*(pVM->pState), VM_ERREXIT);
579*ca987d46SWarner Losh }
580*ca987d46SWarner Losh
581*ca987d46SWarner Losh
582*ca987d46SWarner Losh /**************************************************************************
583*ca987d46SWarner Losh w o r d I s I m m e d i a t e
584*ca987d46SWarner Losh **
585*ca987d46SWarner Losh **************************************************************************/
wordIsImmediate(FICL_WORD * pFW)586*ca987d46SWarner Losh int wordIsImmediate(FICL_WORD *pFW)
587*ca987d46SWarner Losh {
588*ca987d46SWarner Losh return ((pFW != NULL) && (pFW->flags & FW_IMMEDIATE));
589*ca987d46SWarner Losh }
590*ca987d46SWarner Losh
591*ca987d46SWarner Losh
592*ca987d46SWarner Losh /**************************************************************************
593*ca987d46SWarner Losh w o r d I s C o m p i l e O n l y
594*ca987d46SWarner Losh **
595*ca987d46SWarner Losh **************************************************************************/
wordIsCompileOnly(FICL_WORD * pFW)596*ca987d46SWarner Losh int wordIsCompileOnly(FICL_WORD *pFW)
597*ca987d46SWarner Losh {
598*ca987d46SWarner Losh return ((pFW != NULL) && (pFW->flags & FW_COMPILE));
599*ca987d46SWarner Losh }
600*ca987d46SWarner Losh
601*ca987d46SWarner Losh
602*ca987d46SWarner Losh /**************************************************************************
603*ca987d46SWarner Losh s t r r e v
604*ca987d46SWarner Losh **
605*ca987d46SWarner Losh **************************************************************************/
strrev(char * string)606*ca987d46SWarner Losh char *strrev( char *string )
607*ca987d46SWarner Losh { /* reverse a string in-place */
608*ca987d46SWarner Losh int i = strlen(string);
609*ca987d46SWarner Losh char *p1 = string; /* first char of string */
610*ca987d46SWarner Losh char *p2 = string + i - 1; /* last non-NULL char of string */
611*ca987d46SWarner Losh char c;
612*ca987d46SWarner Losh
613*ca987d46SWarner Losh if (i > 1)
614*ca987d46SWarner Losh {
615*ca987d46SWarner Losh while (p1 < p2)
616*ca987d46SWarner Losh {
617*ca987d46SWarner Losh c = *p2;
618*ca987d46SWarner Losh *p2 = *p1;
619*ca987d46SWarner Losh *p1 = c;
620*ca987d46SWarner Losh p1++; p2--;
621*ca987d46SWarner Losh }
622*ca987d46SWarner Losh }
623*ca987d46SWarner Losh
624*ca987d46SWarner Losh return string;
625*ca987d46SWarner Losh }
626*ca987d46SWarner Losh
627*ca987d46SWarner Losh
628*ca987d46SWarner Losh /**************************************************************************
629*ca987d46SWarner Losh d i g i t _ t o _ c h a r
630*ca987d46SWarner Losh **
631*ca987d46SWarner Losh **************************************************************************/
digit_to_char(int value)632*ca987d46SWarner Losh char digit_to_char(int value)
633*ca987d46SWarner Losh {
634*ca987d46SWarner Losh return digits[value];
635*ca987d46SWarner Losh }
636*ca987d46SWarner Losh
637*ca987d46SWarner Losh
638*ca987d46SWarner Losh /**************************************************************************
639*ca987d46SWarner Losh i s P o w e r O f T w o
640*ca987d46SWarner Losh ** Tests whether supplied argument is an integer power of 2 (2**n)
641*ca987d46SWarner Losh ** where 32 > n > 1, and returns n if so. Otherwise returns zero.
642*ca987d46SWarner Losh **************************************************************************/
isPowerOfTwo(FICL_UNS u)643*ca987d46SWarner Losh int isPowerOfTwo(FICL_UNS u)
644*ca987d46SWarner Losh {
645*ca987d46SWarner Losh int i = 1;
646*ca987d46SWarner Losh FICL_UNS t = 2;
647*ca987d46SWarner Losh
648*ca987d46SWarner Losh for (; ((t <= u) && (t != 0)); i++, t <<= 1)
649*ca987d46SWarner Losh {
650*ca987d46SWarner Losh if (u == t)
651*ca987d46SWarner Losh return i;
652*ca987d46SWarner Losh }
653*ca987d46SWarner Losh
654*ca987d46SWarner Losh return 0;
655*ca987d46SWarner Losh }
656*ca987d46SWarner Losh
657*ca987d46SWarner Losh
658*ca987d46SWarner Losh /**************************************************************************
659*ca987d46SWarner Losh l t o a
660*ca987d46SWarner Losh **
661*ca987d46SWarner Losh **************************************************************************/
ltoa(FICL_INT value,char * string,int radix)662*ca987d46SWarner Losh char *ltoa( FICL_INT value, char *string, int radix )
663*ca987d46SWarner Losh { /* convert long to string, any base */
664*ca987d46SWarner Losh char *cp = string;
665*ca987d46SWarner Losh int sign = ((radix == 10) && (value < 0));
666*ca987d46SWarner Losh int pwr;
667*ca987d46SWarner Losh
668*ca987d46SWarner Losh assert(radix > 1);
669*ca987d46SWarner Losh assert(radix < 37);
670*ca987d46SWarner Losh assert(string);
671*ca987d46SWarner Losh
672*ca987d46SWarner Losh pwr = isPowerOfTwo((FICL_UNS)radix);
673*ca987d46SWarner Losh
674*ca987d46SWarner Losh if (sign)
675*ca987d46SWarner Losh value = -value;
676*ca987d46SWarner Losh
677*ca987d46SWarner Losh if (value == 0)
678*ca987d46SWarner Losh *cp++ = '0';
679*ca987d46SWarner Losh else if (pwr != 0)
680*ca987d46SWarner Losh {
681*ca987d46SWarner Losh FICL_UNS v = (FICL_UNS) value;
682*ca987d46SWarner Losh FICL_UNS mask = (FICL_UNS) ~(-1 << pwr);
683*ca987d46SWarner Losh while (v)
684*ca987d46SWarner Losh {
685*ca987d46SWarner Losh *cp++ = digits[v & mask];
686*ca987d46SWarner Losh v >>= pwr;
687*ca987d46SWarner Losh }
688*ca987d46SWarner Losh }
689*ca987d46SWarner Losh else
690*ca987d46SWarner Losh {
691*ca987d46SWarner Losh UNSQR result;
692*ca987d46SWarner Losh DPUNS v;
693*ca987d46SWarner Losh v.hi = 0;
694*ca987d46SWarner Losh v.lo = (FICL_UNS)value;
695*ca987d46SWarner Losh while (v.lo)
696*ca987d46SWarner Losh {
697*ca987d46SWarner Losh result = ficlLongDiv(v, (FICL_UNS)radix);
698*ca987d46SWarner Losh *cp++ = digits[result.rem];
699*ca987d46SWarner Losh v.lo = result.quot;
700*ca987d46SWarner Losh }
701*ca987d46SWarner Losh }
702*ca987d46SWarner Losh
703*ca987d46SWarner Losh if (sign)
704*ca987d46SWarner Losh *cp++ = '-';
705*ca987d46SWarner Losh
706*ca987d46SWarner Losh *cp++ = '\0';
707*ca987d46SWarner Losh
708*ca987d46SWarner Losh return strrev(string);
709*ca987d46SWarner Losh }
710*ca987d46SWarner Losh
711*ca987d46SWarner Losh
712*ca987d46SWarner Losh /**************************************************************************
713*ca987d46SWarner Losh u l t o a
714*ca987d46SWarner Losh **
715*ca987d46SWarner Losh **************************************************************************/
ultoa(FICL_UNS value,char * string,int radix)716*ca987d46SWarner Losh char *ultoa(FICL_UNS value, char *string, int radix )
717*ca987d46SWarner Losh { /* convert long to string, any base */
718*ca987d46SWarner Losh char *cp = string;
719*ca987d46SWarner Losh DPUNS ud;
720*ca987d46SWarner Losh UNSQR result;
721*ca987d46SWarner Losh
722*ca987d46SWarner Losh assert(radix > 1);
723*ca987d46SWarner Losh assert(radix < 37);
724*ca987d46SWarner Losh assert(string);
725*ca987d46SWarner Losh
726*ca987d46SWarner Losh if (value == 0)
727*ca987d46SWarner Losh *cp++ = '0';
728*ca987d46SWarner Losh else
729*ca987d46SWarner Losh {
730*ca987d46SWarner Losh ud.hi = 0;
731*ca987d46SWarner Losh ud.lo = value;
732*ca987d46SWarner Losh result.quot = value;
733*ca987d46SWarner Losh
734*ca987d46SWarner Losh while (ud.lo)
735*ca987d46SWarner Losh {
736*ca987d46SWarner Losh result = ficlLongDiv(ud, (FICL_UNS)radix);
737*ca987d46SWarner Losh ud.lo = result.quot;
738*ca987d46SWarner Losh *cp++ = digits[result.rem];
739*ca987d46SWarner Losh }
740*ca987d46SWarner Losh }
741*ca987d46SWarner Losh
742*ca987d46SWarner Losh *cp++ = '\0';
743*ca987d46SWarner Losh
744*ca987d46SWarner Losh return strrev(string);
745*ca987d46SWarner Losh }
746*ca987d46SWarner Losh
747*ca987d46SWarner Losh
748*ca987d46SWarner Losh /**************************************************************************
749*ca987d46SWarner Losh c a s e F o l d
750*ca987d46SWarner Losh ** Case folds a NULL terminated string in place. All characters
751*ca987d46SWarner Losh ** get converted to lower case.
752*ca987d46SWarner Losh **************************************************************************/
caseFold(char * cp)753*ca987d46SWarner Losh char *caseFold(char *cp)
754*ca987d46SWarner Losh {
755*ca987d46SWarner Losh char *oldCp = cp;
756*ca987d46SWarner Losh
757*ca987d46SWarner Losh while (*cp)
758*ca987d46SWarner Losh {
759*ca987d46SWarner Losh if (isupper(*cp))
760*ca987d46SWarner Losh *cp = (char)tolower(*cp);
761*ca987d46SWarner Losh cp++;
762*ca987d46SWarner Losh }
763*ca987d46SWarner Losh
764*ca987d46SWarner Losh return oldCp;
765*ca987d46SWarner Losh }
766*ca987d46SWarner Losh
767*ca987d46SWarner Losh
768*ca987d46SWarner Losh /**************************************************************************
769*ca987d46SWarner Losh s t r i n c m p
770*ca987d46SWarner Losh ** (jws) simplified the code a bit in hopes of appeasing Purify
771*ca987d46SWarner Losh **************************************************************************/
strincmp(char * cp1,char * cp2,FICL_UNS count)772*ca987d46SWarner Losh int strincmp(char *cp1, char *cp2, FICL_UNS count)
773*ca987d46SWarner Losh {
774*ca987d46SWarner Losh int i = 0;
775*ca987d46SWarner Losh
776*ca987d46SWarner Losh for (; 0 < count; ++cp1, ++cp2, --count)
777*ca987d46SWarner Losh {
778*ca987d46SWarner Losh i = tolower(*cp1) - tolower(*cp2);
779*ca987d46SWarner Losh if (i != 0)
780*ca987d46SWarner Losh return i;
781*ca987d46SWarner Losh else if (*cp1 == '\0')
782*ca987d46SWarner Losh return 0;
783*ca987d46SWarner Losh }
784*ca987d46SWarner Losh return 0;
785*ca987d46SWarner Losh }
786*ca987d46SWarner Losh
787*ca987d46SWarner Losh /**************************************************************************
788*ca987d46SWarner Losh s k i p S p a c e
789*ca987d46SWarner Losh ** Given a string pointer, returns a pointer to the first non-space
790*ca987d46SWarner Losh ** char of the string, or to the NULL terminator if no such char found.
791*ca987d46SWarner Losh ** If the pointer reaches "end" first, stop there. Pass NULL to
792*ca987d46SWarner Losh ** suppress this behavior.
793*ca987d46SWarner Losh **************************************************************************/
skipSpace(char * cp,char * end)794*ca987d46SWarner Losh char *skipSpace(char *cp, char *end)
795*ca987d46SWarner Losh {
796*ca987d46SWarner Losh assert(cp);
797*ca987d46SWarner Losh
798*ca987d46SWarner Losh while ((cp != end) && isspace(*cp))
799*ca987d46SWarner Losh cp++;
800*ca987d46SWarner Losh
801*ca987d46SWarner Losh return cp;
802*ca987d46SWarner Losh }
803*ca987d46SWarner Losh
804*ca987d46SWarner Losh
805