"Fossies" - the Fresh Open Source Software Archive

Member "bc-1.06.95/bc/util.c" (5 Sep 2006, 17062 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 "util.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 /*  This file is part of GNU bc.
    2 
    3     Copyright (C) 1991-1994, 1997, 2006 Free Software Foundation, Inc.
    4 
    5     This program is free software; you can redistribute it and/or modify
    6     it under the terms of the GNU General Public License as published by
    7     the Free Software Foundation; either version 2 of the License , or
    8     (at your option) any later version.
    9 
   10     This program is distributed in the hope that it will be useful,
   11     but WITHOUT ANY WARRANTY; without even the implied warranty of
   12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13     GNU General Public License for more details.
   14 
   15     You should have received a copy of the GNU General Public License
   16     along with this program; see the file COPYING.  If not, write to:
   17       The Free Software Foundation, Inc.
   18       Foundation, Inc.  51 Franklin Street, Fifth Floor,
   19       Boston, MA 02110-1301  USA
   20 
   21     You may contact the author by:
   22        e-mail:  philnelson@acm.org
   23       us-mail:  Philip A. Nelson
   24                 Computer Science Department, 9062
   25                 Western Washington University
   26                 Bellingham, WA 98226-9062
   27        
   28 *************************************************************************/
   29 
   30 /* util.c: Utility routines for bc. */
   31 
   32 #include "bcdefs.h"
   33 #ifndef VARARGS
   34 #include <stdarg.h>
   35 #else
   36 #include <varargs.h>
   37 #endif
   38 #include "proto.h"
   39 
   40 
   41 /* strcopyof mallocs new memory and copies a string to to the new
   42    memory. */
   43 
   44 char *
   45 strcopyof (str)
   46      const char *str;
   47 {
   48   char *temp;
   49 
   50   temp = (char *) bc_malloc (strlen (str)+1);
   51   return (strcpy (temp,str));
   52 }
   53 
   54 
   55 /* nextarg adds another value to the list of arguments. */
   56 
   57 arg_list *
   58 nextarg (args, val, is_var)
   59      arg_list *args;
   60      int val;
   61      int is_var;
   62 { arg_list *temp;
   63 
   64   temp = (arg_list *) bc_malloc (sizeof (arg_list));
   65   temp->av_name = val;
   66   temp->arg_is_var = is_var;
   67   temp->next = args;
   68  
   69   return (temp);
   70 }
   71 
   72 
   73 /* For generate, we must produce a string in the form
   74     "val,val,...,val".  We also need a couple of static variables
   75    for retaining old generated strings.  It also uses a recursive
   76    function that builds the string. */
   77 
   78 static char *arglist1 = NULL, *arglist2 = NULL;
   79 
   80 
   81 /* make_arg_str does the actual construction of the argument string.
   82    ARGS is the pointer to the list and LEN is the maximum number of
   83    characters needed.  1 char is the minimum needed. 
   84  */
   85 
   86 _PROTOTYPE (static char *make_arg_str, (arg_list *args, int len));
   87 
   88 static char *
   89 make_arg_str (args, len)
   90       arg_list *args;
   91       int len;
   92 {
   93   char *temp;
   94   char sval[20];
   95 
   96   /* Recursive call. */
   97   if (args != NULL)
   98     temp = make_arg_str (args->next, len+12);
   99   else
  100     {
  101       temp = (char *) bc_malloc (len);
  102       *temp = 0;
  103       return temp;
  104     }
  105 
  106   /* Add the current number to the end of the string. */
  107   if (args->arg_is_var)
  108     if (len != 1) 
  109       sprintf (sval, "*%d,", args->av_name);
  110     else
  111       sprintf (sval, "*%d", args->av_name);
  112   else
  113     if (len != 1) 
  114       sprintf (sval, "%d,", args->av_name);
  115     else
  116       sprintf (sval, "%d", args->av_name);
  117   temp = strcat (temp, sval);
  118   return (temp);
  119 }
  120 
  121 char *
  122 arg_str (args)
  123      arg_list *args;
  124 {
  125   if (arglist2 != NULL) 
  126     free (arglist2);
  127   arglist2 = arglist1;
  128   arglist1 = make_arg_str (args, 1);
  129   return (arglist1);
  130 }
  131 
  132 char *
  133 call_str (args)
  134      arg_list *args;
  135 {
  136   arg_list *temp;
  137   int       arg_count;
  138   int       ix;
  139   
  140   if (arglist2 != NULL) 
  141     free (arglist2);
  142   arglist2 = arglist1;
  143 
  144   /* Count the number of args and add the 0's and 1's. */
  145   for (temp = args, arg_count = 0; temp != NULL; temp = temp->next)
  146     arg_count++;
  147   arglist1 = (char *) bc_malloc(arg_count+1);
  148   for (temp = args, ix=0; temp != NULL; temp = temp->next)
  149     arglist1[ix++] = ( temp->av_name ? '1' : '0');
  150   arglist1[ix] = 0;
  151       
  152   return (arglist1);
  153 }
  154 
  155 /* free_args frees an argument list ARGS. */
  156 
  157 void
  158 free_args (args)
  159       arg_list *args;
  160 { 
  161   arg_list *temp;
  162  
  163   temp = args;
  164   while (temp != NULL)
  165     {
  166       args = args->next;
  167       free (temp);
  168       temp = args;
  169     }
  170 }
  171 
  172 
  173 /* Check for valid parameter (PARAMS) and auto (AUTOS) lists.
  174    There must be no duplicates any where.  Also, this is where
  175    warnings are generated for array parameters. */
  176 
  177 void
  178 check_params ( params, autos )
  179      arg_list *params, *autos;
  180 {
  181   arg_list *tmp1, *tmp2;
  182 
  183   /* Check for duplicate parameters. */
  184   if (params != NULL)
  185     {
  186       tmp1 = params;
  187       while (tmp1 != NULL)
  188     {
  189       tmp2 = tmp1->next;
  190       while (tmp2 != NULL)
  191         {
  192           if (tmp2->av_name == tmp1->av_name) 
  193         yyerror ("duplicate parameter names");
  194           tmp2 = tmp2->next;
  195         }
  196       if (tmp1->arg_is_var)
  197         warn ("Variable array parameter");
  198       tmp1 = tmp1->next;
  199     }
  200     }
  201 
  202   /* Check for duplicate autos. */
  203   if (autos != NULL)
  204     {
  205       tmp1 = autos;
  206       while (tmp1 != NULL)
  207     {
  208       tmp2 = tmp1->next;
  209       while (tmp2 != NULL)
  210         {
  211           if (tmp2->av_name == tmp1->av_name) 
  212         yyerror ("duplicate auto variable names");
  213           tmp2 = tmp2->next;
  214         }
  215       if (tmp1->arg_is_var)
  216         yyerror ("* not allowed here");
  217       tmp1 = tmp1->next;
  218     }
  219     }
  220 
  221   /* Check for duplicate between parameters and autos. */
  222   if ((params != NULL) && (autos != NULL))
  223     {
  224       tmp1 = params;
  225       while (tmp1 != NULL)
  226     {
  227       tmp2 = autos;
  228       while (tmp2 != NULL)
  229         {
  230           if (tmp2->av_name == tmp1->av_name) 
  231         yyerror ("variable in both parameter and auto lists");
  232           tmp2 = tmp2->next;
  233         }
  234       tmp1 = tmp1->next;
  235     }
  236     }
  237 }
  238 
  239 /* genstr management to avoid buffer overflow. */
  240 void
  241 set_genstr_size (size)
  242      int size;
  243 {
  244   if (size > genlen) {
  245     if (genstr != NULL)
  246       free(genstr);
  247     genstr = (char *) bc_malloc (size);
  248     genlen = size;
  249   }
  250 }
  251 
  252 
  253 /* Initialize the code generator the parser. */
  254 
  255 void
  256 init_gen ()
  257 {
  258   /* Get things ready. */
  259   break_label = 0;
  260   continue_label = 0;
  261   next_label  = 1;
  262   out_count = 2;
  263   if (compile_only) 
  264     printf ("@i");
  265   else
  266     init_load ();
  267   had_error = FALSE;
  268   did_gen = FALSE;
  269   set_genstr_size (64);
  270 }
  271 
  272 
  273 /* generate code STR for the machine. */
  274 
  275 void
  276 generate (str)
  277       const char *str;
  278 {
  279   did_gen = TRUE;
  280   if (compile_only)
  281     {
  282       printf ("%s",str);
  283       out_count += strlen(str);
  284       if (out_count > 60)
  285     {
  286       printf ("\n");
  287       out_count = 0;
  288     }
  289     }
  290   else
  291     load_code (str);
  292 }
  293 
  294 
  295 /* Execute the current code as loaded. */
  296 
  297 void
  298 run_code()
  299 {
  300   /* If no compile errors run the current code. */
  301   if (!had_error && did_gen)
  302     {
  303       if (compile_only)
  304     {
  305       printf ("@r\n"); 
  306       out_count = 0;
  307     }
  308       else
  309     execute ();
  310     }
  311 
  312   /* Reinitialize the code generation and machine. */
  313   if (did_gen)
  314     init_gen();
  315   else
  316     had_error = FALSE;
  317 }
  318 
  319 
  320 /* Output routines: Write a character CH to the standard output.
  321    It keeps track of the number of characters output and may
  322    break the output with a "\<cr>".  Always used for numbers. */
  323 
  324 void
  325 out_char (ch)
  326      int ch;
  327 {
  328   if (ch == '\n')
  329     {
  330       out_col = 0;
  331       putchar ('\n');
  332     }
  333   else
  334     {
  335       out_col++;
  336       if (out_col == line_size-1 && line_size != 0)
  337     {
  338       putchar ('\\');
  339       putchar ('\n');
  340       out_col = 1;
  341     }
  342       putchar (ch);
  343     }
  344 }
  345 
  346 /* Output routines: Write a character CH to the standard output.
  347    It keeps track of the number of characters output and may
  348    break the output with a "\<cr>".  This one is for strings.
  349    In POSIX bc, strings are not broken across lines. */
  350 
  351 void
  352 out_schar (ch)
  353      int ch;
  354 {
  355   if (ch == '\n')
  356     {
  357       out_col = 0;
  358       putchar ('\n');
  359     }
  360   else
  361     {
  362       if (!std_only)
  363     {
  364       out_col++;
  365       if (out_col == line_size-1 && line_size != 0)
  366         {
  367           putchar ('\\');
  368           putchar ('\n');
  369           out_col = 1;
  370         }
  371     }
  372       putchar (ch);
  373     }
  374 }
  375 
  376 
  377 /* The following are "Symbol Table" routines for the parser. */
  378 
  379 /*  find_id returns a pointer to node in TREE that has the correct
  380     ID.  If there is no node in TREE with ID, NULL is returned. */
  381 
  382 id_rec *
  383 find_id (tree, id)
  384      id_rec *tree;
  385      const char   *id;
  386 {
  387   int cmp_result;
  388   
  389   /* Check for an empty tree. */
  390   if (tree == NULL)
  391     return NULL;
  392 
  393   /* Recursively search the tree. */
  394   cmp_result = strcmp (id, tree->id);
  395   if (cmp_result == 0)
  396     return tree;  /* This is the item. */
  397   else if (cmp_result < 0)
  398     return find_id (tree->left, id);
  399   else
  400     return find_id (tree->right, id);  
  401 }
  402 
  403 
  404 /* insert_id_rec inserts a NEW_ID rec into the tree whose ROOT is
  405    provided.  insert_id_rec returns TRUE if the tree height from
  406    ROOT down is increased otherwise it returns FALSE.  This is a
  407    recursive balanced binary tree insertion algorithm. */
  408 
  409 int insert_id_rec (root, new_id)
  410      id_rec **root;
  411      id_rec *new_id;
  412 {
  413   id_rec *A, *B;
  414 
  415   /* If root is NULL, this where it is to be inserted. */
  416   if (*root == NULL)
  417     {
  418       *root = new_id;
  419       new_id->left = NULL;
  420       new_id->right = NULL;
  421       new_id->balance = 0;
  422       return (TRUE);
  423     }
  424 
  425   /* We need to search for a leaf. */
  426   if (strcmp (new_id->id, (*root)->id) < 0)
  427     {
  428       /* Insert it on the left. */
  429       if (insert_id_rec (&((*root)->left), new_id))
  430     {
  431       /* The height increased. */
  432       (*root)->balance --;
  433       
  434       switch ((*root)->balance)
  435         {
  436         case  0:  /* no height increase. */
  437           return (FALSE);
  438         case -1:  /* height increase. */
  439           return (TRUE);
  440         case -2:  /* we need to do a rebalancing act. */
  441           A = *root;
  442           B = (*root)->left;
  443           if (B->balance <= 0)
  444         {
  445           /* Single Rotate. */
  446           A->left = B->right;
  447           B->right = A;
  448           *root = B;
  449           A->balance = 0;
  450           B->balance = 0;
  451         }
  452           else
  453         {
  454           /* Double Rotate. */
  455           *root = B->right;
  456           B->right = (*root)->left;
  457           A->left = (*root)->right;
  458           (*root)->left = B;
  459           (*root)->right = A;
  460           switch ((*root)->balance)
  461             {
  462             case -1:
  463               A->balance = 1;
  464               B->balance = 0;
  465               break;
  466             case  0:
  467               A->balance = 0;
  468               B->balance = 0;
  469               break;
  470             case  1:
  471               A->balance = 0;
  472               B->balance = -1;
  473               break;
  474             }
  475           (*root)->balance = 0;
  476         }
  477         }     
  478     } 
  479     }
  480   else
  481     {
  482       /* Insert it on the right. */
  483       if (insert_id_rec (&((*root)->right), new_id))
  484     {
  485       /* The height increased. */
  486       (*root)->balance ++;
  487 
  488       switch ((*root)->balance)
  489         {
  490         case 0:  /* no height increase. */
  491           return (FALSE);
  492         case 1:  /* height increase. */
  493           return (TRUE);
  494         case 2:  /* we need to do a rebalancing act. */
  495           A = *root;
  496           B = (*root)->right;
  497           if (B->balance >= 0)
  498         {
  499           /* Single Rotate. */
  500           A->right = B->left;
  501           B->left = A;
  502           *root = B;
  503           A->balance = 0;
  504           B->balance = 0;
  505         }
  506           else
  507         {
  508           /* Double Rotate. */
  509           *root = B->left;
  510           B->left = (*root)->right;
  511           A->right = (*root)->left;
  512           (*root)->left = A;
  513           (*root)->right = B;
  514           switch ((*root)->balance)
  515             {
  516             case -1:
  517               A->balance = 0;
  518               B->balance = 1;
  519               break;
  520             case  0:
  521               A->balance = 0;
  522               B->balance = 0;
  523               break;
  524             case  1:
  525               A->balance = -1;
  526               B->balance = 0;
  527               break;
  528             }
  529           (*root)->balance = 0;
  530         }
  531         }     
  532     } 
  533     }
  534   
  535   /* If we fall through to here, the tree did not grow in height. */
  536   return (FALSE);
  537 }
  538 
  539 
  540 /* Initialize variables for the symbol table tree. */
  541 
  542 void
  543 init_tree()
  544 {
  545   name_tree  = NULL;
  546   next_array = 1;
  547   next_func  = 1;
  548   /* 0 => ibase, 1 => obase, 2 => scale, 3 => history, 4 => last. */
  549   next_var   = 5;
  550 }
  551 
  552 
  553 /* Lookup routines for symbol table names. */
  554 
  555 int
  556 lookup (name, namekind)
  557      char *name;
  558      int  namekind;
  559 {
  560   id_rec *id;
  561 
  562   /* Warn about non-standard name. */
  563   if (strlen(name) != 1)
  564     warn ("multiple letter name - %s", name);
  565 
  566   /* Look for the id. */
  567   id = find_id (name_tree, name);
  568   if (id == NULL)
  569     {
  570       /* We need to make a new item. */
  571       id = (id_rec *) bc_malloc (sizeof (id_rec));
  572       id->id = strcopyof (name);
  573       id->a_name = 0;
  574       id->f_name = 0;
  575       id->v_name = 0;
  576       insert_id_rec (&name_tree, id);
  577     }
  578 
  579   /* Return the correct value. */
  580   switch (namekind)
  581     {
  582       
  583     case ARRAY:
  584       /* ARRAY variable numbers are returned as negative numbers. */
  585       if (id->a_name != 0)
  586     {
  587       free (name);
  588       return (-id->a_name);
  589     }
  590       id->a_name = next_array++;
  591       if (id->a_name < MAX_STORE)
  592     {
  593       if (id->a_name >= a_count)
  594         more_arrays ();
  595       a_names[id->a_name] = name;
  596       return (-id->a_name);
  597     }
  598       yyerror ("Too many array variables");
  599       exit (1);
  600 
  601     case FUNCT:
  602     case FUNCTDEF:
  603       if (id->f_name != 0)
  604     {
  605       if (namekind != FUNCT)
  606         free(name);
  607       /* Check to see if we are redefining a math lib function. */ 
  608       if (use_math && namekind == FUNCTDEF && id->f_name <= 6)
  609         id->f_name = next_func++;
  610       return (id->f_name);
  611     }
  612       id->f_name = next_func++;
  613       if (id->f_name < MAX_STORE)
  614     {
  615       if (id->f_name >= f_count)
  616         more_functions ();
  617           f_names[id->f_name] = name;
  618       return (id->f_name);
  619     }
  620       yyerror ("Too many functions");
  621       exit (1);
  622 
  623     case SIMPLE:
  624       if (id->v_name != 0)
  625     {
  626       free(name);
  627       return (id->v_name);
  628     }
  629       id->v_name = next_var++;
  630       if (id->v_name <= MAX_STORE)
  631     {
  632       if (id->v_name >= v_count)
  633         more_variables ();
  634           v_names[id->v_name - 1] = name;
  635       return (id->v_name);
  636     }
  637       yyerror ("Too many variables");
  638       exit (1);
  639     }
  640 
  641   yyerror ("End of util.c/lookup() reached.  Please report this bug.");
  642   exit (1);
  643   /* not reached */
  644 }
  645 
  646 /* Print out the limits of this program. */
  647 
  648 void
  649 limits()
  650 {
  651   printf ("BC_BASE_MAX     = %d\n",  BC_BASE_MAX);
  652   printf ("BC_DIM_MAX      = %ld\n", (long) BC_DIM_MAX);
  653   printf ("BC_SCALE_MAX    = %d\n",  BC_SCALE_MAX);
  654   printf ("BC_STRING_MAX   = %d\n",  BC_STRING_MAX);
  655   printf ("MAX Exponent    = %ld\n", (long) LONG_MAX);
  656   printf ("Number of vars  = %ld\n", (long) MAX_STORE);
  657 #ifdef OLD_EQ_OP
  658   printf ("Old assignment operatiors are valid. (=-, =+, ...)\n");
  659 #endif 
  660 }
  661 
  662 /* bc_malloc will check the return value so all other places do not
  663    have to do it!  SIZE is the number of bytes to allocate. */
  664 
  665 void *
  666 bc_malloc (size)
  667      int size;
  668 {
  669   void *ptr;
  670 
  671   ptr = (void *) malloc (size);
  672   if (ptr == NULL)
  673     out_of_memory ();
  674 
  675   return ptr;
  676 }
  677 
  678 
  679 /* The following routines are error routines for various problems. */
  680 
  681 /* Malloc could not get enought memory. */
  682 
  683 void
  684 out_of_memory()
  685 {
  686   fprintf (stderr, "Fatal error: Out of memory for malloc.\n");
  687   exit (1);
  688 }
  689 
  690 
  691 
  692 /* The standard yyerror routine.  Built with variable number of argumnets. */
  693 
  694 #ifndef VARARGS
  695 #ifdef __STDC__
  696 void
  697 yyerror (const char *str, ...)
  698 #else
  699 void
  700 yyerror (str)
  701      const char *str;
  702 #endif
  703 #else
  704 void
  705 yyerror (str, va_alist)
  706      const char *str;
  707 #endif
  708 {
  709   const char *name;
  710   va_list args;
  711 
  712 #ifndef VARARGS   
  713    va_start (args, str);
  714 #else
  715    va_start (args);
  716 #endif
  717   if (is_std_in)
  718     name = "(standard_in)";
  719   else
  720     name = file_name;
  721   fprintf (stderr,"%s %d: ",name,line_no);
  722   vfprintf (stderr, str, args);
  723   fprintf (stderr, "\n");
  724   had_error = TRUE;
  725   va_end (args);
  726 }
  727 
  728 
  729 /* The routine to produce warnings about non-standard features
  730    found during parsing. */
  731 
  732 #ifndef VARARGS
  733 #ifdef __STDC__
  734 void 
  735 warn (const char *mesg, ...)
  736 #else
  737 void
  738 warn (mesg)
  739      const char *mesg;
  740 #endif
  741 #else
  742 void
  743 warn (mesg, va_alist)
  744      const char *mesg;
  745 #endif
  746 {
  747   const char *name;
  748   va_list args;
  749 
  750 #ifndef VARARGS   
  751   va_start (args, mesg);
  752 #else
  753   va_start (args);
  754 #endif
  755   if (std_only)
  756     {
  757       if (is_std_in)
  758     name = "(standard_in)";
  759       else
  760     name = file_name;
  761       fprintf (stderr,"%s %d: Error: ",name,line_no);
  762       vfprintf (stderr, mesg, args);
  763       fprintf (stderr, "\n");
  764       had_error = TRUE;
  765     }
  766   else
  767     if (warn_not_std)
  768       {
  769     if (is_std_in)
  770       name = "(standard_in)";
  771     else
  772       name = file_name;
  773     fprintf (stderr,"%s %d: (Warning) ",name,line_no);
  774     vfprintf (stderr, mesg, args);
  775     fprintf (stderr, "\n");
  776       }
  777   va_end (args);
  778 }
  779 
  780 /* Runtime error will  print a message and stop the machine. */
  781 
  782 #ifndef VARARGS
  783 #ifdef __STDC__
  784 void
  785 rt_error (const char *mesg, ...)
  786 #else
  787 void
  788 rt_error (mesg)
  789      const char *mesg;
  790 #endif
  791 #else
  792 void
  793 rt_error (mesg, va_alist)
  794      const char *mesg;
  795 #endif
  796 {
  797   va_list args;
  798 
  799   fprintf (stderr, "Runtime error (func=%s, adr=%d): ",
  800        f_names[pc.pc_func], pc.pc_addr);
  801 #ifndef VARARGS   
  802   va_start (args, mesg);
  803 #else
  804   va_start (args);
  805 #endif
  806   vfprintf (stderr, mesg, args);
  807   va_end (args);
  808   
  809   fprintf (stderr, "\n");
  810   runtime_error = TRUE;
  811 }
  812 
  813 
  814 /* A runtime warning tells of some action taken by the processor that
  815    may change the program execution but was not enough of a problem
  816    to stop the execution. */
  817 
  818 #ifndef VARARGS
  819 #ifdef __STDC__
  820 void
  821 rt_warn (const char *mesg, ...)
  822 #else
  823 void
  824 rt_warn (mesg)
  825      const char *mesg;
  826 #endif
  827 #else
  828 void
  829 rt_warn (mesg, va_alist)
  830      const char *mesg;
  831 #endif
  832 {
  833   va_list args;
  834 
  835   fprintf (stderr, "Runtime warning (func=%s, adr=%d): ",
  836        f_names[pc.pc_func], pc.pc_addr);
  837 #ifndef VARARGS   
  838   va_start (args, mesg);
  839 #else
  840   va_start (args);
  841 #endif
  842   vfprintf (stderr, mesg, args);
  843   va_end (args);
  844 
  845   fprintf (stderr, "\n");
  846 }