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