#include "bcdefs.h"
#include "global.h"
#include "proto.h"
void
init_storage ()
{
f_count = 0;
more_functions ();
f_names[0] = "(main)";
v_count = 0;
more_variables ();
a_count = 0;
more_arrays ();
ex_stack = NULL;
fn_stack = NULL;
i_base = 10;
o_base = 10;
scale = 0;
#if defined(READLINE) || defined(LIBEDIT)
n_history = -1;
#endif
c_code = FALSE;
bc_init_numbers();
}
void
more_functions (VOID)
{
int old_count;
int indx;
bc_function *old_f;
bc_function *f;
char **old_names;
old_count = f_count;
old_f = functions;
old_names = f_names;
f_count += STORE_INCR;
functions = (bc_function *) bc_malloc (f_count*sizeof (bc_function));
f_names = (char **) bc_malloc (f_count*sizeof (char *));
for (indx = 0; indx < old_count; indx++)
{
functions[indx] = old_f[indx];
f_names[indx] = old_names[indx];
}
for (; indx < f_count; indx++)
{
f = &functions[indx];
f->f_defined = FALSE;
f->f_body = (char *) bc_malloc (BC_START_SIZE);
f->f_body_size = BC_START_SIZE;
f->f_code_size = 0;
f->f_label = NULL;
f->f_autos = NULL;
f->f_params = NULL;
}
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;
old_count = v_count;
old_var = variables;
old_names = v_names;
v_count += STORE_INCR;
variables = (bc_var **) bc_malloc (v_count*sizeof(bc_var *));
v_names = (char **) bc_malloc (v_count*sizeof(char *));
for (indx = 3; indx < old_count; indx++)
variables[indx] = old_var[indx];
for (; indx < v_count; indx++)
variables[indx] = NULL;
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;
old_count = a_count;
old_ary = arrays;
old_names = a_names;
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 *));
for (indx = 1; indx < old_count; indx++)
arrays[indx] = old_ary[indx];
for (; indx < v_count; indx++)
arrays[indx] = NULL;
if (old_count != 0)
{
free (old_ary);
free (old_names);
}
}
void
clear_func (func)
int func;
{
bc_function *f;
bc_label_group *lg;
f = &functions[func];
f->f_defined = FALSE;
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;
}
}
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);
}
else
{
retval = 0;
rt_error ("function stack underflow, contact maintainer.");
}
return (retval);
}
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;
}
void
pop ()
{
estack_rec *temp;
if (ex_stack != NULL)
{
temp = ex_stack;
ex_stack = temp->s_next;
bc_free_num (&temp->s_num);
free (temp);
}
}
void
push_copy (num)
bc_num num;
{
estack_rec *temp;
temp = (estack_rec *) bc_malloc (sizeof (estack_rec));
temp->s_num = bc_copy_num (num);
temp->s_next = ex_stack;
ex_stack = temp;
}
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;
}
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;
}
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));
bc_init_num (&var_ptr->v_value);
}
return var_ptr;
}
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];
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;
}
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++;
}
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] = bc_copy_num(_zero_);
}
a_var->a_tree = temp;
a_var->a_depth++;
}
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] = bc_copy_num(_zero_);
}
else
temp = temp->n_items.n_down[ix1];
}
return &(temp->n_items.n_num[sub[0]]);
}
void
store_var (var_name)
int var_name;
{
bc_var *var_ptr;
long temp;
char toobig;
if (var_name > 3)
{
var_ptr = get_var (var_name);
if (var_ptr != NULL)
{
bc_free_num(&var_ptr->v_value);
var_ptr->v_value = bc_copy_num (ex_stack->s_num);
}
}
else
{
toobig = FALSE;
temp = 0;
if (bc_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;
#if defined(READLINE) || defined(LIBEDIT)
case 3:
temp = -1;
break;
#endif
}
}
else
{
temp = bc_num2long (ex_stack->s_num);
if (!bc_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:
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;
break;
#if defined(READLINE) || defined(LIBEDIT)
case 3:
if (toobig)
{
temp = -1;
rt_warn ("history too large, set to unlimited");
UNLIMIT_HISTORY;
}
else
{
n_history = temp;
if (temp < 0)
UNLIMIT_HISTORY;
else
HISTORY_SIZE(n_history);
}
#endif
}
}
}
void
store_array (var_name)
int var_name;
{
bc_num *num_ptr;
long index;
if (!check_stack(2)) return;
index = bc_num2long (ex_stack->s_next->s_num);
if (index < 0 || index > BC_DIM_MAX ||
(index == 0 && !bc_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)
{
bc_free_num (num_ptr);
*num_ptr = bc_copy_num (ex_stack->s_num);
bc_free_num (&ex_stack->s_next->s_num);
ex_stack->s_next->s_num = ex_stack->s_num;
bc_init_num (&ex_stack->s_num);
pop();
}
}
}
void
load_var (var_name)
int var_name;
{
bc_var *var_ptr;
switch (var_name)
{
case 0:
push_copy (_zero_);
bc_int2num (&ex_stack->s_num, i_base);
break;
case 1:
push_copy (_zero_);
bc_int2num (&ex_stack->s_num, o_base);
break;
case 2:
push_copy (_zero_);
bc_int2num (&ex_stack->s_num, scale);
break;
#if defined(READLINE) || defined(LIBEDIT)
case 3:
push_copy (_zero_);
bc_int2num (&ex_stack->s_num, n_history);
break;
#endif
default:
var_ptr = variables[var_name];
if (var_ptr != NULL)
push_copy (var_ptr->v_value);
else
push_copy (_zero_);
}
}
void
load_array (var_name)
int var_name;
{
bc_num *num_ptr;
long index;
if (!check_stack(1)) return;
index = bc_num2long (ex_stack->s_num);
if (index < 0 || index > BC_DIM_MAX ||
(index == 0 && !bc_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);
}
}
}
void
decr_var (var_name)
int var_name;
{
bc_var *var_ptr;
switch (var_name)
{
case 0:
if (i_base > 2)
i_base--;
else
rt_warn ("ibase too small in --");
break;
case 1:
if (o_base > 2)
o_base--;
else
rt_warn ("obase too small in --");
break;
case 2:
if (scale > 0)
scale--;
else
rt_warn ("scale can not be negative in -- ");
break;
#if defined(READLINE) || defined(LIBEDIT)
case 3:
n_history--;
if (n_history >= 0)
HISTORY_SIZE(n_history);
else
{
n_history = -1;
rt_warn ("history is negative, set to unlimited");
UNLIMIT_HISTORY;
}
#endif
default:
var_ptr = get_var (var_name);
if (var_ptr != NULL)
bc_sub (var_ptr->v_value,_one_,&var_ptr->v_value, 0);
}
}
void
decr_array (var_name)
int var_name;
{
bc_num *num_ptr;
long index;
if (!check_stack (1)) return;
index = bc_num2long (ex_stack->s_num);
if (index < 0 || index > BC_DIM_MAX ||
(index == 0 && !bc_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, 0);
}
}
}
void
incr_var (var_name)
int var_name;
{
bc_var *var_ptr;
switch (var_name)
{
case 0:
if (i_base < 16)
i_base++;
else
rt_warn ("ibase too big in ++");
break;
case 1:
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;
#if defined(READLINE) || defined(LIBEDIT)
case 3:
n_history++;
if (n_history > 0)
HISTORY_SIZE(n_history);
else
{
n_history = -1;
rt_warn ("history set to unlimited");
UNLIMIT_HISTORY;
}
#endif
default:
var_ptr = get_var (var_name);
if (var_ptr != NULL)
bc_add (var_ptr->v_value, _one_, &var_ptr->v_value, 0);
}
}
void
incr_array (var_name)
int var_name;
{
bc_num *num_ptr;
long index;
if (!check_stack (1)) return;
index = bc_num2long (ex_stack->s_num);
if (index < 0 || index > BC_DIM_MAX ||
(index == 0 && !bc_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, 0);
}
}
}
void
auto_var (name)
int name;
{
bc_var *v_temp;
bc_var_array *a_temp;
int ix;
if (name > 0)
{
ix = name;
v_temp = (bc_var *) bc_malloc (sizeof (bc_var));
v_temp->v_next = variables[ix];
bc_init_num (&v_temp->v_value);
variables[ix] = v_temp;
}
else
{
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;
}
}
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++)
bc_free_num ( &(root->n_items.n_num[ix]));
free (root);
}
}
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)
{
v_temp = variables[ix];
if (v_temp != NULL)
{
variables[ix] = v_temp->v_next;
bc_free_num (&v_temp->v_value);
free (v_temp);
}
}
else
{
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;
}
}
bc_array_node *
copy_tree (ary_node, depth)
bc_array_node *ary_node;
int depth;
{
bc_array_node *res = (bc_array_node *) bc_malloc (sizeof(bc_array_node));
int i;
if (depth > 1)
for (i=0; i<NODE_SIZE; i++)
if (ary_node->n_items.n_down[i] != NULL)
res->n_items.n_down[i] =
copy_tree (ary_node->n_items.n_down[i], depth - 1);
else
res->n_items.n_down[i] = NULL;
else
for (i=0; i<NODE_SIZE; i++)
if (ary_node->n_items.n_num[i] != NULL)
res->n_items.n_num[i] = bc_copy_num (ary_node->n_items.n_num[i]);
else
res->n_items.n_num[i] = NULL;
return res;
}
bc_array *
copy_array (ary)
bc_array *ary;
{
bc_array *res = (bc_array *) bc_malloc (sizeof(bc_array));
res->a_depth = ary->a_depth;
res->a_tree = copy_tree (ary->a_tree, ary->a_depth);
return (res);
}
void
process_params (pc, func)
program_counter *pc;
int func;
{
char ch;
arg_list *params;
int ix, ix1;
bc_var *v_temp;
bc_var_array *a_src, *a_dest;
bc_num *n_temp;
params = functions[func].f_params;
while ((ch = byte(pc)) != ':')
{
if (params != NULL)
{
if ((ch == '0') && params->av_name > 0)
{
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;
bc_init_num (&ex_stack->s_num);
variables[ix] = v_temp;
}
else
if ((ch == '1') && (params->av_name < 0))
{
ix = (int) bc_num2long (ex_stack->s_num);
n_temp = get_array_num (ix, 0);
auto_var (params->av_name);
ix1 = -params->av_name;
if (ix == ix1)
a_src = arrays[ix]->a_next;
else
a_src = arrays[ix];
a_dest = arrays[ix1];
if (params->arg_is_var)
{
a_dest->a_param = TRUE;
a_dest->a_value = a_src->a_value;
}
else
{
a_dest->a_param = FALSE;
a_dest->a_value = copy_array (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
{
rt_error ("Parameter number mismatch");
return;
}
params = params->next;
}
if (params != NULL)
rt_error ("Parameter number mismatch");
}