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