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: The Free Software Foundation, 19 * Inc.; 675 Mass Ave. Cambridge, MA 02139, USA. 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 implementaion 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 static dc_list *dc_register[DC_REGCOUNT]; 54 55 56 /* allocate a new dc_list item */ 57 static dc_list * 58 dc_alloc DC_DECLVOID() 59 { 60 dc_list *result; 61 62 result = dc_malloc(sizeof *result); 63 result->value.dc_type = DC_UNINITIALIZED; 64 result->array = NULL; 65 result->link = NULL; 66 return result; 67 } 68 69 70 /* check that there are two numbers on top of the stack, 71 * then call op with the popped numbers. Construct a dc_data 72 * value from the dc_num returned by op and push it 73 * on the stack. 74 * If the op call doesn't return DC_SUCCESS, then leave the stack 75 * unmodified. 76 */ 77 void 78 dc_binop DC_DECLARG((op, kscale)) 79 int (*op)DC_PROTO((dc_num, dc_num, int, dc_num *)) DC_DECLSEP 80 int kscale DC_DECLEND 81 { 82 dc_data a; 83 dc_data b; 84 dc_data r; 85 86 if (!dc_stack || !dc_stack->link){ 87 Empty_Stack; 88 return; 89 } 90 if (dc_stack->value.dc_type!=DC_NUMBER 91 || dc_stack->link->value.dc_type!=DC_NUMBER){ 92 fprintf(stderr, "%s: non-numeric value\n", progname); 93 return; 94 } 95 (void)dc_pop(&b); 96 (void)dc_pop(&a); 97 if ((*op)(a.v.number, b.v.number, kscale, &r.v.number) == DC_SUCCESS){ 98 r.dc_type = DC_NUMBER; 99 dc_push(r); 100 dc_free_num(&a.v.number); 101 dc_free_num(&b.v.number); 102 }else{ 103 /* op failed; restore the stack */ 104 dc_push(a); 105 dc_push(b); 106 } 107 } 108 109 /* check that there are two numbers on top of the stack, 110 * then call op with the popped numbers. Construct two dc_data 111 * values from the dc_num's returned by op and push them 112 * on the stack. 113 * If the op call doesn't return DC_SUCCESS, then leave the stack 114 * unmodified. 115 */ 116 void 117 dc_binop2 DC_DECLARG((op, kscale)) 118 int (*op)DC_PROTO((dc_num, dc_num, int, dc_num *, dc_num *)) DC_DECLSEP 119 int kscale DC_DECLEND 120 { 121 dc_data a; 122 dc_data b; 123 dc_data r1; 124 dc_data r2; 125 126 if (!dc_stack || !dc_stack->link){ 127 Empty_Stack; 128 return; 129 } 130 if (dc_stack->value.dc_type!=DC_NUMBER 131 || dc_stack->link->value.dc_type!=DC_NUMBER){ 132 fprintf(stderr, "%s: non-numeric value\n", progname); 133 return; 134 } 135 (void)dc_pop(&b); 136 (void)dc_pop(&a); 137 if ((*op)(a.v.number, b.v.number, kscale, 138 &r1.v.number, &r2.v.number) == DC_SUCCESS){ 139 r1.dc_type = DC_NUMBER; 140 dc_push(r1); 141 r2.dc_type = DC_NUMBER; 142 dc_push(r2); 143 dc_free_num(&a.v.number); 144 dc_free_num(&b.v.number); 145 }else{ 146 /* op failed; restore the stack */ 147 dc_push(a); 148 dc_push(b); 149 } 150 } 151 152 /* check that there are two numbers on top of the stack, 153 * then call dc_compare with the popped numbers. 154 * Return negative, zero, or positive based on the ordering 155 * of the two numbers. 156 */ 157 int 158 dc_cmpop DC_DECLVOID() 159 { 160 int result; 161 dc_data a; 162 dc_data b; 163 164 if (!dc_stack || !dc_stack->link){ 165 Empty_Stack; 166 return 0; 167 } 168 if (dc_stack->value.dc_type!=DC_NUMBER 169 || dc_stack->link->value.dc_type!=DC_NUMBER){ 170 fprintf(stderr, "%s: non-numeric value\n", progname); 171 return 0; 172 } 173 (void)dc_pop(&b); 174 (void)dc_pop(&a); 175 result = dc_compare(b.v.number, a.v.number); 176 dc_free_num(&a.v.number); 177 dc_free_num(&b.v.number); 178 return result; 179 } 180 181 /* check that there are three numbers on top of the stack, 182 * then call op with the popped numbers. Construct a dc_data 183 * value from the dc_num returned by op and push it 184 * on the stack. 185 * If the op call doesn't return DC_SUCCESS, then leave the stack 186 * unmodified. 187 */ 188 void 189 dc_triop DC_DECLARG((op, kscale)) 190 int (*op)DC_PROTO((dc_num, dc_num, dc_num, int, dc_num *)) DC_DECLSEP 191 int kscale DC_DECLEND 192 { 193 dc_data a; 194 dc_data b; 195 dc_data c; 196 dc_data r; 197 198 if (!dc_stack || !dc_stack->link || !dc_stack->link->link){ 199 Empty_Stack; 200 return; 201 } 202 if (dc_stack->value.dc_type!=DC_NUMBER 203 || dc_stack->link->value.dc_type!=DC_NUMBER 204 || dc_stack->link->link->value.dc_type!=DC_NUMBER){ 205 fprintf(stderr, "%s: non-numeric value\n", progname); 206 return; 207 } 208 (void)dc_pop(&c); 209 (void)dc_pop(&b); 210 (void)dc_pop(&a); 211 if ((*op)(a.v.number, b.v.number, c.v.number, 212 kscale, &r.v.number) == DC_SUCCESS){ 213 r.dc_type = DC_NUMBER; 214 dc_push(r); 215 dc_free_num(&a.v.number); 216 dc_free_num(&b.v.number); 217 dc_free_num(&c.v.number); 218 }else{ 219 /* op failed; restore the stack */ 220 dc_push(a); 221 dc_push(b); 222 dc_push(c); 223 } 224 } 225 226 227 /* initialize the register stacks to their initial values */ 228 void 229 dc_register_init DC_DECLVOID() 230 { 231 int i; 232 233 for (i=0; i<DC_REGCOUNT; ++i) 234 dc_register[i] = NULL; 235 } 236 237 /* clear the evaluation stack */ 238 void 239 dc_clear_stack DC_DECLVOID() 240 { 241 dc_list *n; 242 dc_list *t; 243 244 for (n=dc_stack; n; n=t){ 245 t = n->link; 246 if (n->value.dc_type == DC_NUMBER) 247 dc_free_num(&n->value.v.number); 248 else if (n->value.dc_type == DC_STRING) 249 dc_free_str(&n->value.v.string); 250 else 251 dc_garbage("in stack", -1); 252 dc_array_free(n->array); 253 free(n); 254 } 255 dc_stack = NULL; 256 } 257 258 /* push a value onto the evaluation stack */ 259 void 260 dc_push DC_DECLARG((value)) 261 dc_data value DC_DECLEND 262 { 263 dc_list *n = dc_alloc(); 264 265 if (value.dc_type!=DC_NUMBER && value.dc_type!=DC_STRING) 266 dc_garbage("in data being pushed", -1); 267 n->value = value; 268 n->link = dc_stack; 269 dc_stack = n; 270 } 271 272 /* push a value onto the named register stack */ 273 void 274 dc_register_push DC_DECLARG((stackid, value)) 275 int stackid DC_DECLSEP 276 dc_data value DC_DECLEND 277 { 278 dc_list *n = dc_alloc(); 279 280 stackid = regmap(stackid); 281 n->value = value; 282 n->link = dc_register[stackid]; 283 dc_register[stackid] = n; 284 } 285 286 /* set *result to the value on the top of the evaluation stack */ 287 /* The caller is responsible for duplicating the value if it 288 * is to be maintained as anything more than a transient identity. 289 * 290 * DC_FAIL is returned if the stack is empty (and *result unchanged), 291 * DC_SUCCESS is returned otherwise 292 */ 293 int 294 dc_top_of_stack DC_DECLARG((result)) 295 dc_data *result DC_DECLEND 296 { 297 if (!dc_stack){ 298 Empty_Stack; 299 return DC_FAIL; 300 } 301 if (dc_stack->value.dc_type!=DC_NUMBER 302 && dc_stack->value.dc_type!=DC_STRING) 303 dc_garbage("at top of stack", -1); 304 *result = dc_stack->value; 305 return DC_SUCCESS; 306 } 307 308 /* set *result to a dup of the value on the top of the named register stack */ 309 /* 310 * DC_FAIL is returned if the named stack is empty (and *result unchanged), 311 * DC_SUCCESS is returned otherwise 312 */ 313 int 314 dc_register_get DC_DECLARG((regid, result)) 315 int regid DC_DECLSEP 316 dc_data *result DC_DECLEND 317 { 318 dc_list *r; 319 320 regid = regmap(regid); 321 r = dc_register[regid]; 322 if ( ! r ){ 323 fprintf(stderr, "%s: register ", progname); 324 dc_show_id(stderr, regid, " is empty\n"); 325 return DC_FAIL; 326 } 327 *result = dc_dup(r->value); 328 return DC_SUCCESS; 329 } 330 331 /* set the top of the named register stack to the indicated value */ 332 /* If the named stack is empty, craft a stack entry to enter the 333 * value into. 334 */ 335 void 336 dc_register_set DC_DECLARG((regid, value)) 337 int regid DC_DECLSEP 338 dc_data value DC_DECLEND 339 { 340 dc_list *r; 341 342 regid = regmap(regid); 343 r = dc_register[regid]; 344 if ( ! r ) 345 dc_register[regid] = dc_alloc(); 346 else if (r->value.dc_type == DC_NUMBER) 347 dc_free_num(&r->value.v.number); 348 else if (r->value.dc_type == DC_STRING) 349 dc_free_str(&r->value.v.string); 350 else 351 dc_garbage("", regid); 352 dc_register[regid]->value = value; 353 } 354 355 /* pop from the evaluation stack 356 * 357 * DC_FAIL is returned if the stack is empty (and *result unchanged), 358 * DC_SUCCESS is returned otherwise 359 */ 360 int 361 dc_pop DC_DECLARG((result)) 362 dc_data *result DC_DECLEND 363 { 364 dc_list *r; 365 366 r = dc_stack; 367 if (!r){ 368 Empty_Stack; 369 return DC_FAIL; 370 } 371 if (r->value.dc_type!=DC_NUMBER && r->value.dc_type!=DC_STRING) 372 dc_garbage("at top of stack", -1); 373 *result = r->value; 374 dc_stack = r->link; 375 dc_array_free(r->array); 376 free(r); 377 return DC_SUCCESS; 378 } 379 380 /* pop from the named register stack 381 * 382 * DC_FAIL is returned if the named stack is empty (and *result unchanged), 383 * DC_SUCCESS is returned otherwise 384 */ 385 int 386 dc_register_pop DC_DECLARG((stackid, result)) 387 int stackid DC_DECLSEP 388 dc_data *result DC_DECLEND 389 { 390 dc_list *r; 391 392 stackid = regmap(stackid); 393 r = dc_register[stackid]; 394 if (!r){ 395 fprintf(stderr, "%s: stack register ", progname); 396 dc_show_id(stderr, stackid, " is empty\n"); 397 return DC_FAIL; 398 } 399 if (r->value.dc_type!=DC_NUMBER && r->value.dc_type!=DC_STRING) 400 dc_garbage(" stack", stackid); 401 *result = r->value; 402 dc_register[stackid] = r->link; 403 dc_array_free(r->array); 404 free(r); 405 return DC_SUCCESS; 406 } 407 408 409 /* tell how many entries are currently on the evaluation stack */ 410 int 411 dc_tell_stackdepth DC_DECLVOID() 412 { 413 dc_list *n; 414 int depth=0; 415 416 for (n=dc_stack; n; n=n->link) 417 ++depth; 418 return depth; 419 } 420 421 422 /* return the length of the indicated data value; 423 * if discard_p is DC_TOSS, the deallocate the value when done 424 * 425 * The definition of a datum's length is deligated to the 426 * appropriate module. 427 */ 428 int 429 dc_tell_length DC_DECLARG((value, discard_p)) 430 dc_data value DC_DECLSEP 431 dc_discard discard_p DC_DECLEND 432 { 433 int length; 434 435 if (value.dc_type == DC_NUMBER){ 436 length = dc_numlen(value.v.number); 437 if (discard_p == DC_TOSS) 438 dc_free_num(&value.v.number); 439 } else if (value.dc_type == DC_STRING) { 440 length = dc_strlen(value.v.string); 441 if (discard_p == DC_TOSS) 442 dc_free_str(&value.v.string); 443 } else { 444 dc_garbage("in tell_length", -1); 445 /*NOTREACHED*/ 446 length = 0; /*just to suppress spurious compiler warnings*/ 447 } 448 return length; 449 } 450 451 452 453 /* print out all of the values on the evaluation stack */ 454 void 455 dc_printall DC_DECLARG((obase)) 456 int obase DC_DECLEND 457 { 458 dc_list *n; 459 460 for (n=dc_stack; n; n=n->link) 461 dc_print(n->value, obase, DC_WITHNL, DC_KEEP); 462 } 463 464 465 466 467 /* get the current array head for the named array */ 468 struct dc_array * 469 dc_get_stacked_array DC_DECLARG((array_id)) 470 int array_id DC_DECLEND 471 { 472 dc_list *r = dc_register[regmap(array_id)]; 473 return r ? r->array : NULL; 474 } 475 476 /* set the current array head for the named array */ 477 void 478 dc_set_stacked_array DC_DECLARG((array_id, new_head)) 479 int array_id DC_DECLSEP 480 struct dc_array *new_head DC_DECLEND 481 { 482 dc_list *r; 483 484 array_id = regmap(array_id); 485 r = dc_register[array_id]; 486 if ( ! r ) 487 r = dc_register[array_id] = dc_alloc(); 488 r->array = new_head; 489 } |