Sync usage with man page.
[netbsd-mini2440.git] / gnu / dist / bc / dc / stack.c
blob1d8a9bf73133b99390c3bdbf0f59d0de0969ea90
1 /*
2 * implement stack functions for dc
4 * Copyright (C) 1994, 1997, 1998 Free Software Foundation, Inc.
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.
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.
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:
20 * The Free Software Foundation, Inc.
21 * 59 Temple Place, Suite 330
22 * Boston, MA 02111 USA
25 /* This module is the only one that knows what stacks (both the
26 * regular evaluation stack and the named register stacks)
27 * look like.
30 #include "config.h"
32 #include <stdio.h>
33 #ifdef HAVE_STDLIB_H
34 # include <stdlib.h>
35 #endif
36 #include "dc.h"
37 #include "dc-proto.h"
38 #include "dc-regdef.h"
40 /* an oft-used error message: */
41 #define Empty_Stack fprintf(stderr, "%s: stack empty\n", progname)
44 /* simple linked-list implementaion suffices: */
45 struct dc_list {
46 dc_data value;
47 struct dc_array *array; /* opaque */
48 struct dc_list *link;
50 typedef struct dc_list dc_list;
52 /* the anonymous evaluation stack */
53 static dc_list *dc_stack=NULL;
55 /* the named register stacks */
56 static dc_list *dc_register[DC_REGCOUNT];
59 /* allocate a new dc_list item */
60 static dc_list *
61 dc_alloc DC_DECLVOID()
63 dc_list *result;
65 result = dc_malloc(sizeof *result);
66 result->value.dc_type = DC_UNINITIALIZED;
67 result->array = NULL;
68 result->link = NULL;
69 return result;
73 /* check that there are two numbers on top of the stack,
74 * then call op with the popped numbers. Construct a dc_data
75 * value from the dc_num returned by op and push it
76 * on the stack.
77 * If the op call doesn't return DC_SUCCESS, then leave the stack
78 * unmodified.
80 void
81 dc_binop DC_DECLARG((op, kscale))
82 int (*op)DC_PROTO((dc_num, dc_num, int, dc_num *)) DC_DECLSEP
83 int kscale DC_DECLEND
85 dc_data a;
86 dc_data b;
87 dc_data r;
89 if (!dc_stack || !dc_stack->link){
90 Empty_Stack;
91 return;
93 if (dc_stack->value.dc_type!=DC_NUMBER
94 || dc_stack->link->value.dc_type!=DC_NUMBER){
95 fprintf(stderr, "%s: non-numeric value\n", progname);
96 return;
98 (void)dc_pop(&b);
99 (void)dc_pop(&a);
100 if ((*op)(a.v.number, b.v.number, kscale, &r.v.number) == DC_SUCCESS){
101 r.dc_type = DC_NUMBER;
102 dc_push(r);
103 dc_free_num(&a.v.number);
104 dc_free_num(&b.v.number);
105 }else{
106 /* op failed; restore the stack */
107 dc_push(a);
108 dc_push(b);
112 /* check that there are two numbers on top of the stack,
113 * then call op with the popped numbers. Construct two dc_data
114 * values from the dc_num's returned by op and push them
115 * on the stack.
116 * If the op call doesn't return DC_SUCCESS, then leave the stack
117 * unmodified.
119 void
120 dc_binop2 DC_DECLARG((op, kscale))
121 int (*op)DC_PROTO((dc_num, dc_num, int, dc_num *, dc_num *)) DC_DECLSEP
122 int kscale DC_DECLEND
124 dc_data a;
125 dc_data b;
126 dc_data r1;
127 dc_data r2;
129 if (!dc_stack || !dc_stack->link){
130 Empty_Stack;
131 return;
133 if (dc_stack->value.dc_type!=DC_NUMBER
134 || dc_stack->link->value.dc_type!=DC_NUMBER){
135 fprintf(stderr, "%s: non-numeric value\n", progname);
136 return;
138 (void)dc_pop(&b);
139 (void)dc_pop(&a);
140 if ((*op)(a.v.number, b.v.number, kscale,
141 &r1.v.number, &r2.v.number) == DC_SUCCESS){
142 r1.dc_type = DC_NUMBER;
143 dc_push(r1);
144 r2.dc_type = DC_NUMBER;
145 dc_push(r2);
146 dc_free_num(&a.v.number);
147 dc_free_num(&b.v.number);
148 }else{
149 /* op failed; restore the stack */
150 dc_push(a);
151 dc_push(b);
155 /* check that there are two numbers on top of the stack,
156 * then call dc_compare with the popped numbers.
157 * Return negative, zero, or positive based on the ordering
158 * of the two numbers.
161 dc_cmpop DC_DECLVOID()
163 int result;
164 dc_data a;
165 dc_data b;
167 if (!dc_stack || !dc_stack->link){
168 Empty_Stack;
169 return 0;
171 if (dc_stack->value.dc_type!=DC_NUMBER
172 || dc_stack->link->value.dc_type!=DC_NUMBER){
173 fprintf(stderr, "%s: non-numeric value\n", progname);
174 return 0;
176 (void)dc_pop(&b);
177 (void)dc_pop(&a);
178 result = dc_compare(b.v.number, a.v.number);
179 dc_free_num(&a.v.number);
180 dc_free_num(&b.v.number);
181 return result;
184 /* check that there are three numbers on top of the stack,
185 * then call op with the popped numbers. Construct a dc_data
186 * value from the dc_num returned by op and push it
187 * on the stack.
188 * If the op call doesn't return DC_SUCCESS, then leave the stack
189 * unmodified.
191 void
192 dc_triop DC_DECLARG((op, kscale))
193 int (*op)DC_PROTO((dc_num, dc_num, dc_num, int, dc_num *)) DC_DECLSEP
194 int kscale DC_DECLEND
196 dc_data a;
197 dc_data b;
198 dc_data c;
199 dc_data r;
201 if (!dc_stack || !dc_stack->link || !dc_stack->link->link){
202 Empty_Stack;
203 return;
205 if (dc_stack->value.dc_type!=DC_NUMBER
206 || dc_stack->link->value.dc_type!=DC_NUMBER
207 || dc_stack->link->link->value.dc_type!=DC_NUMBER){
208 fprintf(stderr, "%s: non-numeric value\n", progname);
209 return;
211 (void)dc_pop(&c);
212 (void)dc_pop(&b);
213 (void)dc_pop(&a);
214 if ((*op)(a.v.number, b.v.number, c.v.number,
215 kscale, &r.v.number) == DC_SUCCESS){
216 r.dc_type = DC_NUMBER;
217 dc_push(r);
218 dc_free_num(&a.v.number);
219 dc_free_num(&b.v.number);
220 dc_free_num(&c.v.number);
221 }else{
222 /* op failed; restore the stack */
223 dc_push(a);
224 dc_push(b);
225 dc_push(c);
230 /* initialize the register stacks to their initial values */
231 void
232 dc_register_init DC_DECLVOID()
234 int i;
236 for (i=0; i<DC_REGCOUNT; ++i)
237 dc_register[i] = NULL;
240 /* clear the evaluation stack */
241 void
242 dc_clear_stack DC_DECLVOID()
244 dc_list *n;
245 dc_list *t;
247 for (n=dc_stack; n; n=t){
248 t = n->link;
249 if (n->value.dc_type == DC_NUMBER)
250 dc_free_num(&n->value.v.number);
251 else if (n->value.dc_type == DC_STRING)
252 dc_free_str(&n->value.v.string);
253 else
254 dc_garbage("in stack", -1);
255 dc_array_free(n->array);
256 free(n);
258 dc_stack = NULL;
261 /* push a value onto the evaluation stack */
262 void
263 dc_push DC_DECLARG((value))
264 dc_data value DC_DECLEND
266 dc_list *n = dc_alloc();
268 if (value.dc_type!=DC_NUMBER && value.dc_type!=DC_STRING)
269 dc_garbage("in data being pushed", -1);
270 n->value = value;
271 n->link = dc_stack;
272 dc_stack = n;
275 /* push a value onto the named register stack */
276 void
277 dc_register_push DC_DECLARG((stackid, value))
278 int stackid DC_DECLSEP
279 dc_data value DC_DECLEND
281 dc_list *n = dc_alloc();
283 stackid = regmap(stackid);
284 n->value = value;
285 n->link = dc_register[stackid];
286 dc_register[stackid] = n;
289 /* set *result to the value on the top of the evaluation stack */
290 /* The caller is responsible for duplicating the value if it
291 * is to be maintained as anything more than a transient identity.
293 * DC_FAIL is returned if the stack is empty (and *result unchanged),
294 * DC_SUCCESS is returned otherwise
297 dc_top_of_stack DC_DECLARG((result))
298 dc_data *result DC_DECLEND
300 if (!dc_stack){
301 Empty_Stack;
302 return DC_FAIL;
304 if (dc_stack->value.dc_type!=DC_NUMBER
305 && dc_stack->value.dc_type!=DC_STRING)
306 dc_garbage("at top of stack", -1);
307 *result = dc_stack->value;
308 return DC_SUCCESS;
311 /* set *result to a dup of the value on the top of the named register stack */
313 * DC_FAIL is returned if the named stack is empty (and *result unchanged),
314 * DC_SUCCESS is returned otherwise
317 dc_register_get DC_DECLARG((regid, result))
318 int regid DC_DECLSEP
319 dc_data *result DC_DECLEND
321 dc_list *r;
323 regid = regmap(regid);
324 r = dc_register[regid];
325 if ( ! r ){
326 fprintf(stderr, "%s: register ", progname);
327 dc_show_id(stderr, regid, " is empty\n");
328 return DC_FAIL;
330 *result = dc_dup(r->value);
331 return DC_SUCCESS;
334 /* set the top of the named register stack to the indicated value */
335 /* If the named stack is empty, craft a stack entry to enter the
336 * value into.
338 void
339 dc_register_set DC_DECLARG((regid, value))
340 int regid DC_DECLSEP
341 dc_data value DC_DECLEND
343 dc_list *r;
345 regid = regmap(regid);
346 r = dc_register[regid];
347 if ( ! r )
348 dc_register[regid] = dc_alloc();
349 else if (r->value.dc_type == DC_NUMBER)
350 dc_free_num(&r->value.v.number);
351 else if (r->value.dc_type == DC_STRING)
352 dc_free_str(&r->value.v.string);
353 else if (r->value.dc_type == DC_UNINITIALIZED)
355 else
356 dc_garbage("", regid);
357 dc_register[regid]->value = value;
360 /* pop from the evaluation stack
362 * DC_FAIL is returned if the stack is empty (and *result unchanged),
363 * DC_SUCCESS is returned otherwise
366 dc_pop DC_DECLARG((result))
367 dc_data *result DC_DECLEND
369 dc_list *r;
371 r = dc_stack;
372 if (!r){
373 Empty_Stack;
374 return DC_FAIL;
376 if (r->value.dc_type!=DC_NUMBER && r->value.dc_type!=DC_STRING)
377 dc_garbage("at top of stack", -1);
378 *result = r->value;
379 dc_stack = r->link;
380 dc_array_free(r->array);
381 free(r);
382 return DC_SUCCESS;
385 /* pop from the named register stack
387 * DC_FAIL is returned if the named stack is empty (and *result unchanged),
388 * DC_SUCCESS is returned otherwise
391 dc_register_pop DC_DECLARG((stackid, result))
392 int stackid DC_DECLSEP
393 dc_data *result DC_DECLEND
395 dc_list *r;
397 stackid = regmap(stackid);
398 r = dc_register[stackid];
399 if (!r){
400 fprintf(stderr, "%s: stack register ", progname);
401 dc_show_id(stderr, stackid, " is empty\n");
402 return DC_FAIL;
404 if (r->value.dc_type!=DC_NUMBER && r->value.dc_type!=DC_STRING)
405 dc_garbage(" stack", stackid);
406 *result = r->value;
407 dc_register[stackid] = r->link;
408 dc_array_free(r->array);
409 free(r);
410 return DC_SUCCESS;
414 /* tell how many entries are currently on the evaluation stack */
416 dc_tell_stackdepth DC_DECLVOID()
418 dc_list *n;
419 int depth=0;
421 for (n=dc_stack; n; n=n->link)
422 ++depth;
423 return depth;
427 /* return the length of the indicated data value;
428 * if discard_p is DC_TOSS, the deallocate the value when done
430 * The definition of a datum's length is deligated to the
431 * appropriate module.
434 dc_tell_length DC_DECLARG((value, discard_p))
435 dc_data value DC_DECLSEP
436 dc_discard discard_p DC_DECLEND
438 int length;
440 if (value.dc_type == DC_NUMBER){
441 length = dc_numlen(value.v.number);
442 if (discard_p == DC_TOSS)
443 dc_free_num(&value.v.number);
444 } else if (value.dc_type == DC_STRING) {
445 length = dc_strlen(value.v.string);
446 if (discard_p == DC_TOSS)
447 dc_free_str(&value.v.string);
448 } else {
449 dc_garbage("in tell_length", -1);
450 /*NOTREACHED*/
451 length = 0; /*just to suppress spurious compiler warnings*/
453 return length;
458 /* print out all of the values on the evaluation stack */
459 void
460 dc_printall DC_DECLARG((obase))
461 int obase DC_DECLEND
463 dc_list *n;
465 for (n=dc_stack; n; n=n->link)
466 dc_print(n->value, obase, DC_WITHNL, DC_KEEP);
472 /* get the current array head for the named array */
473 struct dc_array *
474 dc_get_stacked_array DC_DECLARG((array_id))
475 int array_id DC_DECLEND
477 dc_list *r = dc_register[regmap(array_id)];
478 return r ? r->array : NULL;
481 /* set the current array head for the named array */
482 void
483 dc_set_stacked_array DC_DECLARG((array_id, new_head))
484 int array_id DC_DECLSEP
485 struct dc_array *new_head DC_DECLEND
487 dc_list *r;
489 array_id = regmap(array_id);
490 r = dc_register[array_id];
491 if ( ! r )
492 r = dc_register[array_id] = dc_alloc();
493 r->array = new_head;