home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / bc-1.03-base.tgz / bc-1.03-base.tar / fsf / bc / dc-stack.c < prev    next >
C/C++ Source or Header  |  1994-08-08  |  8KB  |  370 lines

  1. /* 
  2.  * implement stack functions for dc
  3.  *
  4.  * Copyright (C) 1994 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_list *link;
  45. };
  46. typedef struct dc_list dc_list;
  47.  
  48. /* the anonymous evaluation stack */
  49. static dc_list *dc_stack=NULL;
  50.  
  51. /* the named register stacks */
  52. static dc_list *dc_register[DC_REGCOUNT];
  53.  
  54.  
  55. /* allocate a new dc_list item */
  56. static dc_list *
  57. dc_alloc DC_DECLVOID()
  58. {
  59.     dc_list *result;
  60.  
  61.     result = dc_malloc(sizeof *result);
  62.     result->value.dc_type = DC_UNINITIALIZED;
  63.     result->link = NULL;
  64.     return result;
  65. }
  66.  
  67.  
  68. /* check that there are two numbers on top of the stack,
  69.  * then call op with the popped numbers.  Construct a dc_data
  70.  * value from the dc_num returned by op and push it
  71.  * on the stack.
  72.  * If the op call doesn't return DC_SUCCESS, then leave the stack
  73.  * unmodified.
  74.  */
  75. void
  76. dc_binop DC_DECLARG((op, kscale))
  77.     int (*op)DC_PROTO((dc_num, dc_num, int, dc_num *)) DC_DECLSEP
  78.     int kscale DC_DECLEND
  79. {
  80.     dc_data a;
  81.     dc_data b;
  82.     dc_data r;
  83.  
  84.     if (!dc_stack || !dc_stack->link){
  85.         Empty_Stack;
  86.         return;
  87.     }
  88.     if (dc_stack->value.dc_type!=DC_NUMBER
  89.             || dc_stack->link->value.dc_type!=DC_NUMBER){
  90.         fprintf(stderr, "%s: non-numeric value\n", progname);
  91.         return;
  92.     }
  93.     (void)dc_pop(&b);
  94.     (void)dc_pop(&a);
  95.     if ((*op)(a.v.number, b.v.number, kscale, &r.v.number) == DC_SUCCESS){
  96.         r.dc_type = DC_NUMBER;
  97.         dc_push(r);
  98.         dc_free_num(&a.v.number);
  99.         dc_free_num(&b.v.number);
  100.     }else{
  101.         /* op failed; restore the stack */
  102.         dc_push(a);
  103.         dc_push(b);
  104.     }
  105. }
  106.  
  107. /* check that there are two numbers on top of the stack,
  108.  * then call dc_compare with the popped numbers.
  109.  * Return negative, zero, or positive based on the ordering
  110.  * of the two numbers.
  111.  */
  112. int
  113. dc_cmpop DC_DECLVOID()
  114. {
  115.     int result;
  116.     dc_data a;
  117.     dc_data b;
  118.  
  119.     if (!dc_stack || !dc_stack->link){
  120.         Empty_Stack;
  121.         return 0;
  122.     }
  123.     if (dc_stack->value.dc_type!=DC_NUMBER
  124.             || dc_stack->link->value.dc_type!=DC_NUMBER){
  125.         fprintf(stderr, "%s: non-numeric value\n", progname);
  126.         return 0;
  127.     }
  128.     (void)dc_pop(&b);
  129.     (void)dc_pop(&a);
  130.     result = dc_compare(b.v.number, a.v.number);
  131.     dc_free_num(&a.v.number);
  132.     dc_free_num(&b.v.number);
  133.     return result;
  134. }
  135.  
  136.  
  137. /* initialize the register stacks to their initial values */
  138. void
  139. dc_register_init DC_DECLVOID()
  140. {
  141.     int i;
  142.  
  143.     for (i=0; i<DC_REGCOUNT; ++i)
  144.         dc_register[i] = NULL;
  145. }
  146.  
  147. /* clear the evaluation stack */
  148. void
  149. dc_clear_stack DC_DECLVOID()
  150. {
  151.     dc_list *n;
  152.     dc_list *t;
  153.  
  154.     for (n=dc_stack; n; n=t){
  155.         t = n->link;
  156.         if (n->value.dc_type == DC_NUMBER)
  157.             dc_free_num(&n->value.v.number);
  158.         else if (n->value.dc_type == DC_STRING)
  159.             dc_free_str(&n->value.v.string);
  160.         else
  161.             dc_garbage("in stack", -1);
  162.         free(n);
  163.     }
  164.     dc_stack = NULL;
  165. }
  166.  
  167. /* push a value onto the evaluation stack */
  168. void
  169. dc_push DC_DECLARG((value))
  170.     dc_data value DC_DECLEND
  171. {
  172.     dc_list *n = dc_alloc();
  173.  
  174.     if (value.dc_type!=DC_NUMBER && value.dc_type!=DC_STRING)
  175.         dc_garbage("in data being pushed", -1);
  176.     n->value = value;
  177.     n->link = dc_stack;
  178.     dc_stack = n;
  179. }
  180.  
  181. /* push a value onto the named register stack */
  182. void
  183. dc_register_push DC_DECLARG((stackid, value))
  184.     int stackid DC_DECLSEP
  185.     dc_data value DC_DECLEND
  186. {
  187.     dc_list *n = dc_alloc();
  188.  
  189.     stackid = regmap(stackid);
  190.     n->value = value;
  191.     n->link = dc_register[stackid];
  192.     dc_register[stackid] = n;
  193. }
  194.  
  195. /* set *result to the value on the top of the evaluation stack */
  196. /* The caller is responsible for duplicating the value if it
  197.  * is to be maintained as anything more than a transient identity.
  198.  *
  199.  * DC_FAIL is returned if the stack is empty (and *result unchanged),
  200.  * DC_SUCCESS is returned otherwise
  201.  */
  202. int
  203. dc_top_of_stack DC_DECLARG((result))
  204.     dc_data *result DC_DECLEND
  205. {
  206.     if (!dc_stack){
  207.         Empty_Stack;
  208.         return DC_FAIL;
  209.     }
  210.     if (dc_stack->value.dc_type!=DC_NUMBER
  211.             && dc_stack->value.dc_type!=DC_STRING)
  212.         dc_garbage("at top of stack", -1);
  213.     *result = dc_stack->value;
  214.     return DC_SUCCESS;
  215. }
  216.  
  217. /* set *result to a dup of the value on the top of the named register stack */
  218. /*
  219.  * DC_FAIL is returned if the named stack is empty (and *result unchanged),
  220.  * DC_SUCCESS is returned otherwise
  221.  */
  222. int
  223. dc_register_get DC_DECLARG((regid, result))
  224.     int regid DC_DECLSEP
  225.     dc_data *result DC_DECLEND
  226. {
  227.     dc_list *r;
  228.  
  229.     regid = regmap(regid);
  230.     r = dc_register[regid];
  231.     if ( ! r ){
  232.         fprintf(stderr, "%s: register ", progname);
  233.         dc_show_id(stderr, regid, " is empty\n");
  234.         return DC_FAIL;
  235.     }
  236.     *result = dc_dup(r->value);
  237.     return DC_SUCCESS;
  238. }
  239.  
  240. /* set the top of the named register stack to the indicated value */
  241. /* If the named stack is empty, craft a stack entry to enter the
  242.  * value into.
  243.  */
  244. void
  245. dc_register_set DC_DECLARG((regid, value))
  246.     int regid DC_DECLSEP
  247.     dc_data value DC_DECLEND
  248. {
  249.     dc_list *r;
  250.  
  251.     regid = regmap(regid);
  252.     r = dc_register[regid];
  253.     if ( ! r )
  254.         dc_register[regid] = dc_alloc();
  255.     else if (r->value.dc_type == DC_NUMBER)
  256.         dc_free_num(&r->value.v.number);
  257.     else if (r->value.dc_type == DC_STRING)
  258.         dc_free_str(&r->value.v.string);
  259.     else
  260.         dc_garbage("", regid);
  261.     dc_register[regid]->value = value;
  262. }
  263.  
  264. /* pop from the evaluation stack
  265.  *
  266.  * DC_FAIL is returned if the stack is empty (and *result unchanged),
  267.  * DC_SUCCESS is returned otherwise
  268.  */
  269. int
  270. dc_pop DC_DECLARG((result))
  271.     dc_data *result DC_DECLEND
  272. {
  273.     dc_list *r;
  274.  
  275.     r = dc_stack;
  276.     if (!r){
  277.         Empty_Stack;
  278.         return DC_FAIL;
  279.     }
  280.     if (r->value.dc_type!=DC_NUMBER && r->value.dc_type!=DC_STRING)
  281.         dc_garbage("at top of stack", -1);
  282.     *result = r->value;
  283.     dc_stack = r->link;
  284.     free(r);
  285.     return DC_SUCCESS;
  286. }
  287.  
  288. /* pop from the named register stack
  289.  *
  290.  * DC_FAIL is returned if the named stack is empty (and *result unchanged),
  291.  * DC_SUCCESS is returned otherwise
  292.  */
  293. int
  294. dc_register_pop DC_DECLARG((stackid, result))
  295.     int stackid DC_DECLSEP
  296.     dc_data *result DC_DECLEND
  297. {
  298.     dc_list *r;
  299.  
  300.     stackid = regmap(stackid);
  301.     r = dc_register[stackid];
  302.     if (!r){
  303.         fprintf(stderr, "%s: stack register ", progname);
  304.         dc_show_id(stderr, stackid, " is empty\n");
  305.         return DC_FAIL;
  306.     }
  307.     if (r->value.dc_type!=DC_NUMBER && r->value.dc_type!=DC_STRING)
  308.         dc_garbage(" stack", stackid);
  309.     *result = r->value;
  310.     dc_register[stackid] = r->link;
  311.     free(r);
  312.     return DC_SUCCESS;
  313. }
  314.  
  315.  
  316. /* tell how many entries are currently on the evaluation stack */
  317. int
  318. dc_tell_stackdepth DC_DECLVOID()
  319. {
  320.     dc_list *n;
  321.     int depth=0;
  322.  
  323.     for (n=dc_stack; n; n=n->link)
  324.         ++depth;
  325.     return depth;
  326. }
  327.  
  328.  
  329. /* return the length of the indicated data value;
  330.  * if discard_flag is true, the deallocate the value when done
  331.  *
  332.  * The definition of a datum's length is deligated to the
  333.  * appropriate module.
  334.  */
  335. int
  336. dc_tell_length DC_DECLARG((value, discard_flag))
  337.     dc_data value DC_DECLSEP
  338.     dc_boolean discard_flag DC_DECLEND
  339. {
  340.     int length;
  341.  
  342.     if (value.dc_type == DC_NUMBER){
  343.         length = dc_numlen(value.v.number);
  344.         if (discard_flag == DC_TRUE)
  345.             dc_free_num(&value.v.number);
  346.     } else if (value.dc_type == DC_STRING) {
  347.         length = dc_strlen(value.v.string);
  348.         if (discard_flag == DC_TRUE)
  349.             dc_free_str(&value.v.string);
  350.     } else {
  351.         dc_garbage("in tell_length", -1);
  352.         /*NOTREACHED*/
  353.         length = 0;    /*just to suppress spurious compiler warnings*/
  354.     }
  355.     return length;
  356. }
  357.  
  358.  
  359.  
  360. /* print out all of the values on the evaluation stack */
  361. void
  362. dc_printall DC_DECLARG((obase))
  363.     int obase DC_DECLEND
  364. {
  365.     dc_list *n;
  366.  
  367.     for (n=dc_stack; n; n=n->link)
  368.         dc_print(n->value, obase);
  369. }
  370.