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