"Fossies" - the Fresh Open Source Software Archive

Member "bc-1.06.95/dc/stack.c" (29 Mar 2006, 11734 Bytes) of package /linux/misc/old/bc-1.06.95.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "stack.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.06.95_vs_1.07.

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