5761222 [rkeene@sledge /home/rkeene/devel/old/bc-dos/dc]$ cat -n stack.c
  1 /* 
  2  * implement stack functions for dc
  3  *
  4  * Copyright (C) 1994, 1997, 1998 Free Software Foundation, Inc.
  5  *
  6  * This program is free software; you can redistribute it and/or modify
  7  * it under the terms of the GNU General Public License as published by
  8  * the Free Software Foundation; either version 2, or (at your option)
  9  * any later version.
 10  *
 11  * This program is distributed in the hope that it will be useful,
 12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14  * GNU General Public License for more details.
 15  *
 16  * You should have received a copy of the GNU General Public License
 17  * along with this program; if not, you can either send email to this
 18  * program's author (see below) or write to: The Free Software Foundation,
 19  * Inc.; 675 Mass Ave. Cambridge, MA 02139, USA.
 20  */
 21 
 22 /* This module is the only one that knows what stacks (both the
 23  * regular evaluation stack and the named register stacks)
 24  * look like.
 25  */
 26 
 27 #include "config.h"
 28 
 29 #include <stdio.h>
 30 #ifdef HAVE_STDLIB_H
 31 # include <stdlib.h>
 32 #endif
 33 #include "dc.h"
 34 #include "dc-proto.h"
 35 #include "dc-regdef.h"
 36 
 37 /* an oft-used error message: */
 38 #define Empty_Stack fprintf(stderr, "%s: stack empty\n", progname)
 39 
 40 
 41 /* simple linked-list implementaion suffices: */
 42 struct dc_list {
 43     dc_data value;
 44     struct dc_array *array; /* opaque */
 45     struct dc_list *link;
 46 };
 47 typedef struct dc_list dc_list;
 48 
 49 /* the anonymous evaluation stack */
 50 static dc_list *dc_stack=NULL;
 51 
 52 /* the named register stacks */
 53 static dc_list *dc_register[DC_REGCOUNT];
 54 
 55 
 56 /* allocate a new dc_list item */
 57 static dc_list *
 58 dc_alloc DC_DECLVOID()
 59 {
 60     dc_list *result;
 61 
 62     result = dc_malloc(sizeof *result);
 63     result->value.dc_type = DC_UNINITIALIZED;
 64     result->array = NULL;
 65     result->link = NULL;
 66     return result;
 67 }
 68 
 69 
 70 /* check that there are two numbers on top of the stack,
 71  * then call op with the popped numbers.  Construct a dc_data
 72  * value from the dc_num returned by op and push it
 73  * on the stack.
 74  * If the op call doesn't return DC_SUCCESS, then leave the stack
 75  * unmodified.
 76  */
 77 void
 78 dc_binop DC_DECLARG((op, kscale))
 79     int (*op)DC_PROTO((dc_num, dc_num, int, dc_num *)) DC_DECLSEP
 80     int kscale DC_DECLEND
 81 {
 82     dc_data a;
 83     dc_data b;
 84     dc_data r;
 85 
 86     if (!dc_stack || !dc_stack->link){
 87         Empty_Stack;
 88         return;
 89     }
 90     if (dc_stack->value.dc_type!=DC_NUMBER
 91             || dc_stack->link->value.dc_type!=DC_NUMBER){
 92         fprintf(stderr, "%s: non-numeric value\n", progname);
 93         return;
 94     }
 95     (void)dc_pop(&b);
 96     (void)dc_pop(&a);
 97     if ((*op)(a.v.number, b.v.number, kscale, &r.v.number) == DC_SUCCESS){
 98         r.dc_type = DC_NUMBER;
 99         dc_push(r);
100         dc_free_num(&a.v.number);
101         dc_free_num(&b.v.number);
102     }else{
103         /* op failed; restore the stack */
104         dc_push(a);
105         dc_push(b);
106     }
107 }
108 
109 /* check that there are two numbers on top of the stack,
110  * then call op with the popped numbers.  Construct two dc_data
111  * values from the dc_num's returned by op and push them
112  * on the stack.
113  * If the op call doesn't return DC_SUCCESS, then leave the stack
114  * unmodified.
115  */
116 void
117 dc_binop2 DC_DECLARG((op, kscale))
118     int (*op)DC_PROTO((dc_num, dc_num, int, dc_num *, dc_num *)) DC_DECLSEP
119     int kscale DC_DECLEND
120 {
121     dc_data a;
122     dc_data b;
123     dc_data r1;
124     dc_data r2;
125 
126     if (!dc_stack || !dc_stack->link){
127         Empty_Stack;
128         return;
129     }
130     if (dc_stack->value.dc_type!=DC_NUMBER
131             || dc_stack->link->value.dc_type!=DC_NUMBER){
132         fprintf(stderr, "%s: non-numeric value\n", progname);
133         return;
134     }
135     (void)dc_pop(&b);
136     (void)dc_pop(&a);
137     if ((*op)(a.v.number, b.v.number, kscale,
138                                 &r1.v.number, &r2.v.number) == DC_SUCCESS){
139         r1.dc_type = DC_NUMBER;
140         dc_push(r1);
141         r2.dc_type = DC_NUMBER;
142         dc_push(r2);
143         dc_free_num(&a.v.number);
144         dc_free_num(&b.v.number);
145     }else{
146         /* op failed; restore the stack */
147         dc_push(a);
148         dc_push(b);
149     }
150 }
151 
152 /* check that there are two numbers on top of the stack,
153  * then call dc_compare with the popped numbers.
154  * Return negative, zero, or positive based on the ordering
155  * of the two numbers.
156  */
157 int
158 dc_cmpop DC_DECLVOID()
159 {
160     int result;
161     dc_data a;
162     dc_data b;
163 
164     if (!dc_stack || !dc_stack->link){
165         Empty_Stack;
166         return 0;
167     }
168     if (dc_stack->value.dc_type!=DC_NUMBER
169             || dc_stack->link->value.dc_type!=DC_NUMBER){
170         fprintf(stderr, "%s: non-numeric value\n", progname);
171         return 0;
172     }
173     (void)dc_pop(&b);
174     (void)dc_pop(&a);
175     result = dc_compare(b.v.number, a.v.number);
176     dc_free_num(&a.v.number);
177     dc_free_num(&b.v.number);
178     return result;
179 }
180 
181 /* check that there are three numbers on top of the stack,
182  * then call op with the popped numbers.  Construct a dc_data
183  * value from the dc_num returned by op and push it
184  * on the stack.
185  * If the op call doesn't return DC_SUCCESS, then leave the stack
186  * unmodified.
187  */
188 void
189 dc_triop DC_DECLARG((op, kscale))
190     int (*op)DC_PROTO((dc_num, dc_num, dc_num, int, dc_num *)) DC_DECLSEP
191     int kscale DC_DECLEND
192 {
193     dc_data a;
194     dc_data b;
195     dc_data c;
196     dc_data r;
197 
198     if (!dc_stack || !dc_stack->link || !dc_stack->link->link){
199         Empty_Stack;
200         return;
201     }
202     if (dc_stack->value.dc_type!=DC_NUMBER
203             || dc_stack->link->value.dc_type!=DC_NUMBER
204             || dc_stack->link->link->value.dc_type!=DC_NUMBER){
205         fprintf(stderr, "%s: non-numeric value\n", progname);
206         return;
207     }
208     (void)dc_pop(&c);
209     (void)dc_pop(&b);
210     (void)dc_pop(&a);
211     if ((*op)(a.v.number, b.v.number, c.v.number,
212                 kscale, &r.v.number) == DC_SUCCESS){
213         r.dc_type = DC_NUMBER;
214         dc_push(r);
215         dc_free_num(&a.v.number);
216         dc_free_num(&b.v.number);
217         dc_free_num(&c.v.number);
218     }else{
219         /* op failed; restore the stack */
220         dc_push(a);
221         dc_push(b);
222         dc_push(c);
223     }
224 }
225 
226 
227 /* initialize the register stacks to their initial values */
228 void
229 dc_register_init DC_DECLVOID()
230 {
231     int i;
232 
233     for (i=0; i<DC_REGCOUNT; ++i)
234         dc_register[i] = NULL;
235 }
236 
237 /* clear the evaluation stack */
238 void
239 dc_clear_stack DC_DECLVOID()
240 {
241     dc_list *n;
242     dc_list *t;
243 
244     for (n=dc_stack; n; n=t){
245         t = n->link;
246         if (n->value.dc_type == DC_NUMBER)
247             dc_free_num(&n->value.v.number);
248         else if (n->value.dc_type == DC_STRING)
249             dc_free_str(&n->value.v.string);
250         else
251             dc_garbage("in stack", -1);
252         dc_array_free(n->array);
253         free(n);
254     }
255     dc_stack = NULL;
256 }
257 
258 /* push a value onto the evaluation stack */
259 void
260 dc_push DC_DECLARG((value))
261     dc_data value DC_DECLEND
262 {
263     dc_list *n = dc_alloc();
264 
265     if (value.dc_type!=DC_NUMBER && value.dc_type!=DC_STRING)
266         dc_garbage("in data being pushed", -1);
267     n->value = value;
268     n->link = dc_stack;
269     dc_stack = n;
270 }
271 
272 /* push a value onto the named register stack */
273 void
274 dc_register_push DC_DECLARG((stackid, value))
275     int stackid DC_DECLSEP
276     dc_data value DC_DECLEND
277 {
278     dc_list *n = dc_alloc();
279 
280     stackid = regmap(stackid);
281     n->value = value;
282     n->link = dc_register[stackid];
283     dc_register[stackid] = n;
284 }
285 
286 /* set *result to the value on the top of the evaluation stack */
287 /* The caller is responsible for duplicating the value if it
288  * is to be maintained as anything more than a transient identity.
289  *
290  * DC_FAIL is returned if the stack is empty (and *result unchanged),
291  * DC_SUCCESS is returned otherwise
292  */
293 int
294 dc_top_of_stack DC_DECLARG((result))
295     dc_data *result DC_DECLEND
296 {
297     if (!dc_stack){
298         Empty_Stack;
299         return DC_FAIL;
300     }
301     if (dc_stack->value.dc_type!=DC_NUMBER
302             && dc_stack->value.dc_type!=DC_STRING)
303         dc_garbage("at top of stack", -1);
304     *result = dc_stack->value;
305     return DC_SUCCESS;
306 }
307 
308 /* set *result to a dup of the value on the top of the named register stack */
309 /*
310  * DC_FAIL is returned if the named stack is empty (and *result unchanged),
311  * DC_SUCCESS is returned otherwise
312  */
313 int
314 dc_register_get DC_DECLARG((regid, result))
315     int regid DC_DECLSEP
316     dc_data *result DC_DECLEND
317 {
318     dc_list *r;
319 
320     regid = regmap(regid);
321     r = dc_register[regid];
322     if ( ! r ){
323         fprintf(stderr, "%s: register ", progname);
324         dc_show_id(stderr, regid, " is empty\n");
325         return DC_FAIL;
326     }
327     *result = dc_dup(r->value);
328     return DC_SUCCESS;
329 }
330 
331 /* set the top of the named register stack to the indicated value */
332 /* If the named stack is empty, craft a stack entry to enter the
333  * value into.
334  */
335 void
336 dc_register_set DC_DECLARG((regid, value))
337     int regid DC_DECLSEP
338     dc_data value DC_DECLEND
339 {
340     dc_list *r;
341 
342     regid = regmap(regid);
343     r = dc_register[regid];
344     if ( ! r )
345         dc_register[regid] = dc_alloc();
346     else if (r->value.dc_type == DC_NUMBER)
347         dc_free_num(&r->value.v.number);
348     else if (r->value.dc_type == DC_STRING)
349         dc_free_str(&r->value.v.string);
350     else
351         dc_garbage("", regid);
352     dc_register[regid]->value = value;
353 }
354 
355 /* pop from the evaluation stack
356  *
357  * DC_FAIL is returned if the stack is empty (and *result unchanged),
358  * DC_SUCCESS is returned otherwise
359  */
360 int
361 dc_pop DC_DECLARG((result))
362     dc_data *result DC_DECLEND
363 {
364     dc_list *r;
365 
366     r = dc_stack;
367     if (!r){
368         Empty_Stack;
369         return DC_FAIL;
370     }
371     if (r->value.dc_type!=DC_NUMBER && r->value.dc_type!=DC_STRING)
372         dc_garbage("at top of stack", -1);
373     *result = r->value;
374     dc_stack = r->link;
375     dc_array_free(r->array);
376     free(r);
377     return DC_SUCCESS;
378 }
379 
380 /* pop from the named register stack
381  *
382  * DC_FAIL is returned if the named stack is empty (and *result unchanged),
383  * DC_SUCCESS is returned otherwise
384  */
385 int
386 dc_register_pop DC_DECLARG((stackid, result))
387     int stackid DC_DECLSEP
388     dc_data *result DC_DECLEND
389 {
390     dc_list *r;
391 
392     stackid = regmap(stackid);
393     r = dc_register[stackid];
394     if (!r){
395         fprintf(stderr, "%s: stack register ", progname);
396         dc_show_id(stderr, stackid, " is empty\n");
397         return DC_FAIL;
398     }
399     if (r->value.dc_type!=DC_NUMBER && r->value.dc_type!=DC_STRING)
400         dc_garbage(" stack", stackid);
401     *result = r->value;
402     dc_register[stackid] = r->link;
403     dc_array_free(r->array);
404     free(r);
405     return DC_SUCCESS;
406 }
407 
408 
409 /* tell how many entries are currently on the evaluation stack */
410 int
411 dc_tell_stackdepth DC_DECLVOID()
412 {
413     dc_list *n;
414     int depth=0;
415 
416     for (n=dc_stack; n; n=n->link)
417         ++depth;
418     return depth;
419 }
420 
421 
422 /* return the length of the indicated data value;
423  * if discard_p is DC_TOSS, the deallocate the value when done
424  *
425  * The definition of a datum's length is deligated to the
426  * appropriate module.
427  */
428 int
429 dc_tell_length DC_DECLARG((value, discard_p))
430     dc_data value DC_DECLSEP
431     dc_discard discard_p DC_DECLEND
432 {
433     int length;
434 
435     if (value.dc_type == DC_NUMBER){
436         length = dc_numlen(value.v.number);
437         if (discard_p == DC_TOSS)
438             dc_free_num(&value.v.number);
439     } else if (value.dc_type == DC_STRING) {
440         length = dc_strlen(value.v.string);
441         if (discard_p == DC_TOSS)
442             dc_free_str(&value.v.string);
443     } else {
444         dc_garbage("in tell_length", -1);
445         /*NOTREACHED*/
446         length = 0; /*just to suppress spurious compiler warnings*/
447     }
448     return length;
449 }
450 
451 
452 
453 /* print out all of the values on the evaluation stack */
454 void
455 dc_printall DC_DECLARG((obase))
456     int obase DC_DECLEND
457 {
458     dc_list *n;
459 
460     for (n=dc_stack; n; n=n->link)
461         dc_print(n->value, obase, DC_WITHNL, DC_KEEP);
462 }
463 
464 
465 
466 
467 /* get the current array head for the named array */
468 struct dc_array *
469 dc_get_stacked_array DC_DECLARG((array_id))
470     int array_id DC_DECLEND
471 {
472     dc_list *r = dc_register[regmap(array_id)];
473     return r ? r->array : NULL;
474 }
475 
476 /* set the current array head for the named array */
477 void
478 dc_set_stacked_array DC_DECLARG((array_id, new_head))
479     int array_id DC_DECLSEP
480     struct dc_array *new_head DC_DECLEND
481 {
482     dc_list *r;
483 
484     array_id = regmap(array_id);
485     r = dc_register[array_id];
486     if ( ! r )
487         r = dc_register[array_id] = dc_alloc();
488     r->array = new_head;
489 }
5761223 [rkeene@sledge /home/rkeene/devel/old/bc-dos/dc]$

Click here to go back to the directory listing.
Click here to download this file.
last modified: 1998-03-09 05:21:01