Blame bc/util.c

Packit 70b277
/*  This file is part of GNU bc.
Packit 70b277
Packit 70b277
    Copyright (C) 1991-1994, 1997, 2006, 2008, 2012-2017 Free Software Foundation, Inc.
Packit 70b277
Packit 70b277
    This program is free software; you can redistribute it and/or modify
Packit 70b277
    it under the terms of the GNU General Public License as published by
Packit 70b277
    the Free Software Foundation; either version 3 of the License , or
Packit 70b277
    (at your option) any later version.
Packit 70b277
Packit 70b277
    This program is distributed in the hope that it will be useful,
Packit 70b277
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 70b277
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 70b277
    GNU General Public License for more details.
Packit 70b277
Packit 70b277
    You should have received a copy of the GNU General Public License
Packit 70b277
    along with this program; see the file COPYING.  If not, see
Packit 70b277
    <http://www.gnu.org/licenses>.
Packit 70b277
Packit 70b277
    You may contact the author by:
Packit 70b277
       e-mail:  philnelson@acm.org
Packit 70b277
      us-mail:  Philip A. Nelson
Packit 70b277
                Computer Science Department, 9062
Packit 70b277
                Western Washington University
Packit 70b277
                Bellingham, WA 98226-9062
Packit 70b277
       
Packit 70b277
*************************************************************************/
Packit 70b277
Packit 70b277
/* util.c: Utility routines for bc. */
Packit 70b277
Packit 70b277
#include "bcdefs.h"
Packit 70b277
#ifndef VARARGS
Packit 70b277
#include <stdarg.h>
Packit 70b277
#else
Packit 70b277
#include <varargs.h>
Packit 70b277
#endif
Packit 70b277
#include "proto.h"
Packit 70b277
Packit 70b277
Packit 70b277
/* strcopyof mallocs new memory and copies a string to to the new
Packit 70b277
   memory. */
