1 /*
2 * implement stack functions for dc
3 *
4 * Copyright (C) 1994, 1997, 1998, 2000, 2005, 2006, 2008, 2012, 2016
5 * Free Software Foundation, Inc.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
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 implementation 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 typedef dc_list *dc_listp;
54 static dc_listp dc_register[DC_REGCOUNT];
55
56
57 /* allocate a new dc_list item */
58 static dc_list *
DC_DECLVOID()59 dc_alloc DC_DECLVOID()
60 {
61 dc_list *result;
62
63 result = dc_malloc(sizeof *result);
64 result->value.dc_type = DC_UNINITIALIZED;
65 result->array = NULL;
66 result->link = NULL;
67 return result;
68 }
69
70
71 /* check that there are two numbers on top of the stack,
72 * then call op with the popped numbers. Construct a dc_data
73 * value from the dc_num returned by op and push it
74 * on the stack.
75 * If the op call doesn't return DC_SUCCESS, then leave the stack
76 * unmodified.
77 */
78 void
dc_binop(op,kscale)79 dc_binop DC_DECLARG((op, kscale))
80 int (*op)DC_PROTO((dc_num, dc_num, int, dc_num *)) DC_DECLSEP
81 int kscale DC_DECLEND
82 {
83 dc_data a;
84 dc_data b;
85 dc_data r;
86
87 if (dc_stack == NULL || dc_stack->link == NULL){
88 Empty_Stack;
89 return;
90 }
91 if (dc_stack->value.dc_type!=DC_NUMBER
92 || dc_stack->link->value.dc_type!=DC_NUMBER){
93 fprintf(stderr, "%s: non-numeric value\n", progname);
94 return;
95 }
96 (void)dc_pop(&b);
97 (void)dc_pop(&a);
98 if ((*op)(a.v.number, b.v.number, kscale, &r.v.number) == DC_SUCCESS){
99 r.dc_type = DC_NUMBER;
100 dc_push(r);
101 dc_free_num(&a.v.number);
102 dc_free_num(&b.v.number);
103 }else{
104 /* op failed; restore the stack */
105 dc_push(a);
106 dc_push(b);
107 }
108 }
109
110 /* check that there are two numbers on top of the stack,
111 * then call op with the popped numbers. Construct two dc_data
112 * values from the dc_num's returned by op and push them
113 * on the stack.
114 * If the op call doesn't return DC_SUCCESS, then leave the stack
115 * unmodified.
116 */
117 void
dc_binop2(op,kscale)118 dc_binop2 DC_DECLARG((op, kscale))
119 int (*op)DC_PROTO((dc_num, dc_num, int, dc_num *, dc_num *)) DC_DECLSEP
120 int kscale DC_DECLEND
121 {
122 dc_data a;
123 dc_data b;
124 dc_data r1;
125 dc_data r2;
126
127 if (dc_stack == NULL || dc_stack->link == NULL){
128 Empty_Stack;
129 return;
130 }
131 if (dc_stack->value.dc_type!=DC_NUMBER
132 || dc_stack->link->value.dc_type!=DC_NUMBER){
133 fprintf(stderr, "%s: non-numeric value\n", progname);
134 return;
135 }
136 (void)dc_pop(&b);
137 (void)dc_pop(&a);
138 if ((*op)(a.v.number, b.v.number, kscale,
139 &r1.v.number, &r2.v.number) == DC_SUCCESS){
140 r1.dc_type = DC_NUMBER;
141 dc_push(r1);
142 r2.dc_type = DC_NUMBER;
143 dc_push(r2);
144 dc_free_num(&a.v.number);
145 dc_free_num(&b.v.number);
146 }else{
147 /* op failed; restore the stack */
148 dc_push(a);
149 dc_push(b);
150 }
151 }
152
153 /* check that there are two numbers on top of the stack,
154 * then call dc_compare with the popped numbers.
155 * Return negative, zero, or positive based on the ordering
156 * of the two numbers.
157 */
158 int
DC_DECLVOID()159 dc_cmpop DC_DECLVOID()
160 {
161 int result;
162 dc_data a;
163 dc_data b;
164
165 if (dc_stack == NULL || dc_stack->link == NULL){
166 Empty_Stack;
167 return 0;
168 }
169 if (dc_stack->value.dc_type!=DC_NUMBER
170 || dc_stack->link->value.dc_type!=DC_NUMBER){
171 fprintf(stderr, "%s: non-numeric value\n", progname);
172 return 0;
173 }
174 (void)dc_pop(&b);
175 (void)dc_pop(&a);
176 result = dc_compare(b.v.number, a.v.number);
177 dc_free_num(&a.v.number);
178 dc_free_num(&b.v.number);
179 return result;
180 }
181
182 /* check that there are three numbers on top of the stack,
183 * then call op with the popped numbers. Construct a dc_data
184 * value from the dc_num returned by op and push it
185 * on the stack.
186 * If the op call doesn't return DC_SUCCESS, then leave the stack
187 * unmodified.
188 */
189 void
dc_triop(op,kscale)190 dc_triop DC_DECLARG((op, kscale))
191 int (*op)DC_PROTO((dc_num, dc_num, dc_num, int, dc_num *)) DC_DECLSEP
192 int kscale DC_DECLEND
193 {
194 dc_data a;
195 dc_data b;
196 dc_data c;
197 dc_data r;
198
199 if (dc_stack == NULL
200 || dc_stack->link == NULL
201 || dc_stack->link->link == NULL){
202 Empty_Stack;
203 return;
204 }
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;
210 }
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);
226 }
227 }
228
229
230 /* initialize the register stacks to their initial values */
231 void
DC_DECLVOID()232 dc_register_init DC_DECLVOID()
233 {
234 int i;
235
236 for (i=0; i<DC_REGCOUNT; ++i)
237 dc_register[i] = NULL;
238 }
239
240 /* clear the evaluation stack */
241 void
DC_DECLVOID()242 dc_clear_stack DC_DECLVOID()
243 {
244 dc_list *n;
245 dc_list *t;
246
247 for (n=dc_stack; n!=NULL; 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);
257 }
258 dc_stack = NULL;
259 }
260
261 /* push a value onto the evaluation stack */
262 void
dc_push(value)263 dc_push DC_DECLARG((value))
264 dc_data value DC_DECLEND
265 {
266 dc_list *n = dc_alloc();
267
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;
273 }
274
275 /* push a value onto the named register stack */
276 void
dc_register_push(stackid,value)277 dc_register_push DC_DECLARG((stackid, value))
278 int stackid DC_DECLSEP
279 dc_data value DC_DECLEND
280 {
281 dc_list *n = dc_alloc();
282
283 stackid = regmap(stackid);
284 n->value = value;
285 n->link = dc_register[stackid];
286 dc_register[stackid] = n;
287 }
288
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.
292 *
293 * DC_FAIL is returned if the stack is empty (and *result unchanged),
294 * DC_SUCCESS is returned otherwise
295 */
296 int
dc_top_of_stack(result)297 dc_top_of_stack DC_DECLARG((result))
298 dc_data *result DC_DECLEND
299 {
300 if (dc_stack == NULL){
301 Empty_Stack;
302 return DC_FAIL;
303 }
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;
309 }
310
311 /* set *result to a dup of the value on the top of the named register stack,
312 * or 0 (zero) if the stack is empty */
313 /*
314 * DC_FAIL is returned if an internal bug is detected
315 * DC_SUCCESS is returned otherwise
316 */
317 int
dc_register_get(regid,result)318 dc_register_get DC_DECLARG((regid, result))
319 int regid DC_DECLSEP
320 dc_data *result DC_DECLEND
321 {
322 dc_list *r;
323
324 regid = regmap(regid);
325 r = dc_register[regid];
326 if (r==NULL){
327 *result = dc_int2data(0);
328 }else if (r->value.dc_type==DC_UNINITIALIZED){
329 fprintf(stderr, "%s: BUG: register ", progname);
330 dc_show_id(stderr, regid, " exists but is uninitialized?\n");
331 return DC_FAIL;
332 }else{
333 *result = dc_dup(r->value);
334 }
335 return DC_SUCCESS;
336 }
337
338 /* set the top of the named register stack to the indicated value */
339 /* If the named stack is empty, craft a stack entry to enter the
340 * value into.
341 */
342 void
dc_register_set(regid,value)343 dc_register_set DC_DECLARG((regid, value))
344 int regid DC_DECLSEP
345 dc_data value DC_DECLEND
346 {
347 dc_list *r;
348
349 regid = regmap(regid);
350 r = dc_register[regid];
351 if (r == NULL)
352 dc_register[regid] = dc_alloc();
353 else if (r->value.dc_type == DC_NUMBER)
354 dc_free_num(&r->value.v.number);
355 else if (r->value.dc_type == DC_STRING)
356 dc_free_str(&r->value.v.string);
357 else if (r->value.dc_type == DC_UNINITIALIZED)
358 ;
359 else
360 dc_garbage("", regid);
361 dc_register[regid]->value = value;
362 }
363
364 /* pop from the evaluation stack
365 *
366 * DC_FAIL is returned if the stack is empty (and *result unchanged),
367 * DC_SUCCESS is returned otherwise
368 */
369 int
dc_pop(result)370 dc_pop DC_DECLARG((result))
371 dc_data *result DC_DECLEND
372 {
373 dc_list *r;
374
375 r = dc_stack;
376 if (r==NULL || r->value.dc_type==DC_UNINITIALIZED){
377 Empty_Stack;
378 return DC_FAIL;
379 }
380 if (r->value.dc_type!=DC_NUMBER && r->value.dc_type!=DC_STRING)
381 dc_garbage("at top of stack", -1);
382 *result = r->value;
383 dc_stack = r->link;
384 dc_array_free(r->array);
385 free(r);
386 return DC_SUCCESS;
387 }
388
389 /* pop from the named register stack
390 *
391 * DC_FAIL is returned if the named stack is empty (and *result unchanged),
392 * DC_SUCCESS is returned otherwise
393 */
394 int
dc_register_pop(stackid,result)395 dc_register_pop DC_DECLARG((stackid, result))
396 int stackid DC_DECLSEP
397 dc_data *result DC_DECLEND
398 {
399 dc_list *r;
400
401 stackid = regmap(stackid);
402 r = dc_register[stackid];
403 if (r==NULL || r->value.dc_type==DC_UNINITIALIZED){
404 fprintf(stderr, "%s: stack register ", progname);
405 dc_show_id(stderr, stackid, " is empty\n");
406 return DC_FAIL;
407 }
408 if (r->value.dc_type!=DC_NUMBER && r->value.dc_type!=DC_STRING)
409 dc_garbage(" stack", stackid);
410 *result = r->value;
411 dc_register[stackid] = r->link;
412 dc_array_free(r->array);
413 free(r);
414 return DC_SUCCESS;
415 }
416
417
418 /* cyclically rotate the "n" topmost elements of the stack;
419 * negative "n" rotates forward (topomost element becomes n-th deep)
420 * positive "n" rotates backward (topmost element becomes 2nd deep)
421 *
422 * If stack depth is less than "n", whole stack is rotated
423 * (without raising an error).
424 */
425 void
dc_stack_rotate(int n)426 dc_stack_rotate(int n)
427 {
428 dc_list *p; /* becomes bottom of sub-stack */
429 dc_list *r; /* predecessor of "p" */
430 int absn = n<0 ? -n : n;
431
432 /* always do nothing for empty stack or degenerate rotation depth */
433 if (!dc_stack || absn < 2)
434 return;
435 /* find bottom of rotation sub-stack */
436 r = NULL;
437 for (p=dc_stack; p->link && --absn>0; p=p->link)
438 r = p;
439 /* if stack has only one element, treat rotation as no-op */
440 if (!r)
441 return;
442 /* do the rotation, in appropriate direction */
443 if (n > 0) {
444 r->link = p->link;
445 p->link = dc_stack;
446 dc_stack = p;
447 } else {
448 dc_list *new_tos = dc_stack->link;
449 dc_stack->link = p->link;
450 p->link = dc_stack;
451 dc_stack = new_tos;
452 }
453 }
454
455
456 /* tell how many entries are currently on the evaluation stack */
457 int
DC_DECLVOID()458 dc_tell_stackdepth DC_DECLVOID()
459 {
460 dc_list *n;
461 int depth=0;
462
463 for (n=dc_stack; n!=NULL; n=n->link)
464 ++depth;
465 return depth;
466 }
467
468
469 /* return the length of the indicated data value;
470 * if discard_p is DC_TOSS, the deallocate the value when done
471 *
472 * The definition of a datum's length is deligated to the
473 * appropriate module.
474 */
475 int
dc_tell_length(value,discard_p)476 dc_tell_length DC_DECLARG((value, discard_p))
477 dc_data value DC_DECLSEP
478 dc_discard discard_p DC_DECLEND
479 {
480 int length;
481
482 if (value.dc_type == DC_NUMBER){
483 length = dc_numlen(value.v.number);
484 if (discard_p == DC_TOSS)
485 dc_free_num(&value.v.number);
486 } else if (value.dc_type == DC_STRING) {
487 length = (int) dc_strlen(value.v.string);
488 if (discard_p == DC_TOSS)
489 dc_free_str(&value.v.string);
490 } else {
491 dc_garbage("in tell_length", -1);
492 /*NOTREACHED*/
493 length = 0; /*just to suppress spurious compiler warnings*/
494 }
495 return length;
496 }
497
498
499
500 /* print out all of the values on the evaluation stack */
501 void
dc_printall(obase)502 dc_printall DC_DECLARG((obase))
503 int obase DC_DECLEND
504 {
505 dc_list *n;
506
507 for (n=dc_stack; n!=NULL; n=n->link)
508 dc_print(n->value, obase, DC_WITHNL, DC_KEEP);
509 }
510
511
512
513
514 /* get the current array head for the named array */
515 struct dc_array *
516 dc_get_stacked_array DC_DECLARG((array_id))
517 int array_id DC_DECLEND
518 {
519 dc_list *r = dc_register[regmap(array_id)];
520 return r == NULL ? NULL : r->array;
521 }
522
523 /* set the current array head for the named array */
524 void
dc_set_stacked_array(array_id,new_head)525 dc_set_stacked_array DC_DECLARG((array_id, new_head))
526 int array_id DC_DECLSEP
527 struct dc_array *new_head DC_DECLEND
528 {
529 dc_list *r;
530
531 array_id = regmap(array_id);
532 r = dc_register[array_id];
533 if (r == NULL)
534 r = dc_register[array_id] = dc_alloc();
535 r->array = new_head;
536 }
537
538
539 /*
540 * Local Variables:
541 * mode: C
542 * tab-width: 4
543 * End:
544 * vi: set ts=4 :
545 */
546