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:
19 *
20 *    The Free Software Foundation, Inc.
21 *    59 Temple Place, Suite 330
22 *    Boston, MA 02111 USA
23 */
24
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.
28 */
29
30#include "config.h"
31
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"
39
40/* an oft-used error message: */
41#define Empty_Stack	fprintf(stderr, "%s: stack empty\n", progname)
42
43
44/* simple linked-list implementaion suffices: */
45struct dc_list {
46	dc_data value;
47	struct dc_array *array;	/* opaque */
48	struct dc_list *link;
49};
50typedef struct dc_list dc_list;
51
52/* the anonymous evaluation stack */
53static dc_list *dc_stack=NULL;
54
55/* the named register stacks */
56static dc_list *dc_register[DC_REGCOUNT];
57
58
59/* allocate a new dc_list item */
60static dc_list *
61dc_alloc DC_DECLVOID()
62{
63	dc_list *result;
64
65	result = dc_malloc(sizeof *result);
66	result->value.dc_type = DC_UNINITIALIZED;
67	result->array = NULL;
68	result->link = NULL;
69	return result;
70}
71
72
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.
79 */
80void
81dc_binop DC_DECLARG((op, kscale))
82	int (*op)DC_PROTO((dc_num, dc_num, int, dc_num *)) DC_DECLSEP
83	int kscale DC_DECLEND
84{
85	dc_data a;
86	dc_data b;
87	dc_data r;
88
89	if (!dc_stack || !dc_stack->link){
90		Empty_Stack;
91		return;
92	}
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;
97	}
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);
109	}
110}
111
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.
118 */
119void
120dc_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
123{
124	dc_data a;
125	dc_data b;
126	dc_data r1;
127	dc_data r2;
128
129	if (!dc_stack || !dc_stack->link){
130		Empty_Stack;
131		return;
132	}
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;
137	}
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);
152	}
153}
154
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.
159 */
160int
161dc_cmpop DC_DECLVOID()
162{
163	int result;
164	dc_data a;
165	dc_data b;
166
167	if (!dc_stack || !dc_stack->link){
168		Empty_Stack;
169		return 0;
170	}
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;
175	}
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;
182}
183
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.
190 */
191void
192dc_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
195{
196	dc_data a;
197	dc_data b;
198	dc_data c;
199	dc_data r;
200
201	if (!dc_stack || !dc_stack->link || !dc_stack->link->link){
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 */
231void
232dc_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 */
241void
242dc_clear_stack DC_DECLVOID()
243{
244	dc_list *n;
245	dc_list *t;
246
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);
257	}
258	dc_stack = NULL;
259}
260
261/* push a value onto the evaluation stack */
262void
263dc_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 */
276void
277dc_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 */
296int
297dc_top_of_stack DC_DECLARG((result))
298	dc_data *result DC_DECLEND
299{
300	if (!dc_stack){
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/*
313 * DC_FAIL is returned if the named stack is empty (and *result unchanged),
314 * DC_SUCCESS is returned otherwise
315 */
316int
317dc_register_get DC_DECLARG((regid, result))
318	int regid DC_DECLSEP
319	dc_data *result DC_DECLEND
320{
321	dc_list *r;
322
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;
329	}
330	*result = dc_dup(r->value);
331	return DC_SUCCESS;
332}
333
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.
337 */
338void
339dc_register_set DC_DECLARG((regid, value))
340	int regid DC_DECLSEP
341	dc_data value DC_DECLEND
342{
343	dc_list *r;
344
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)
354		;
355	else
356		dc_garbage("", regid);
357	dc_register[regid]->value = value;
358}
359
360/* pop from the evaluation stack
361 *
362 * DC_FAIL is returned if the stack is empty (and *result unchanged),
363 * DC_SUCCESS is returned otherwise
364 */
365int
366dc_pop DC_DECLARG((result))
367	dc_data *result DC_DECLEND
368{
369	dc_list *r;
370
371	r = dc_stack;
372	if (!r){
373		Empty_Stack;
374		return DC_FAIL;
375	}
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;
383}
384
385/* pop from the named register stack
386 *
387 * DC_FAIL is returned if the named stack is empty (and *result unchanged),
388 * DC_SUCCESS is returned otherwise
389 */
390int
391dc_register_pop DC_DECLARG((stackid, result))
392	int stackid DC_DECLSEP
393	dc_data *result DC_DECLEND
394{
395	dc_list *r;
396
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;
403	}
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;
411}
412
413
414/* tell how many entries are currently on the evaluation stack */
415int
416dc_tell_stackdepth DC_DECLVOID()
417{
418	dc_list *n;
419	int depth=0;
420
421	for (n=dc_stack; n; n=n->link)
422		++depth;
423	return depth;
424}
425
426
427/* return the length of the indicated data value;
428 * if discard_p is DC_TOSS, the deallocate the value when done
429 *
430 * The definition of a datum's length is deligated to the
431 * appropriate module.
432 */
433int
434dc_tell_length DC_DECLARG((value, discard_p))
435	dc_data value DC_DECLSEP
436	dc_discard discard_p DC_DECLEND
437{
438	int length;
439
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*/
452	}
453	return length;
454}
455
456
457
458/* print out all of the values on the evaluation stack */
459void
460dc_printall DC_DECLARG((obase))
461	int obase DC_DECLEND
462{
463	dc_list *n;
464
465	for (n=dc_stack; n; n=n->link)
466		dc_print(n->value, obase, DC_WITHNL, DC_KEEP);
467}
468
469
470
471
472/* get the current array head for the named array */
473struct dc_array *
474dc_get_stacked_array DC_DECLARG((array_id))
475	int array_id DC_DECLEND
476{
477	dc_list *r = dc_register[regmap(array_id)];
478	return r ? r->array : NULL;
479}
480
481/* set the current array head for the named array */
482void
483dc_set_stacked_array DC_DECLARG((array_id, new_head))
484	int array_id DC_DECLSEP
485	struct dc_array *new_head DC_DECLEND
486{
487	dc_list *r;
488
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;
494}
495