Packit 70b277
Packit 70b277
char *
Packit 70b277
strcopyof (const char *str)
Packit 70b277
{
Packit 70b277
  char *temp;
Packit 70b277
Packit 70b277
  temp = bc_malloc (strlen (str)+1);
Packit 70b277
  return (strcpy (temp,str));
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* nextarg adds another value to the list of arguments. */
Packit 70b277
Packit 70b277
arg_list *
Packit 70b277
nextarg (arg_list *args, int val, int is_var)
Packit 70b277
{ arg_list *temp;
Packit 70b277
Packit 70b277
  temp = bc_malloc (sizeof (arg_list));
Packit 70b277
  temp->av_name = val;
Packit 70b277
  temp->arg_is_var = is_var;
Packit 70b277
  temp->next = args;
Packit 70b277
 
Packit 70b277
  return (temp);
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* For generate, we must produce a string in the form
Packit 70b277
    "val,val,...,val".  We also need a couple of static variables
Packit 70b277
   for retaining old generated strings.  It also uses a recursive
Packit 70b277
   function that builds the string. */
Packit 70b277
Packit 70b277
static char *arglist1 = NULL, *arglist2 = NULL;
Packit 70b277
Packit 70b277
Packit 70b277
/* make_arg_str does the actual construction of the argument string.
Packit 70b277
   ARGS is the pointer to the list and LEN is the maximum number of
Packit 70b277
   characters needed.  1 char is the minimum needed. 
Packit 70b277
 */
Packit 70b277
Packit 70b277
static char *make_arg_str (arg_list *args, int len);
Packit 70b277
Packit 70b277
static char *
Packit 70b277
make_arg_str (arg_list *args, int len)
Packit 70b277
{
Packit 70b277
  char *temp;
Packit 70b277
  char sval[30];
Packit 70b277
Packit 70b277
  /* Recursive call. */
Packit 70b277
  if (args != NULL)
Packit 70b277
    temp = make_arg_str (args->next, len+12);
Packit 70b277
  else
Packit 70b277
    {
Packit 70b277
      temp = bc_malloc (len);
Packit 70b277
      *temp = 0;
Packit 70b277
      return temp;
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Add the current number to the end of the string. */
Packit 70b277
  if (args->arg_is_var)
Packit 70b277
    if (len != 1) 
Packit 70b277
      snprintf (sval, sizeof(sval), "*%d,", args->av_name);
Packit 70b277
    else
Packit 70b277
      snprintf (sval, sizeof(sval), "*%d", args->av_name);
Packit 70b277
  else
Packit 70b277
    if (len != 1) 
Packit 70b277
      snprintf (sval, sizeof(sval), "%d,", args->av_name);
Packit 70b277
    else
Packit 70b277
      snprintf (sval, sizeof(sval), "%d", args->av_name);
Packit 70b277
  temp = strcat (temp, sval);
Packit 70b277
  return (temp);
Packit 70b277
}
Packit 70b277
Packit 70b277
char *
Packit 70b277
arg_str (arg_list *args)
Packit 70b277
{
Packit 70b277
  if (arglist2 != NULL) 
Packit 70b277
    free (arglist2);
Packit 70b277
  arglist2 = arglist1;
Packit 70b277
  arglist1 = make_arg_str (args, 1);
Packit 70b277
  return (arglist1);
Packit 70b277
}
Packit 70b277
Packit 70b277
char *
Packit 70b277
call_str (arg_list *args)
Packit 70b277
{
Packit 70b277
  arg_list *temp;
Packit 70b277
  int       arg_count;
Packit 70b277
  int       ix;
Packit 70b277
  
Packit 70b277
  if (arglist2 != NULL) 
Packit 70b277
    free (arglist2);
Packit 70b277
  arglist2 = arglist1;
Packit 70b277
Packit 70b277
  /* Count the number of args and add the 0's and 1's. */
Packit 70b277
  for (temp = args, arg_count = 0; temp != NULL; temp = temp->next)
Packit 70b277
    arg_count++;
Packit 70b277
  arglist1 = bc_malloc(arg_count+1);
Packit 70b277
  for (temp = args, ix=0; temp != NULL; temp = temp->next)
Packit 70b277
    arglist1[ix++] = ( temp->av_name ? '1' : '0');
Packit 70b277
  arglist1[ix] = 0;
Packit 70b277
      
Packit 70b277
  return (arglist1);
Packit 70b277
}
Packit 70b277
Packit 70b277
/* free_args frees an argument list ARGS. */
Packit 70b277
Packit 70b277
void
Packit 70b277
free_args (arg_list *args)
Packit 70b277
{ 
Packit 70b277
  arg_list *temp;
Packit 70b277
 
Packit 70b277
  temp = args;
Packit 70b277
  while (temp != NULL)
Packit 70b277
    {
Packit 70b277
      args = args->next;
Packit 70b277
      free (temp);
Packit 70b277
      temp = args;
Packit 70b277
    }
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* Check for valid parameter (PARAMS) and auto (AUTOS) lists.
Packit 70b277
   There must be no duplicates any where.  Also, this is where
Packit 70b277
   warnings are generated for array parameters. */
Packit 70b277
Packit 70b277
void
Packit 70b277
check_params (arg_list *params, arg_list *autos)
Packit 70b277
{
Packit 70b277
  arg_list *tmp1, *tmp2;
Packit 70b277
Packit 70b277
  /* Check for duplicate parameters. */
Packit 70b277
  if (params != NULL)
Packit 70b277
    {
Packit 70b277
      tmp1 = params;
Packit 70b277
      while (tmp1 != NULL)
Packit 70b277
	{
Packit 70b277
	  tmp2 = tmp1->next;
Packit 70b277
	  while (tmp2 != NULL)
Packit 70b277
	    {
Packit 70b277
	      if (tmp2->av_name == tmp1->av_name) 
Packit 70b277
		yyerror ("duplicate parameter names");
Packit 70b277
	      tmp2 = tmp2->next;
Packit 70b277
	    }
Packit 70b277
	  if (tmp1->arg_is_var)
Packit 70b277
	    ct_warn ("Variable array parameter");
Packit 70b277
	  tmp1 = tmp1->next;
Packit 70b277
	}
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Check for duplicate autos. */
Packit 70b277
  if (autos != NULL)
Packit 70b277
    {
Packit 70b277
      tmp1 = autos;
Packit 70b277
      while (tmp1 != NULL)
Packit 70b277
	{
Packit 70b277
	  tmp2 = tmp1->next;
Packit 70b277
	  while (tmp2 != NULL)
Packit 70b277
	    {
Packit 70b277
	      if (tmp2->av_name == tmp1->av_name) 
Packit 70b277
		yyerror ("duplicate auto variable names");
Packit 70b277
	      tmp2 = tmp2->next;
Packit 70b277
	    }
Packit 70b277
	  if (tmp1->arg_is_var)
Packit 70b277
	    yyerror ("* not allowed here");
Packit 70b277
	  tmp1 = tmp1->next;
Packit 70b277
	}
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Check for duplicate between parameters and autos. */
Packit 70b277
  if ((params != NULL) && (autos != NULL))
Packit 70b277
    {
Packit 70b277
      tmp1 = params;
Packit 70b277
      while (tmp1 != NULL)
Packit 70b277
	{
Packit 70b277
	  tmp2 = autos;
Packit 70b277
	  while (tmp2 != NULL)
Packit 70b277
	    {
Packit 70b277
	      if (tmp2->av_name == tmp1->av_name) 
Packit 70b277
		yyerror ("variable in both parameter and auto lists");
Packit 70b277
	      tmp2 = tmp2->next;
Packit 70b277
	    }
Packit 70b277
	  tmp1 = tmp1->next;
Packit 70b277
	}
Packit 70b277
    }
Packit 70b277
}
Packit 70b277
Packit 70b277
/* genstr management to avoid buffer overflow. */
Packit 70b277
void
Packit 70b277
set_genstr_size (int size)
Packit 70b277
{
Packit 70b277
  if (size > genlen) {
Packit 70b277
    if (genstr != NULL)
Packit 70b277
      free(genstr);
Packit 70b277
    genstr = bc_malloc (size);
Packit 70b277
    genlen = size;
Packit 70b277
  }
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* Initialize the code generator the parser. */
Packit 70b277
Packit 70b277
void
Packit 70b277
init_gen (void)
Packit 70b277
{
Packit 70b277
  /* Get things ready. */
Packit 70b277
  break_label = 0;
Packit 70b277
  continue_label = 0;
Packit 70b277
  next_label  = 1;
Packit 70b277
  out_count = 2;
Packit 70b277
  if (compile_only) 
Packit 70b277
    printf ("@i");
Packit 70b277
  else
Packit 70b277
    init_load ();
Packit 70b277
  had_error = FALSE;
Packit 70b277
  did_gen = FALSE;
Packit 70b277
  set_genstr_size (64);
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* generate code STR for the machine. */
Packit 70b277
Packit 70b277
void
Packit 70b277
generate (const char *str)
Packit 70b277
{
Packit 70b277
  did_gen = TRUE;
Packit 70b277
  if (compile_only)
Packit 70b277
    {
Packit 70b277
      printf ("%s",str);
Packit 70b277
      out_count += strlen(str);
Packit 70b277
      if (out_count > 60)
Packit 70b277
	{
Packit 70b277
	  printf ("\n");
Packit 70b277
	  out_count = 0;
Packit 70b277
	}
Packit 70b277
    }
Packit 70b277
  else
Packit 70b277
    load_code (str);
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* Execute the current code as loaded. */
Packit 70b277
Packit 70b277
void
Packit 70b277
run_code(void)
Packit 70b277
{
Packit 70b277
  /* If no compile errors run the current code. */
Packit 70b277
  if (!had_error && did_gen)
Packit 70b277
    {
Packit 70b277
      if (compile_only)
Packit 70b277
	{
Packit 70b277
	  printf ("@r\n"); 
Packit 70b277
	  out_count = 0;
Packit 70b277
	}
Packit 70b277
      else
Packit 70b277
	execute ();
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Reinitialize the code generation and machine. */
Packit 70b277
  if (did_gen)
Packit 70b277
    init_gen();
Packit 70b277
  else
Packit 70b277
    had_error = FALSE;
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* Output routines: Write a character CH to the standard output.
Packit 70b277
   It keeps track of the number of characters output and may
Packit 70b277
   break the output with a "\<cr>".  Always used for numbers. */
Packit 70b277
Packit 70b277
void
Packit 70b277
out_char (int ch)
Packit 70b277
{
Packit 70b277
  if (ch == '\n')
Packit 70b277
    {
Packit 70b277
      out_col = 0;
Packit 70b277
      putchar ('\n');
Packit 70b277
    }
Packit 70b277
  else
Packit 70b277
    {
Packit 70b277
      out_col++;
Packit 70b277
      if (out_col == line_size-1 && line_size != 0)
Packit 70b277
	{
Packit 70b277
	  putchar ('\\');
Packit 70b277
	  putchar ('\n');
Packit 70b277
	  out_col = 1;
Packit 70b277
	}
Packit 70b277
      putchar (ch);
Packit 70b277
    }
Packit 70b277
}
Packit 70b277
Packit 70b277
/* Output routines: Write a character CH to the standard output.
Packit 70b277
   It keeps track of the number of characters output and may
Packit 70b277
   break the output with a "\<cr>".  This one is for strings.
Packit 70b277
   In POSIX bc, strings are not broken across lines. */
Packit 70b277
Packit 70b277
void
Packit 70b277
out_schar (int ch)
Packit 70b277
{
Packit 70b277
  if (ch == '\n')
Packit 70b277
    {
Packit 70b277
      out_col = 0;
Packit 70b277
      putchar ('\n');
Packit 70b277
    }
Packit 70b277
  else
Packit 70b277
    {
Packit 70b277
      if (!std_only)
Packit 70b277
	{
Packit 70b277
	  out_col++;
Packit 70b277
	  if (out_col == line_size-1 && line_size != 0)
Packit 70b277
	    {
Packit 70b277
	      putchar ('\\');
Packit 70b277
	      putchar ('\n');
Packit 70b277
	      out_col = 1;
Packit 70b277
	    }
Packit 70b277
	}
Packit 70b277
      putchar (ch);
Packit 70b277
    }
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* The following are "Symbol Table" routines for the parser. */
Packit 70b277
Packit 70b277
/*  find_id returns a pointer to node in TREE that has the correct
Packit 70b277
    ID.  If there is no node in TREE with ID, NULL is returned. */
Packit 70b277
Packit 70b277
id_rec *
Packit 70b277
find_id (id_rec *tree, const char *id)
Packit 70b277
{
Packit 70b277
  int cmp_result;
Packit 70b277
  
Packit 70b277
  /* Check for an empty tree. */
Packit 70b277
  if (tree == NULL)
Packit 70b277
    return NULL;
Packit 70b277
Packit 70b277
  /* Recursively search the tree. */
Packit 70b277
  cmp_result = strcmp (id, tree->id);
Packit 70b277
  if (cmp_result == 0)
Packit 70b277
    return tree;  /* This is the item. */
Packit 70b277
  else if (cmp_result < 0)
Packit 70b277
    return find_id (tree->left, id);
Packit 70b277
  else
Packit 70b277
    return find_id (tree->right, id);  
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* insert_id_rec inserts a NEW_ID rec into the tree whose ROOT is
Packit 70b277
   provided.  insert_id_rec returns TRUE if the tree height from
Packit 70b277
   ROOT down is increased otherwise it returns FALSE.  This is a
Packit 70b277
   recursive balanced binary tree insertion algorithm. */
Packit 70b277
Packit 70b277
int insert_id_rec (id_rec **root, id_rec *new_id)
Packit 70b277
{
Packit 70b277
  id_rec *A, *B;
Packit 70b277
Packit 70b277
  /* If root is NULL, this where it is to be inserted. */
Packit 70b277
  if (*root == NULL)
Packit 70b277
    {
Packit 70b277
      *root = new_id;
Packit 70b277
      new_id->left = NULL;
Packit 70b277
      new_id->right = NULL;
Packit 70b277
      new_id->balance = 0;
Packit 70b277
      return (TRUE);
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* We need to search for a leaf. */
Packit 70b277
  if (strcmp (new_id->id, (*root)->id) < 0)
Packit 70b277
    {
Packit 70b277
      /* Insert it on the left. */
Packit 70b277
      if (insert_id_rec (&((*root)->left), new_id))
Packit 70b277
	{
Packit 70b277
	  /* The height increased. */
Packit 70b277
	  (*root)->balance --;
Packit 70b277
	  
Packit 70b277
	  switch ((*root)->balance)
Packit 70b277
	    {
Packit 70b277
	    case  0:  /* no height increase. */
Packit 70b277
	      return (FALSE);
Packit 70b277
	    case -1:  /* height increase. */
Packit 70b277
	      return (TRUE);
Packit 70b277
	    case -2:  /* we need to do a rebalancing act. */
Packit 70b277
	      A = *root;
Packit 70b277
	      B = (*root)->left;
Packit 70b277
	      if (B->balance <= 0)
Packit 70b277
		{
Packit 70b277
		  /* Single Rotate. */
Packit 70b277
		  A->left = B->right;
Packit 70b277
		  B->right = A;
Packit 70b277
		  *root = B;
Packit 70b277
		  A->balance = 0;
Packit 70b277
		  B->balance = 0;
Packit 70b277
		}
Packit 70b277
	      else
Packit 70b277
		{
Packit 70b277
		  /* Double Rotate. */
Packit 70b277
		  *root = B->right;
Packit 70b277
		  B->right = (*root)->left;
Packit 70b277
		  A->left = (*root)->right;
Packit 70b277
		  (*root)->left = B;
Packit 70b277
		  (*root)->right = A;
Packit 70b277
		  switch ((*root)->balance)
Packit 70b277
		    {
Packit 70b277
		    case -1:
Packit 70b277
		      A->balance = 1;
Packit 70b277
		      B->balance = 0;
Packit 70b277
		      break;
Packit 70b277
		    case  0:
Packit 70b277
		      A->balance = 0;
Packit 70b277
		      B->balance = 0;
Packit 70b277
		      break;
Packit 70b277
		    case  1:
Packit 70b277
		      A->balance = 0;
Packit 70b277
		      B->balance = -1;
Packit 70b277
		      break;
Packit 70b277
		    }
Packit 70b277
		  (*root)->balance = 0;
Packit 70b277
		}
Packit 70b277
	    }     
Packit 70b277
	} 
Packit 70b277
    }
Packit 70b277
  else
Packit 70b277
    {
Packit 70b277
      /* Insert it on the right. */
Packit 70b277
      if (insert_id_rec (&((*root)->right), new_id))
Packit 70b277
	{
Packit 70b277
	  /* The height increased. */
Packit 70b277
	  (*root)->balance ++;
Packit 70b277
Packit 70b277
	  switch ((*root)->balance)
Packit 70b277
	    {
Packit 70b277
	    case 0:  /* no height increase. */
Packit 70b277
	      return (FALSE);
Packit 70b277
	    case 1:  /* height increase. */
Packit 70b277
	      return (TRUE);
Packit 70b277
	    case 2:  /* we need to do a rebalancing act. */
Packit 70b277
	      A = *root;
Packit 70b277
	      B = (*root)->right;
Packit 70b277
	      if (B->balance >= 0)
Packit 70b277
		{
Packit 70b277
		  /* Single Rotate. */
Packit 70b277
		  A->right = B->left;
Packit 70b277
		  B->left = A;
Packit 70b277
		  *root = B;
Packit 70b277
		  A->balance = 0;
Packit 70b277
		  B->balance = 0;
Packit 70b277
		}
Packit 70b277
	      else
Packit 70b277
		{
Packit 70b277
		  /* Double Rotate. */
Packit 70b277
		  *root = B->left;
Packit 70b277
		  B->left = (*root)->right;
Packit 70b277
		  A->right = (*root)->left;
Packit 70b277
		  (*root)->left = A;
Packit 70b277
		  (*root)->right = B;
Packit 70b277
		  switch ((*root)->balance)
Packit 70b277
		    {
Packit 70b277
		    case -1:
Packit 70b277
		      A->balance = 0;
Packit 70b277
		      B->balance = 1;
Packit 70b277
		      break;
Packit 70b277
		    case  0:
Packit 70b277
		      A->balance = 0;
Packit 70b277
		      B->balance = 0;
Packit 70b277
		      break;
Packit 70b277
		    case  1:
Packit 70b277
		      A->balance = -1;
Packit 70b277
		      B->balance = 0;
Packit 70b277
		      break;
Packit 70b277
		    }
Packit 70b277
		  (*root)->balance = 0;
Packit 70b277
		}
Packit 70b277
	    }     
Packit 70b277
	} 
Packit 70b277
    }
Packit 70b277
  
Packit 70b277
  /* If we fall through to here, the tree did not grow in height. */
Packit 70b277
  return (FALSE);
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* Initialize variables for the symbol table tree. */
Packit 70b277
Packit 70b277
void
Packit 70b277
init_tree(void)
Packit 70b277
{
Packit 70b277
  name_tree  = NULL;
Packit 70b277
  next_array = 1;
Packit 70b277
  next_func  = 1;
Packit 70b277
  /* 0 => ibase, 1 => obase, 2 => scale, 3 => history, 4 => last. */
Packit 70b277
  next_var   = 5;
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* Lookup routines for symbol table names. */
Packit 70b277
Packit 70b277
int
Packit 70b277
lookup (char *name, int  namekind)
Packit 70b277
{
Packit 70b277
  id_rec *id;
Packit 70b277
Packit 70b277
  /* Warn about non-standard name. */
Packit 70b277
  if (strlen(name) != 1)
Packit 70b277
    ct_warn ("multiple letter name - %s", name);
Packit 70b277
Packit 70b277
  /* Look for the id. */
Packit 70b277
  id = find_id (name_tree, name);
Packit 70b277
  if (id == NULL)
Packit 70b277
    {
Packit 70b277
      /* We need to make a new item. */
Packit 70b277
      id = bc_malloc (sizeof (id_rec));
Packit 70b277
      id->id = strcopyof (name);
Packit 70b277
      id->a_name = 0;
Packit 70b277
      id->f_name = 0;
Packit 70b277
      id->v_name = 0;
Packit 70b277
      insert_id_rec (&name_tree, id);
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Return the correct value. */
Packit 70b277
  switch (namekind)
Packit 70b277
    {
Packit 70b277
      
Packit 70b277
    case ARRAY:
Packit 70b277
      /* ARRAY variable numbers are returned as negative numbers. */
Packit 70b277
      if (id->a_name != 0)
Packit 70b277
	{
Packit 70b277
	  free (name);
Packit 70b277
	  return (-id->a_name);
Packit 70b277
	}
Packit 70b277
      id->a_name = next_array++;
Packit 70b277
      if (id->a_name < MAX_STORE)
Packit 70b277
	{
Packit 70b277
	  if (id->a_name >= a_count)
Packit 70b277
	    more_arrays ();
Packit 70b277
	  a_names[id->a_name] = name;
Packit 70b277
	  return (-id->a_name);
Packit 70b277
	}
Packit 70b277
      yyerror ("Too many array variables");
Packit 70b277
      bc_exit (1);
Packit 70b277
      /*NOTREACHED*/
Packit 70b277
Packit 70b277
    case FUNCT:
Packit 70b277
    case FUNCTDEF:
Packit 70b277
      if (id->f_name != 0)
Packit 70b277
	{
Packit 70b277
          free(name);
Packit 70b277
	  /* Check to see if we are redefining a math lib function. */ 
Packit 70b277
	  if (use_math && namekind == FUNCTDEF && id->f_name <= 6)
Packit 70b277
	    id->f_name = next_func++;
Packit 70b277
	  return (id->f_name);
Packit 70b277
	}
Packit 70b277
      id->f_name = next_func++;
Packit 70b277
      if (id->f_name < MAX_STORE)
Packit 70b277
	{
Packit 70b277
	  if (id->f_name >= f_count)
Packit 70b277
	    more_functions ();
Packit 70b277
          f_names[id->f_name] = name;
Packit 70b277
	  return (id->f_name);
Packit 70b277
	}
Packit 70b277
      yyerror ("Too many functions");
Packit 70b277
      bc_exit (1);
Packit 70b277
      /*NOTREACHED*/
Packit 70b277
Packit 70b277
    case SIMPLE:
Packit 70b277
      if (id->v_name != 0)
Packit 70b277
	{
Packit 70b277
	  free(name);
Packit 70b277
	  return (id->v_name);
Packit 70b277
	}
Packit 70b277
      id->v_name = next_var++;
Packit 70b277
      if (id->v_name <= MAX_STORE)
Packit 70b277
	{
Packit 70b277
	  if (id->v_name >= v_count)
Packit 70b277
	    more_variables ();
Packit 70b277
          v_names[id->v_name - 1] = name;
Packit 70b277
	  return (id->v_name);
Packit 70b277
	}
Packit 70b277
      yyerror ("Too many variables");
Packit 70b277
      bc_exit (1);
Packit 70b277
      /*NOTREACHED*/
Packit 70b277
Packit 70b277
    }
Packit 70b277
Packit 70b277
  yyerror ("End of util.c/lookup() reached.  Please report this bug.");
Packit 70b277
  bc_exit (1);
Packit 70b277
  /*NOTREACHED*/
Packit 70b277
  return 0;
Packit 70b277
}
Packit 70b277
Packit 70b277
/* Print out the limits of this program. */
Packit 70b277
Packit 70b277
void
Packit 70b277
limits(void)
Packit 70b277
{
Packit 70b277
  printf ("BC_BASE_MAX     = %d\n",  BC_BASE_MAX);
Packit 70b277
  printf ("BC_DIM_MAX      = %ld\n", (long) BC_DIM_MAX);
Packit 70b277
  printf ("BC_SCALE_MAX    = %d\n",  BC_SCALE_MAX);
Packit 70b277
  printf ("BC_STRING_MAX   = %d\n",  BC_STRING_MAX);
Packit 70b277
  printf ("MAX Exponent    = %ld\n", (long) LONG_MAX);
Packit 70b277
  printf ("Number of vars  = %ld\n", (long) MAX_STORE);
Packit 70b277
#ifdef OLD_EQ_OP
Packit 70b277
  printf ("Old assignment operatiors are valid. (=-, =+, ...)\n");
Packit 70b277
#endif 
Packit 70b277
}
Packit 70b277
Packit 70b277
/* bc_malloc will check the return value so all other places do not
Packit 70b277
   have to do it!  SIZE is the number of bytes to allocate. */
Packit 70b277
Packit 70b277
void *
Packit 70b277
bc_malloc (size_t size)
Packit 70b277
{
Packit 70b277
  void *ptr;
Packit 70b277
Packit 70b277
  ptr = (void *) malloc (size);
Packit 70b277
  if (ptr == NULL)
Packit 70b277
    out_of_memory ();
Packit 70b277
Packit 70b277
  return ptr;
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* The following routines are error routines for various problems. */
Packit 70b277
Packit 70b277
/* Malloc could not get enought memory. */
Packit 70b277
Packit 70b277
void
Packit 70b277
out_of_memory(void)
Packit 70b277
{
Packit 70b277
  fprintf (stderr, "Fatal error: Out of memory for malloc.\n");
Packit 70b277
  bc_exit (1);
Packit 70b277
  /*NOTREACHED*/
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
Packit 70b277
/* The standard yyerror routine.  Built with variable number of argumnets. */
Packit 70b277
Packit 70b277
#ifndef VARARGS
Packit 70b277
#ifdef __STDC__
Packit 70b277
void
Packit 70b277
yyerror (const char *str, ...)
Packit 70b277
#else
Packit 70b277
void
Packit 70b277
yyerror (str)
Packit 70b277
     const char *str;
Packit 70b277
#endif
Packit 70b277
#else
Packit 70b277
void
Packit 70b277
yyerror (str, va_alist)
Packit 70b277
     const char *str;
Packit 70b277
#endif
Packit 70b277
{
Packit 70b277
  const char *name;
Packit 70b277
  va_list args;
Packit 70b277
Packit 70b277
#ifndef VARARGS   
Packit 70b277
   va_start (args, str);
Packit 70b277
#else
Packit 70b277
   va_start (args);
Packit 70b277
#endif
Packit 70b277
  if (is_std_in)
Packit 70b277
    name = "(standard_in)";
Packit 70b277
  else
Packit 70b277
    name = file_name;
Packit 70b277
  fprintf (stderr,"%s %d: ",name,line_no);
Packit 70b277
  vfprintf (stderr, str, args);
Packit 70b277
  fprintf (stderr, "\n");
Packit 70b277
  had_error = TRUE;
Packit 70b277
  va_end (args);
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* The routine to produce warnings about non-standard features
Packit 70b277
   found during parsing. */
Packit 70b277
Packit 70b277
#ifndef VARARGS
Packit 70b277
#ifdef __STDC__
Packit 70b277
void 
Packit 70b277
ct_warn (const char *mesg, ...)
Packit 70b277
#else
Packit 70b277
void
Packit 70b277
ct_warn (mesg)
Packit 70b277
     const char *mesg;
Packit 70b277
#endif
Packit 70b277
#else
Packit 70b277
void
Packit 70b277
ct_warn (mesg, va_alist)
Packit 70b277
     const char *mesg;
Packit 70b277
#endif
Packit 70b277
{
Packit 70b277
  const char *name;
Packit 70b277
  va_list args;
Packit 70b277
Packit 70b277
#ifndef VARARGS   
Packit 70b277
  va_start (args, mesg);
Packit 70b277
#else
Packit 70b277
  va_start (args);
Packit 70b277
#endif
Packit 70b277
  if (std_only)
Packit 70b277
    {
Packit 70b277
      if (is_std_in)
Packit 70b277
	name = "(standard_in)";
Packit 70b277
      else
Packit 70b277
	name = file_name;
Packit 70b277
      fprintf (stderr,"%s %d: Error: ",name,line_no);
Packit 70b277
      vfprintf (stderr, mesg, args);
Packit 70b277
      fprintf (stderr, "\n");
Packit 70b277
      had_error = TRUE;
Packit 70b277
    }
Packit 70b277
  else
Packit 70b277
    if (warn_not_std)
Packit 70b277
      {
Packit 70b277
	if (is_std_in)
Packit 70b277
	  name = "(standard_in)";
Packit 70b277
	else
Packit 70b277
	  name = file_name;
Packit 70b277
	fprintf (stderr,"%s %d: (Warning) ",name,line_no);
Packit 70b277
	vfprintf (stderr, mesg, args);
Packit 70b277
	fprintf (stderr, "\n");
Packit 70b277
      }
Packit 70b277
  va_end (args);
Packit 70b277
}
Packit 70b277
Packit 70b277
/* Runtime error will  print a message and stop the machine. */
Packit 70b277
Packit 70b277
#ifndef VARARGS
Packit 70b277
#ifdef __STDC__
Packit 70b277
void
Packit 70b277
rt_error (const char *mesg, ...)
Packit 70b277
#else
Packit 70b277
void
Packit 70b277
rt_error (mesg)
Packit 70b277
     const char *mesg;
Packit 70b277
#endif
Packit 70b277
#else
Packit 70b277
void
Packit 70b277
rt_error (mesg, va_alist)
Packit 70b277
     const char *mesg;
Packit 70b277
#endif
Packit 70b277
{
Packit 70b277
  va_list args;
Packit 70b277
Packit 70b277
  fprintf (stderr, "Runtime error (func=%s, adr=%d): ",
Packit 70b277
	   f_names[pc.pc_func], pc.pc_addr);
Packit 70b277
#ifndef VARARGS   
Packit 70b277
  va_start (args, mesg);
Packit 70b277
#else
Packit 70b277
  va_start (args);
Packit 70b277
#endif
Packit 70b277
  vfprintf (stderr, mesg, args);
Packit 70b277
  va_end (args);
Packit 70b277
  
Packit 70b277
  fprintf (stderr, "\n");
Packit 70b277
  runtime_error = TRUE;
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* A runtime warning tells of some action taken by the processor that
Packit 70b277
   may change the program execution but was not enough of a problem
Packit 70b277
   to stop the execution. */
Packit 70b277
Packit 70b277
#ifndef VARARGS
Packit 70b277
#ifdef __STDC__
Packit 70b277
void
Packit 70b277
rt_warn (const char *mesg, ...)
Packit 70b277
#else
Packit 70b277
void
Packit 70b277
rt_warn (const char *mesg)
Packit 70b277
#endif
Packit 70b277
#else
Packit 70b277
void
Packit 70b277
rt_warn (const char *mesg)
Packit 70b277
#endif
Packit 70b277
{
Packit 70b277
  va_list args;
Packit 70b277
Packit 70b277
  fprintf (stderr, "Runtime warning (func=%s, adr=%d): ",
Packit 70b277
	   f_names[pc.pc_func], pc.pc_addr);
Packit 70b277
#ifndef VARARGS   
Packit 70b277
  va_start (args, mesg);
Packit 70b277
#else
Packit 70b277
  va_start (args);
Packit 70b277
#endif
Packit 70b277
  vfprintf (stderr, mesg, args);
Packit 70b277
  va_end (args);
Packit 70b277
Packit 70b277
  fprintf (stderr, "\n");
Packit 70b277
}
Packit 70b277
Packit 70b277
/* bc_exit: Make sure to reset the edit state. */
Packit 70b277
Packit 70b277
void bc_exit(int val)
Packit 70b277
{
Packit 70b277
#if defined(LIBEDIT)
Packit 70b277
  if (edit != NULL)
Packit 70b277
    el_end(edit);
Packit 70b277
#endif
Packit 70b277
  exit(val);
Packit 70b277
  /*NOTREACHED*/
Packit 70b277
}