1 /*******************************************************************
2 ** s t a c k . c
3 ** Forth Inspired Command Language
4 ** Author: John Sadler (john_sadler@alum.mit.edu)
5 ** Created: 16 Oct 1997
6 ** $Id: stack.c,v 1.11 2010/08/12 13:57:22 asau Exp $
7 *******************************************************************/
8 /*
9 ** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu)
10 ** All rights reserved.
11 **
12 ** Get the latest Ficl release at http://ficl.sourceforge.net
13 **
14 ** I am interested in hearing from anyone who uses Ficl. If you have
15 ** a problem, a success story, a defect, an enhancement request, or
16 ** if you would like to contribute to the Ficl release, please
17 ** contact me by email at the address above.
18 **
19 ** L I C E N S E  and  D I S C L A I M E R
20 **
21 ** Redistribution and use in source and binary forms, with or without
22 ** modification, are permitted provided that the following conditions
23 ** are met:
24 ** 1. Redistributions of source code must retain the above copyright
25 **    notice, this list of conditions and the following disclaimer.
26 ** 2. Redistributions in binary form must reproduce the above copyright
27 **    notice, this list of conditions and the following disclaimer in the
28 **    documentation and/or other materials provided with the distribution.
29 **
30 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
31 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 ** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
34 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 ** SUCH DAMAGE.
41 */
42 
43 /*-
44  * Adapted to work with FTH
45  *
46  * Copyright (c) 2004-2017 Michael Scholz <mi-scholz@users.sourceforge.net>
47  * All rights reserved.
48  *
49  * Redistribution and use in source and binary forms, with or without
50  * modification, are permitted provided that the following conditions
51  * are met:
52  * 1. Redistributions of source code must retain the above copyright
53  *    notice, this list of conditions and the following disclaimer.
54  * 2. Redistributions in binary form must reproduce the above copyright
55  *    notice, this list of conditions and the following disclaimer in the
56  *    documentation and/or other materials provided with the distribution.
57  *
58  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
59  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
62  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68  * SUCH DAMAGE.
69  *
70  * @(#)stack.c	1.50 12/31/17
71  */
72 
73 #if defined(HAVE_CONFIG_H)
74 #include "config.h"
75 #endif
76 
77 #include <stdlib.h>
78 #include "ficl.h"
79 
80 #include "fth.h"
81 #include "utils.h"
82 
83 #define STKDEPTH(s) (((s)->top - (s)->base) + 1)
84 
85 /*
86 ** N O T E: Stack convention:
87 **
88 ** THIS CHANGED IN FICL 4.0!
89 **
90 ** top points to the *current* top data value
91 ** push: increment top, store value at top
92 ** pop:  fetch value at top, decrement top
93 ** Stack grows from low to high memory
94 */
95 
96 /*******************************************************************
97  **                  v m C h e c k S t a c k
98  ** Check the parameter stack for underflow or overflow.
99  ** size controls the type of check: if size is zero,
100  ** the function checks the stack state for underflow and overflow.
101  ** If size > 0, checks to see that the stack has room to push
102  ** that many cells. If less than zero, checks to see that the
103  ** stack has room to pop that many cells. If any test fails,
104  ** the function throws (via vmThrow) a VM_ERREXIT exception.
105  *******************************************************************/
106 /*
107  * [ms]
108  * raises 'stack-underflow exception
109  */
110 void
ficlStackCheck(ficlStack * stack,int popCells,int pushCells)111 ficlStackCheck(ficlStack *stack, int popCells, int pushCells)
112 {
113 	ficlInteger depth, nFree, pop, push;
114 
115 	pop = (ficlInteger)popCells;
116 	push = (ficlInteger)pushCells;
117 	depth = STKDEPTH(stack);
118 	nFree = (ficlInteger)stack->size - depth;
119 	if (pop > depth) {
120 		if (depth < 0)
121 			ficlVmThrowException(stack->vm,
122 			    FICL_VM_STATUS_STACK_UNDERFLOW,
123 			    "not enough arguments, at least %ld required",
124 			    pop + -depth);
125 		else
126 			ficlVmThrowException(stack->vm,
127 			    FICL_VM_STATUS_STACK_UNDERFLOW,
128 			    "not enough arguments, %ld instead of %ld",
129 			    depth,
130 			    pop);
131 	}
132 	if (nFree < (push - pop)) {
133 		if (stack->name != NULL && strcmp(stack->name, "data") == 0)
134 			ficlVmThrowException(stack->vm,
135 			    FICL_VM_STATUS_STACK_OVERFLOW, NULL);
136 		else
137 			ficlVmThrowException(stack->vm,
138 			    FICL_VM_STATUS_RSTACK_OVERFLOW, NULL);
139 	}
140 }
141 
142 /*******************************************************************
143  **                  s t a c k C r e a t e
144  **
145  *******************************************************************/
ficlStackCreate(ficlVm * vm,char * name,unsigned size)146 ficlStack *ficlStackCreate(ficlVm *vm, char *name, unsigned size)
147 {
148   size_t totalSize = sizeof(ficlStack) + (size * sizeof(ficlCell));
149   ficlStack *stack;
150 
151   FICL_ASSERT(size > 0);
152   stack = memset(FTH_MALLOC(totalSize), 0, totalSize);
153 
154   stack->size = size;
155   stack->frame = NULL;
156 
157   stack->vm = vm;
158   stack->name = name;
159 
160   ficlStackReset(stack);
161   return stack;
162 }
163 
164 /*******************************************************************
165  **                  s t a c k D e p t h
166  **
167  *******************************************************************/
ficlStackDepth(ficlStack * stack)168 int ficlStackDepth(ficlStack *stack)
169 {
170   return (int)STKDEPTH(stack);
171 }
172 
173 /*******************************************************************
174  **                  s t a c k D r o p
175  **
176  *******************************************************************/
ficlStackDrop(ficlStack * stack,int n)177 void ficlStackDrop(ficlStack *stack, int n)
178 {
179   if (n > 0)
180     stack->top -= n;
181 }
182 
183 /*******************************************************************
184  **                  s t a c k F e t c h
185  **
186  *******************************************************************/
ficlStackFetch(ficlStack * stack,int n)187 ficlCell ficlStackFetch(ficlStack *stack, int n)
188 {
189   return stack->top[-n];
190 }
191 
ficlStackStore(ficlStack * stack,int n,ficlCell c)192 void ficlStackStore(ficlStack *stack, int n, ficlCell c)
193 {
194   stack->top[-n] = c;
195 }
196 
197 /*******************************************************************
198  **                    s t a c k G e t T o p
199  **
200  *******************************************************************/
ficlStackGetTop(ficlStack * stack)201 ficlCell ficlStackGetTop(ficlStack *stack)
202 {
203   return stack->top[0];
204 }
205 
206 /*******************************************************************
207  **                  s t a c k L i n k
208  ** Link a frame using the stack's frame pointer. Allot space for
209  ** size cells in the frame
210  ** 1) Push frame
211  ** 2) frame = top
212  ** 3) top += size
213  *******************************************************************/
ficlStackLink(ficlStack * stack,int size)214 void ficlStackLink(ficlStack *stack, int size)
215 {
216   ficlStackPushPointer(stack, stack->frame);
217   stack->frame = stack->top + 1;
218   stack->top += size;
219 }
220 
221 /*******************************************************************
222  **                  s t a c k U n l i n k
223  ** Unlink a stack frame previously created by stackLink
224  ** 1) top = frame
225  ** 2) frame = pop()
226  *******************************************************************/
ficlStackUnlink(ficlStack * stack)227 void ficlStackUnlink(ficlStack *stack)
228 {
229   stack->top = stack->frame - 1;
230   stack->frame = ficlStackPopPointer(stack);
231 
232 }
233 
234 /*******************************************************************
235  **                  s t a c k P i c k
236  **
237  *******************************************************************/
ficlStackPick(ficlStack * stack,int n)238 void ficlStackPick(ficlStack *stack, int n)
239 {
240   ficlCell cell;
241 
242   cell = stack->top[-n];
243   *++stack->top = cell;
244   /*
245    * With
246    * *++stack->top = stack->top[-n];
247    * gcc45+ complains:
248    * warning: operation on `stack->top' may be undefined [-Wsequence-point]
249    */
250 }
251 
252 /*******************************************************************
253  **                  s t a c k P o p
254  **
255  *******************************************************************/
ficlStackPop(ficlStack * stack)256 ficlCell ficlStackPop(ficlStack *stack)
257 {
258   return *stack->top--;
259 }
260 
ficlStackPopInteger(ficlStack * stack)261 ficlInteger ficlStackPopInteger(ficlStack *stack)
262 {
263   ficlInteger i = STACK_INT_REF(stack);
264 
265   stack->top--;
266   return i;
267 }
268 
ficlStackPopUnsigned(ficlStack * stack)269 ficlUnsigned ficlStackPopUnsigned(ficlStack *stack)
270 {
271   ficlUnsigned u = STACK_UINT_REF(stack);
272 
273   stack->top--;
274   return u;
275 }
276 
ficlStackPop2Integer(ficlStack * stack)277 ficl2Integer ficlStackPop2Integer(ficlStack *stack)
278 {
279   ficl2Integer di = STACK_LONG_REF(stack);
280 
281   stack->top--;
282   return di;
283 }
284 
ficlStackPop2Unsigned(ficlStack * stack)285 ficl2Unsigned ficlStackPop2Unsigned(ficlStack *stack)
286 {
287   ficl2Unsigned ud = STACK_ULONG_REF(stack);
288 
289   stack->top--;
290   return ud;
291 }
292 
ficlStackPopBoolean(ficlStack * stack)293 int ficlStackPopBoolean(ficlStack *stack)
294 {
295   int i = STACK_BOOL_REF(stack);
296 
297   stack->top--;
298   return i;
299 }
300 
ficlStackPopPointer(ficlStack * stack)301 void *ficlStackPopPointer(ficlStack *stack)
302 {
303   void *p = STACK_VOIDP_REF(stack);
304 
305   stack->top--;
306   return p;
307 }
308 
ficlStackPopFTH(ficlStack * stack)309 FTH ficlStackPopFTH(ficlStack *stack)
310 {
311   FTH fp = STACK_FTH_REF(stack);
312 
313   stack->top--;
314   return fp;
315 }
316 
ficlStackPopFloat(ficlStack * stack)317 ficlFloat ficlStackPopFloat(ficlStack *stack)
318 {
319   ficlFloat f = STACK_FLOAT_REF(stack);
320 
321   stack->top--;
322   return f;
323 }
324 /*******************************************************************
325  **                  s t a c k P u s h
326  **
327  *******************************************************************/
ficlStackPush(ficlStack * stack,ficlCell c)328 void ficlStackPush(ficlStack *stack, ficlCell c)
329 {
330   *++stack->top = c;
331 }
332 
ficlStackPushInteger(ficlStack * stack,ficlInteger i)333 void ficlStackPushInteger(ficlStack *stack, ficlInteger i)
334 {
335   ++stack->top;
336   STACK_INT_SET(stack, i);
337 }
338 
ficlStackPushUnsigned(ficlStack * stack,ficlUnsigned u)339 void ficlStackPushUnsigned(ficlStack *stack, ficlUnsigned u)
340 {
341   ++stack->top;
342   STACK_UINT_SET(stack, u);
343 }
ficlStackPush2Integer(ficlStack * stack,ficl2Integer di)344 void ficlStackPush2Integer(ficlStack *stack, ficl2Integer di)
345 {
346   ++stack->top;
347   if (FIXABLE_P(di))
348     STACK_INT_SET(stack, di);
349   else
350     STACK_LONG_SET(stack, di);
351 }
352 
ficlStackPush2Unsigned(ficlStack * stack,ficl2Unsigned ud)353 void ficlStackPush2Unsigned(ficlStack *stack, ficl2Unsigned ud)
354 {
355   ++stack->top;
356   if (POSFIXABLE_P((long)ud))
357     STACK_UINT_SET(stack, ud);
358   else
359     STACK_ULONG_SET(stack, ud);
360 }
361 
ficlStackPushBoolean(ficlStack * stack,int b)362 void ficlStackPushBoolean(ficlStack *stack, int b)
363 {
364   ++stack->top;
365   STACK_BOOL_SET(stack, b);
366 }
367 
ficlStackPushPointer(ficlStack * stack,void * p)368 void ficlStackPushPointer(ficlStack *stack, void *p)
369 {
370   ++stack->top;
371   STACK_VOIDP_SET(stack, p);
372 }
373 
ficlStackPushFTH(ficlStack * stack,FTH fp)374 void ficlStackPushFTH(ficlStack *stack, FTH fp)
375 {
376   ++stack->top;
377   STACK_FTH_SET(stack, fp);
378 }
379 
ficlStackPushFloat(ficlStack * stack,ficlFloat f)380 void ficlStackPushFloat(ficlStack *stack, ficlFloat f)
381 {
382   ++stack->top;
383   STACK_FLOAT_SET(stack, f);
384 }
385 
386 /*******************************************************************
387  **                  s t a c k R e s e t
388  **
389  *******************************************************************/
ficlStackReset(ficlStack * stack)390 void ficlStackReset(ficlStack *stack)
391 {
392   stack->top = stack->base - 1;
393 }
394 
395 /*******************************************************************
396  **                  s t a c k R o l l
397  ** Roll nth stack entry to the top (counting from zero), if n is
398  ** >= 0. Drop other entries as needed to fill the hole.
399  ** If n < 0, roll top-of-stack to nth entry, pushing others
400  ** upward as needed to fill the hole.
401  *******************************************************************/
ficlStackRoll(ficlStack * stack,int n)402 void ficlStackRoll(ficlStack *stack, int n)
403 {
404   ficlCell c;
405   ficlCell *cell;
406 
407   if (n == 0)
408     return;
409 
410   else if (n > 0)
411   {
412     cell = stack->top - n;
413     c = *cell;
414 
415     for (;n > 0; --n, cell++)
416       *cell = cell[1];
417 
418     *cell = c;
419   }
420   else
421   {
422     cell = stack->top;
423     c = *cell;
424 
425     for (; n < 0; ++n, cell--)
426       *cell = cell[-1];
427 
428     *cell = c;
429   }
430 }
431 
432 /*******************************************************************
433  **                  s t a c k S e t T o p
434  **
435  *******************************************************************/
ficlStackSetTop(ficlStack * stack,ficlCell c)436 void ficlStackSetTop(ficlStack *stack, ficlCell c)
437 {
438   FICL_STACK_CHECK(stack, 1, 1);
439   stack->top[0] = c;
440 }
441 
ficlStackWalk(ficlStack * stack,ficlStackWalkFunction callback,void * context,ficlInteger bottomToTop)442 void ficlStackWalk(ficlStack *stack,
443 		   ficlStackWalkFunction callback,
444 		   void *context,
445 		   ficlInteger bottomToTop)
446 {
447   int i;
448   int depth;
449   ficlCell *cell;
450 
451   FICL_STACK_CHECK(stack, 0, 0);
452 
453   depth = ficlStackDepth(stack);
454   cell = bottomToTop ? stack->base : stack->top;
455 
456   for (i = 0; i < depth; i++)
457   {
458     if (callback(context, cell) == FICL_FALSE)
459       break;
460 
461     cell += bottomToTop ? 1 : -1;
462   }
463 }
464