/* storage.c: Code and data storage manipulations. This includes labels. */
/* This file is part of bc written for MINIX.
Copyright (C) 1991 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:
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
/* Initialize the storage at the beginning of the run. */
/* Functions: we start with none and ask for more. */
/* Three functions for increasing the number of functions, variables, or
arrays that are needed. This adds another 32 of the requested object. */
/* Save old information. */
/* Add a fixed amount and allocate new space. */
functions
= (bc_function
*) bc_malloc (f_count
*sizeof (bc_function
));
f_names
= (char **) bc_malloc (f_count
*sizeof (char *));
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
++)
for (indx2
= 0; indx2
< BC_MAX_SEGS
; indx2
++)
f
->f_body
[indx2
] = NULL
;
/* Free the old elements. */
/* Save the old values. */
/* Increment by a fixed amount and allocate. */
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
++)
/* Free the old elements. */
/* Save the old values. */
/* Increment by a fixed amount and allocate. */
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
++)
/* Free the old elements. */
/* clear_func clears out function FUNC and makes it ready to redefine. */
/* Set the pointer to the function. */
/* Clear the code segments. */
for (indx
= 0; indx
< BC_MAX_SEGS
; indx
++)
if (f
->f_body
[indx
] != NULL
)
while (f
->f_label
!= NULL
)
/* Pop the function execution stack and return the top. */
/* Push VAL on to the function stack. */
temp
= (fstack_rec
*) bc_malloc (sizeof (fstack_rec
));
/* Pop and discard the top element of the regular execution stack. */
/* Push a copy of NUM on to the regular execution stack. */
temp
= (estack_rec
*) bc_malloc (sizeof (estack_rec
));
temp
->s_num
= copy_num (num
);
/* Push NUM on to the regular execution stack. Do NOT push a copy. */
temp
= (estack_rec
*) bc_malloc (sizeof (estack_rec
));
/* Make sure the ex_stack has at least DEPTH elements on it.
Return TRUE if it has at least DEPTH elements, otherwise
while ((temp
!= NULL
) && (depth
> 0))
rt_error ("Stack error.");
/* The following routines manipulate simple variables and
/* get_var returns a pointer to the variable VAR_NAME. If one does not
exist, one is created. */
var_ptr
= variables
[var_name
];
var_ptr
= variables
[var_name
] = (bc_var
*) bc_malloc (sizeof (bc_var
));
init_num (&var_ptr
->v_value
);
/* 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. */
get_array_num (var_index
, index
)
/* Get the array entry. */
ary_ptr
= arrays
[var_index
];
ary_ptr
= arrays
[var_index
] =
(bc_var_array
*) bc_malloc (sizeof (bc_var_array
));
ary_ptr
->a_param
= FALSE
;
a_var
= ary_ptr
->a_value
;
a_var
= ary_ptr
->a_value
= (bc_array
*) bc_malloc (sizeof (bc_array
));
/* Get the index variable. */
sub
[0] = index
& NODE_MASK
;
ix
= index
>> NODE_SHIFT
;
while (ix
> 0 || log
< a_var
->a_depth
)
sub
[log
] = ix
& NODE_MASK
;
/* Build any tree that is necessary. */
while (log
> a_var
->a_depth
)
temp
= (bc_array_node
*) bc_malloc (sizeof(bc_array_node
));
temp
->n_items
.n_down
[0] = a_var
->a_tree
;
for (ix
=1; ix
< NODE_SIZE
; ix
++)
temp
->n_items
.n_down
[ix
] = NULL
;
for (ix
=0; ix
< NODE_SIZE
; ix
++)
temp
->n_items
.n_num
[ix
] = copy_num(_zero_
);
/* Find the indexed variable. */
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
];
for (ix
=0; ix
< NODE_SIZE
; ix
++)
temp
->n_items
.n_down
[ix
] = NULL
;
for (ix
=0; ix
< NODE_SIZE
; ix
++)
temp
->n_items
.n_num
[ix
] = copy_num(_zero_
);
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. */
/* It is a simple variable. */
var_ptr
= get_var (var_name
);
free_num(&var_ptr
->v_value
);
var_ptr
->v_value
= copy_num (ex_stack
->s_num
);
/* It is a special variable... */
if (is_neg (ex_stack
->s_num
))
rt_warn ("negative ibase, set to 2");
rt_warn ("negative obase, set to 2");
rt_warn ("negative scale, set to 0");
temp
= num2long (ex_stack
->s_num
);
if (!is_zero (ex_stack
->s_num
) && temp
== 0)
rt_warn ("ibase too small, set to 2");
rt_warn ("ibase too large, set to 16");
rt_warn ("obase too small, set to 2");
if (temp
> BC_BASE_MAX
|| toobig
)
rt_warn ("obase too large, set to %d", BC_BASE_MAX
);
/* 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
)
rt_warn ("scale too large, set to %d", BC_SCALE_MAX
);
/* 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. */
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
]);
num_ptr
= get_array_num (var_name
, index
);
*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
);
/* Load a copy of VAR_NAME on to the execution stack. This includes
the special variables ibase, obase and scale. */
/* Special variable ibase. */
int2num (&ex_stack
->s_num
, i_base
);
/* Special variable obase. */
int2num (&ex_stack
->s_num
, o_base
);
/* Special variable scale. */
int2num (&ex_stack
->s_num
, scale
);
/* It is a simple variable. */
var_ptr
= variables
[var_name
];
push_copy (var_ptr
->v_value
);
/* Load a copy of VAR_NAME on to the execution stack. This includes
the special variables ibase, obase and scale. */
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
]);
num_ptr
= get_array_num (var_name
, index
);
/* Decrement VAR_NAME by one. This includes the special variables
ibase, obase, and scale. */
rt_warn ("ibase too small in --");
rt_warn ("obase too small in --");
rt_warn ("scale can not be negative in -- ");
default: /* It is a simple variable. */
var_ptr
= get_var (var_name
);
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. */
/* 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
]);
num_ptr
= get_array_num (var_name
, index
);
bc_sub (*num_ptr
, _one_
, num_ptr
);
/* Increment VAR_NAME by one. This includes the special variables
ibase, obase, and scale. */
rt_warn ("ibase too big in ++");
if (o_base
< BC_BASE_MAX
)
rt_warn ("obase too big in ++");
if (scale
< BC_SCALE_MAX
)
rt_warn ("Scale too big in ++");
default: /* It is a simple variable. */
var_ptr
= get_var (var_name
);
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. */
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
]);
num_ptr
= get_array_num (var_name
, index
);
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. */
v_temp
= (bc_var
*) bc_malloc (sizeof (bc_var
));
v_temp
->v_next
= variables
[ix
];
init_num (&v_temp
->v_value
);
a_temp
= (bc_var_array
*) bc_malloc (sizeof (bc_var_array
));
a_temp
->a_next
= arrays
[ix
];
/* Free_a_tree frees everything associated with an array variable tree.
This is used when popping an array variable off its auto stack. */
free_a_tree ( root
, depth
)
for (ix
= 0; ix
< NODE_SIZE
; ix
++)
free_a_tree (root
->n_items
.n_down
[ix
], depth
-1);
for (ix
= 0; ix
< NODE_SIZE
; ix
++)
free_num ( &(root
->n_items
.n_num
[ix
]));
/* LIST is an NULL terminated list of varible names that need to be
popped off their auto stacks. */
variables
[ix
] = v_temp
->v_next
;
free_num (&v_temp
->v_value
);
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
);
/* 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
process_params (pc
, func
)
bc_var_array
*a_src
, *a_dest
;
/* Get the parameter names from the function. */
params
= functions
[func
].f_params
;
while ((ch
= byte(pc
)) != ':')
if ((ch
== '0') && params
->av_name
> 0)
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
);
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
);
/* Set up the correct pointers in the structure. */
a_src
= arrays
[ix
]->a_next
;
a_dest
->a_value
= a_src
->a_value
;
rt_error ("Parameter type mismatch parameter %s.",
a_names
[-params
->av_name
]);
rt_error ("Parameter type mismatch, parameter %s.",
v_names
[params
->av_name
]);
rt_error ("Parameter number mismatch");
rt_error ("Parameter number mismatch");