home *** CD-ROM | disk | FTP | other *** search
- /* storage.c: Code and data storage manipulations. This includes labels. */
-
- /* This file is part of bc written for MINIX.
- Copyright (C) 1991, 1992 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License , or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- You may contact the author by:
- e-mail: phil@cs.wwu.edu
- us-mail: Philip A. Nelson
- Computer Science Department, 9062
- Western Washington University
- Bellingham, WA 98226-9062
-
- *************************************************************************/
-
- #include "bcdefs.h"
- #include "global.h"
- #include "proto.h"
-
-
- /* Initialize the storage at the beginning of the run. */
-
- void
- init_storage ()
- {
-
- /* Functions: we start with none and ask for more. */
- f_count = 0;
- more_functions ();
- f_names[0] = "(main)";
-
- /* Variables. */
- v_count = 0;
- more_variables ();
-
- /* Arrays. */
- a_count = 0;
- more_arrays ();
-
- /* Other things... */
- ex_stack = NULL;
- fn_stack = NULL;
- i_base = 10;
- o_base = 10;
- scale = 0;
- c_code = FALSE;
- init_numbers();
- }
-
- /* Three functions for increasing the number of functions, variables, or
- arrays that are needed. This adds another 32 of the requested object. */
-
- void
- more_functions (VOID)
- {
- int old_count;
- int indx1, indx2;
- bc_function *old_f;
- bc_function *f;
- char **old_names;
-
- /* Save old information. */
- old_count = f_count;
- old_f = functions;
- old_names = f_names;
-
- /* Add a fixed amount and allocate new space. */
- f_count += STORE_INCR;
- functions = (bc_function *) bc_malloc (f_count*sizeof (bc_function));
- f_names = (char **) bc_malloc (f_count*sizeof (char *));
-
- /* Copy old ones. */
- for (indx1 = 0; indx1 < old_count; indx1++)
- {
- functions[indx1] = old_f[indx1];
- f_names[indx1] = old_names[indx1];
- }
-
- /* Initialize the new ones. */
- for (; indx1 < f_count; indx1++)
- {
- f = &functions[indx1];
- f->f_defined = FALSE;
- for (indx2 = 0; indx2 < BC_MAX_SEGS; indx2++)
- f->f_body [indx2] = NULL;
- f->f_code_size = 0;
- f->f_label = NULL;
- f->f_autos = NULL;
- f->f_params = NULL;
- }
-
- /* Free the old elements. */
- if (old_count != 0)
- {
- free (old_f);
- free (old_names);
- }
- }
-
- void
- more_variables ()
- {
- int indx;
- int old_count;
- bc_var **old_var;
- char **old_names;
-
- /* Save the old values. */
- old_count = v_count;
- old_var = variables;
- old_names = v_names;
-
- /* Increment by a fixed amount and allocate. */
- v_count += STORE_INCR;
- variables = (bc_var **) bc_malloc (v_count*sizeof(bc_var *));
- v_names = (char **) bc_malloc (v_count*sizeof(char *));
-
- /* Copy the old variables. */
- for (indx = 3; indx < old_count; indx++)
- variables[indx] = old_var[indx];
-
- /* Initialize the new elements. */
- for (; indx < v_count; indx++)
- variables[indx] = NULL;
-
- /* Free the old elements. */
- if (old_count != 0)
- {
- free (old_var);
- free (old_names);
- }
- }
-
- void
- more_arrays ()
- {
- int indx;
- int old_count;
- bc_var_array **old_ary;
- char **old_names;
-
- /* Save the old values. */
- old_count = a_count;
- old_ary = arrays;
- old_names = a_names;
-
- /* Increment by a fixed amount and allocate. */
- a_count += STORE_INCR;
- arrays = (bc_var_array **) bc_malloc (a_count*sizeof(bc_var_array *));
- a_names = (char **) bc_malloc (a_count*sizeof(char *));
-
- /* Copy the old arrays. */
- for (indx = 1; indx < old_count; indx++)
- arrays[indx] = old_ary[indx];
-
-
- /* Initialize the new elements. */
- for (; indx < v_count; indx++)
- arrays[indx] = NULL;
-
- /* Free the old elements. */
- if (old_count != 0)
- {
- free (old_ary);
- free (old_names);
- }
- }
-
-
- /* clear_func clears out function FUNC and makes it ready to redefine. */
-
- void
- clear_func (func)
- char func;
- {
- bc_function *f;
- int indx;
- bc_label_group *lg;
-
- /* Set the pointer to the function. */
- f = &functions[func];
- f->f_defined = FALSE;
-
- /* Clear the code segments. */
- for (indx = 0; indx < BC_MAX_SEGS; indx++)
- {
- if (f->f_body[indx] != NULL)
- {
- free (f->f_body[indx]);
- f->f_body[indx] = NULL;
- }
- }
-
- f->f_code_size = 0;
- if (f->f_autos != NULL)
- {
- free_args (f->f_autos);
- f->f_autos = NULL;
- }
- if (f->f_params != NULL)
- {
- free_args (f->f_params);
- f->f_params = NULL;
- }
- while (f->f_label != NULL)
- {
- lg = f->f_label->l_next;
- free (f->f_label);
- f->f_label = lg;
- }
- }
-
-
- /* Pop the function execution stack and return the top. */
-
- int
- fpop()
- {
- fstack_rec *temp;
- int retval;
-
- if (fn_stack != NULL)
- {
- temp = fn_stack;
- fn_stack = temp->s_next;
- retval = temp->s_val;
- free (temp);
- }
- return (retval);
- }
-
-
- /* Push VAL on to the function stack. */
-
- void
- fpush (val)
- int val;
- {
- fstack_rec *temp;
-
- temp = (fstack_rec *) bc_malloc (sizeof (fstack_rec));
- temp->s_next = fn_stack;
- temp->s_val = val;
- fn_stack = temp;
- }
-
-
- /* Pop and discard the top element of the regular execution stack. */
-
- void
- pop ()
- {
- estack_rec *temp;
-
- if (ex_stack != NULL)
- {
- temp = ex_stack;
- ex_stack = temp->s_next;
- free_num (&temp->s_num);
- free (temp);
- }
- }
-
-
- /* Push a copy of NUM on to the regular execution stack. */
-
- void
- push_copy (num)
- bc_num num;
- {
- estack_rec *temp;
-
- temp = (estack_rec *) bc_malloc (sizeof (estack_rec));
- temp->s_num = copy_num (num);
- temp->s_next = ex_stack;
- ex_stack = temp;
- }
-
-
- /* Push NUM on to the regular execution stack. Do NOT push a copy. */
-
- void
- push_num (num)
- bc_num num;
- {
- estack_rec *temp;
-
- temp = (estack_rec *) bc_malloc (sizeof (estack_rec));
- temp->s_num = num;
- temp->s_next = ex_stack;
- ex_stack = temp;
- }
-
-
- /* Make sure the ex_stack has at least DEPTH elements on it.
- Return TRUE if it has at least DEPTH elements, otherwise
- return FALSE. */
-
- char
- check_stack (depth)
- int depth;
- {
- estack_rec *temp;
-
- temp = ex_stack;
- while ((temp != NULL) && (depth > 0))
- {
- temp = temp->s_next;
- depth--;
- }
- if (depth > 0)
- {
- rt_error ("Stack error.");
- return FALSE;
- }
- return TRUE;
- }
-
-
- /* The following routines manipulate simple variables and
- array variables. */
-
- /* get_var returns a pointer to the variable VAR_NAME. If one does not
- exist, one is created. */
-
- bc_var *
- get_var (var_name)
- int var_name;
- {
- bc_var *var_ptr;
-
- var_ptr = variables[var_name];
- if (var_ptr == NULL)
- {
- var_ptr = variables[var_name] = (bc_var *) bc_malloc (sizeof (bc_var));
- init_num (&var_ptr->v_value);
- }
- return var_ptr;
- }
-
-
- /* get_array_num returns the address of the bc_num in the array
- structure. If more structure is requried to get to the index,
- this routine does the work to create that structure. VAR_INDEX
- is a zero based index into the arrays storage array. INDEX is
- the index into the bc array. */
-
- bc_num *
- get_array_num (var_index, index)
- int var_index;
- long index;
- {
- bc_var_array *ary_ptr;
- bc_array *a_var;
- bc_array_node *temp;
- int log, ix, ix1;
- int sub [NODE_DEPTH];
-
- /* Get the array entry. */
- ary_ptr = arrays[var_index];
- if (ary_ptr == NULL)
- {
- ary_ptr = arrays[var_index] =
- (bc_var_array *) bc_malloc (sizeof (bc_var_array));
- ary_ptr->a_value = NULL;
- ary_ptr->a_next = NULL;
- ary_ptr->a_param = FALSE;
- }
-
- a_var = ary_ptr->a_value;
- if (a_var == NULL) {
- a_var = ary_ptr->a_value = (bc_array *) bc_malloc (sizeof (bc_array));
- a_var->a_tree = NULL;
- a_var->a_depth = 0;
- }
-
- /* Get the index variable. */
- sub[0] = index & NODE_MASK;
- ix = index >> NODE_SHIFT;
- log = 1;
- while (ix > 0 || log < a_var->a_depth)
- {
- sub[log] = ix & NODE_MASK;
- ix >>= NODE_SHIFT;
- log++;
- }
-
- /* Build any tree that is necessary. */
- while (log > a_var->a_depth)
- {
- temp = (bc_array_node *) bc_malloc (sizeof(bc_array_node));
- if (a_var->a_depth != 0)
- {
- temp->n_items.n_down[0] = a_var->a_tree;
- for (ix=1; ix < NODE_SIZE; ix++)
- temp->n_items.n_down[ix] = NULL;
- }
- else
- {
- for (ix=0; ix < NODE_SIZE; ix++)
- temp->n_items.n_num[ix] = copy_num(_zero_);
- }
- a_var->a_tree = temp;
- a_var->a_depth++;
- }
-
- /* Find the indexed variable. */
- temp = a_var->a_tree;
- while ( log-- > 1)
- {
- ix1 = sub[log];
- if (temp->n_items.n_down[ix1] == NULL)
- {
- temp->n_items.n_down[ix1] =
- (bc_array_node *) bc_malloc (sizeof(bc_array_node));
- temp = temp->n_items.n_down[ix1];
- if (log > 1)
- for (ix=0; ix < NODE_SIZE; ix++)
- temp->n_items.n_down[ix] = NULL;
- else
- for (ix=0; ix < NODE_SIZE; ix++)
- temp->n_items.n_num[ix] = copy_num(_zero_);
- }
- else
- temp = temp->n_items.n_down[ix1];
- }
-
- /* Return the address of the indexed variable. */
- return &(temp->n_items.n_num[sub[0]]);
- }
-
-
- /* Store the top of the execution stack into VAR_NAME.
- This includes the special variables ibase, obase, and scale. */
-
- void
- store_var (var_name)
- int var_name;
- {
- bc_var *var_ptr;
- long temp;
- char toobig;
-
- if (var_name > 2)
- {
- /* It is a simple variable. */
- var_ptr = get_var (var_name);
- if (var_ptr != NULL)
- {
- free_num(&var_ptr->v_value);
- var_ptr->v_value = copy_num (ex_stack->s_num);
- }
- }
- else
- {
- /* It is a special variable... */
- toobig = FALSE;
- if (is_neg (ex_stack->s_num))
- {
- switch (var_name)
- {
- case 0:
- rt_warn ("negative ibase, set to 2");
- temp = 2;
- break;
- case 1:
- rt_warn ("negative obase, set to 2");
- temp = 2;
- break;
- case 2:
- rt_warn ("negative scale, set to 0");
- temp = 0;
- break;
- }
- }
- else
- {
- temp = num2long (ex_stack->s_num);
- if (!is_zero (ex_stack->s_num) && temp == 0)
- toobig = TRUE;
- }
- switch (var_name)
- {
- case 0:
- if (temp < 2 && !toobig)
- {
- i_base = 2;
- rt_warn ("ibase too small, set to 2");
- }
- else
- if (temp > 16 || toobig)
- {
- i_base = 16;
- rt_warn ("ibase too large, set to 16");
- }
- else
- i_base = (int) temp;
- break;
-
- case 1:
- if (temp < 2 && !toobig)
- {
- o_base = 2;
- rt_warn ("obase too small, set to 2");
- }
- else
- if (temp > BC_BASE_MAX || toobig)
- {
- o_base = BC_BASE_MAX;
- rt_warn ("obase too large, set to %d", BC_BASE_MAX);
- }
- else
- o_base = (int) temp;
- break;
-
- case 2:
- /* WARNING: The following if statement may generate a compiler
- warning if INT_MAX == LONG_MAX. This is NOT a problem. */
- if (temp > BC_SCALE_MAX || toobig )
- {
- scale = BC_SCALE_MAX;
- rt_warn ("scale too large, set to %d", BC_SCALE_MAX);
- }
- else
- scale = (int) temp;
- }
- }
- }
-
-
- /* Store the top of the execution stack into array VAR_NAME.
- VAR_NAME is the name of an array, and the next to the top
- of stack for the index into the array. */
-
- void
- store_array (var_name)
- int var_name;
- {
- bc_num *num_ptr;
- long index;
-
- if (!check_stack(2)) return;
- index = num2long (ex_stack->s_next->s_num);
- if (index < 0 || index > BC_DIM_MAX ||
- (index == 0 && !is_zero(ex_stack->s_next->s_num)))
- rt_error ("Array %s subscript out of bounds.", a_names[var_name]);
- else
- {
- num_ptr = get_array_num (var_name, index);
- if (num_ptr != NULL)
- {
- free_num (num_ptr);
- *num_ptr = copy_num (ex_stack->s_num);
- free_num (&ex_stack->s_next->s_num);
- ex_stack->s_next->s_num = ex_stack->s_num;
- init_num (&ex_stack->s_num);
- pop();
- }
- }
- }
-
-
- /* Load a copy of VAR_NAME on to the execution stack. This includes
- the special variables ibase, obase and scale. */
-
- void
- load_var (var_name)
- int var_name;
- {
- bc_var *var_ptr;
-
- switch (var_name)
- {
-
- case 0:
- /* Special variable ibase. */
- push_copy (_zero_);
- int2num (&ex_stack->s_num, i_base);
- break;
-
- case 1:
- /* Special variable obase. */
- push_copy (_zero_);
- int2num (&ex_stack->s_num, o_base);
- break;
-
- case 2:
- /* Special variable scale. */
- push_copy (_zero_);
- int2num (&ex_stack->s_num, scale);
- break;
-
- default:
- /* It is a simple variable. */
- var_ptr = variables[var_name];
- if (var_ptr != NULL)
- push_copy (var_ptr->v_value);
- else
- push_copy (_zero_);
- }
- }
-
-
- /* Load a copy of VAR_NAME on to the execution stack. This includes
- the special variables ibase, obase and scale. */
-
- void
- load_array (var_name)
- int var_name;
- {
- bc_num *num_ptr;
- long index;
-
- if (!check_stack(1)) return;
- index = num2long (ex_stack->s_num);
- if (index < 0 || index > BC_DIM_MAX ||
- (index == 0 && !is_zero(ex_stack->s_num)))
- rt_error ("Array %s subscript out of bounds.", a_names[var_name]);
- else
- {
- num_ptr = get_array_num (var_name, index);
- if (num_ptr != NULL)
- {
- pop();
- push_copy (*num_ptr);
- }
- }
- }
-
-
- /* Decrement VAR_NAME by one. This includes the special variables
- ibase, obase, and scale. */
-
- void
- decr_var (var_name)
- int var_name;
- {
- bc_var *var_ptr;
-
- switch (var_name)
- {
-
- case 0: /* ibase */
- if (i_base > 2)
- i_base--;
- else
- rt_warn ("ibase too small in --");
- break;
-
- case 1: /* obase */
- if (o_base > 2)
- o_base--;
- else
- rt_warn ("obase too small in --");
- break;
-
- case 2: /* scale */
- if (scale > 0)
- scale--;
- else
- rt_warn ("scale can not be negative in -- ");
- break;
-
- default: /* It is a simple variable. */
- var_ptr = get_var (var_name);
- if (var_ptr != NULL)
- bc_sub (var_ptr->v_value,_one_,&var_ptr->v_value);
- }
- }
-
-
- /* Decrement VAR_NAME by one. VAR_NAME is an array, and the top of
- the execution stack is the index and it is popped off the stack. */
-
- void
- decr_array (var_name)
- char var_name;
- {
- bc_num *num_ptr;
- long index;
-
- /* It is an array variable. */
- if (!check_stack (1)) return;
- index = num2long (ex_stack->s_num);
- if (index < 0 || index > BC_DIM_MAX ||
- (index == 0 && !is_zero (ex_stack->s_num)))
- rt_error ("Array %s subscript out of bounds.", a_names[var_name]);
- else
- {
- num_ptr = get_array_num (var_name, index);
- if (num_ptr != NULL)
- {
- pop ();
- bc_sub (*num_ptr, _one_, num_ptr);
- }
- }
- }
-
-
- /* Increment VAR_NAME by one. This includes the special variables
- ibase, obase, and scale. */
-
- void
- incr_var (var_name)
- int var_name;
- {
- bc_var *var_ptr;
-
- switch (var_name)
- {
-
- case 0: /* ibase */
- if (i_base < 16)
- i_base++;
- else
- rt_warn ("ibase too big in ++");
- break;
-
- case 1: /* obase */
- if (o_base < BC_BASE_MAX)
- o_base++;
- else
- rt_warn ("obase too big in ++");
- break;
-
- case 2:
- if (scale < BC_SCALE_MAX)
- scale++;
- else
- rt_warn ("Scale too big in ++");
- break;
-
- default: /* It is a simple variable. */
- var_ptr = get_var (var_name);
- if (var_ptr != NULL)
- bc_add (var_ptr->v_value, _one_, &var_ptr->v_value);
-
- }
- }
-
-
- /* Increment VAR_NAME by one. VAR_NAME is an array and top of
- execution stack is the index and is popped off the stack. */
-
- void
- incr_array (var_name)
- int var_name;
- {
- bc_num *num_ptr;
- long index;
-
- if (!check_stack (1)) return;
- index = num2long (ex_stack->s_num);
- if (index < 0 || index > BC_DIM_MAX ||
- (index == 0 && !is_zero (ex_stack->s_num)))
- rt_error ("Array %s subscript out of bounds.", a_names[var_name]);
- else
- {
- num_ptr = get_array_num (var_name, index);
- if (num_ptr != NULL)
- {
- pop ();
- bc_add (*num_ptr, _one_, num_ptr);
- }
- }
- }
-
-
- /* Routines for processing autos variables and parameters. */
-
- /* NAME is an auto variable that needs to be pushed on its stack. */
-
- void
- auto_var (name)
- int name;
- {
- bc_var *v_temp;
- bc_var_array *a_temp;
- int ix;
-
- if (name > 0)
- {
- /* A simple variable. */
- ix = name;
- v_temp = (bc_var *) bc_malloc (sizeof (bc_var));
- v_temp->v_next = variables[ix];
- init_num (&v_temp->v_value);
- variables[ix] = v_temp;
- }
- else
- {
- /* An array variable. */
- ix = -name;
- a_temp = (bc_var_array *) bc_malloc (sizeof (bc_var_array));
- a_temp->a_next = arrays[ix];
- a_temp->a_value = NULL;
- a_temp->a_param = FALSE;
- arrays[ix] = a_temp;
- }
- }
-
-
- /* Free_a_tree frees everything associated with an array variable tree.
- This is used when popping an array variable off its auto stack. */
-
- void
- free_a_tree ( root, depth )
- bc_array_node *root;
- int depth;
- {
- int ix;
-
- if (root != NULL)
- {
- if (depth > 1)
- for (ix = 0; ix < NODE_SIZE; ix++)
- free_a_tree (root->n_items.n_down[ix], depth-1);
- else
- for (ix = 0; ix < NODE_SIZE; ix++)
- free_num ( &(root->n_items.n_num[ix]));
- free (root);
- }
- }
-
-
- /* LIST is an NULL terminated list of varible names that need to be
- popped off their auto stacks. */
-
- void
- pop_vars (list)
- arg_list *list;
- {
- bc_var *v_temp;
- bc_var_array *a_temp;
- int ix;
-
- while (list != NULL)
- {
- ix = list->av_name;
- if (ix > 0)
- {
- /* A simple variable. */
- v_temp = variables[ix];
- if (v_temp != NULL)
- {
- variables[ix] = v_temp->v_next;
- free_num (&v_temp->v_value);
- free (v_temp);
- }
- }
- else
- {
- /* An array variable. */
- ix = -ix;
- a_temp = arrays[ix];
- if (a_temp != NULL)
- {
- arrays[ix] = a_temp->a_next;
- if (!a_temp->a_param && a_temp->a_value != NULL)
- {
- free_a_tree (a_temp->a_value->a_tree,
- a_temp->a_value->a_depth);
- free (a_temp->a_value);
- }
- free (a_temp);
- }
- }
- list = list->next;
- }
- }
-
-
- /* A call is being made to FUNC. The call types are at PC. Process
- the parameters by doing an auto on the parameter variable and then
- store the value at the new variable or put a pointer the the array
- variable. */
-
- void
- process_params (pc, func)
- program_counter *pc;
- int func;
- {
- char ch;
- arg_list *params;
- char warned = FALSE;
- int ix, ix1;
- bc_var *v_temp;
- bc_var_array *a_src, *a_dest;
- bc_num *n_temp;
-
- /* Get the parameter names from the function. */
- params = functions[func].f_params;
-
- while ((ch = byte(pc)) != ':')
- {
- if (params != NULL)
- {
- if ((ch == '0') && params->av_name > 0)
- {
- /* A simple variable. */
- ix = params->av_name;
- v_temp = (bc_var *) bc_malloc (sizeof(bc_var));
- v_temp->v_next = variables[ix];
- v_temp->v_value = ex_stack->s_num;
- init_num (&ex_stack->s_num);
- variables[ix] = v_temp;
- }
- else
- if ((ch == '1') && (params->av_name < 0))
- {
- /* The variables is an array variable. */
-
- /* Compute source index and make sure some structure exists. */
- ix = (int) num2long (ex_stack->s_num);
- n_temp = get_array_num (ix, 0);
-
- /* Push a new array and Compute Destination index */
- auto_var (params->av_name);
- ix1 = -params->av_name;
-
- /* Set up the correct pointers in the structure. */
- if (ix == ix1)
- a_src = arrays[ix]->a_next;
- else
- a_src = arrays[ix];
- a_dest = arrays[ix1];
- a_dest->a_param = TRUE;
- a_dest->a_value = a_src->a_value;
- }
- else
- {
- if (params->av_name < 0)
- rt_error ("Parameter type mismatch parameter %s.",
- a_names[-params->av_name]);
- else
- rt_error ("Parameter type mismatch, parameter %s.",
- v_names[params->av_name]);
- params++;
- }
- pop ();
- }
- else
- {
- if (!warned)
- {
- rt_error ("Parameter number mismatch");
- warned = TRUE;
- }
- }
- params = params->next;
- }
- if (params != NULL)
- rt_error ("Parameter number mismatch");
- }
-