#include "bcdefs.h"
#include <signal.h>
#include "global.h"
#include "proto.h"
int had_sigint;
void
stop_execution (sig)
int sig;
{
had_sigint = TRUE;
printf ("\n");
rt_error ("interrupted execution");
}
unsigned char
byte (pc)
program_counter *pc;
{
return (functions[pc->pc_func].f_body[pc->pc_addr++]);
}
void
execute ()
{
int label_num, l_gp, l_off;
bc_label_group *gp;
char inst, ch;
int new_func;
int var_name;
int const_base;
bc_num temp_num;
arg_list *auto_list;
pc.pc_func = 0;
pc.pc_addr = 0;
runtime_error = FALSE;
bc_init_num (&temp_num);
if (interactive)
{
signal (SIGINT, stop_execution);
had_sigint = FALSE;
}
while (pc.pc_addr < functions[pc.pc_func].f_code_size && !runtime_error)
{
inst = byte(&pc);
#if DEBUG > 3
{
int depth; estack_rec *temp = ex_stack;
printf ("func=%d addr=%d inst=%c\n",pc.pc_func, pc.pc_addr, inst);
if (temp == NULL) printf ("empty stack.\n", inst);
else
{
depth = 1;
while (temp != NULL)
{
printf (" %d = ", depth);
bc_out_num (temp->s_num, 10, out_char, std_only);
depth++;
temp = temp->s_next;
}
out_char ('\n');
}
}
#endif
switch ( inst )
{
case 'A' :
var_name = byte(&pc);
if ((var_name & 0x80) != 0)
var_name = ((var_name & 0x7f) << 8) + byte(&pc);
incr_array (var_name);
break;
case 'B' :
case 'Z' :
c_code = !bc_is_zero (ex_stack->s_num);
pop ();
case 'J' :
label_num = byte(&pc);
label_num += byte(&pc) << 8;
if (inst == 'J' || (inst == 'B' && c_code)
|| (inst == 'Z' && !c_code)) {
gp = functions[pc.pc_func].f_label;
l_gp = label_num >> BC_LABEL_LOG;
l_off = label_num % BC_LABEL_GROUP;
while (l_gp-- > 0) gp = gp->l_next;
pc.pc_addr = gp->l_adrs[l_off];
}
break;
case 'C' :
new_func = byte(&pc);
if ((new_func & 0x80) != 0)
new_func = ((new_func & 0x7f) << 8) + byte(&pc);
if (!functions[new_func].f_defined)
{
rt_error ("Function %s not defined.", f_names[new_func]);
break;
}
process_params (&pc, new_func);
for (auto_list = functions[new_func].f_autos;
auto_list != NULL;
auto_list = auto_list->next)
auto_var (auto_list->av_name);
fpush (pc.pc_func);
fpush (pc.pc_addr);
fpush (i_base);
pc.pc_func = new_func;
pc.pc_addr = 0;
break;
case 'D' :
push_copy (ex_stack->s_num);
break;
case 'K' :
if (pc.pc_func == 0)
const_base = i_base;
else
const_base = fn_stack->s_val;
if (const_base == 10)
push_b10_const (&pc);
else
push_constant (prog_char, const_base);
break;
case 'L' :
var_name = byte(&pc);
if ((var_name & 0x80) != 0)
var_name = ((var_name & 0x7f) << 8) + byte(&pc);
load_array (var_name);
break;
case 'M' :
var_name = byte(&pc);
if ((var_name & 0x80) != 0)
var_name = ((var_name & 0x7f) << 8) + byte(&pc);
decr_array (var_name);
break;
case 'O' :
while ((ch = byte(&pc)) != '"')
if (ch != '\\')
out_schar (ch);
else
{
ch = byte(&pc);
if (ch == '"') break;
switch (ch)
{
case 'a': out_schar (007); break;
case 'b': out_schar ('\b'); break;
case 'f': out_schar ('\f'); break;
case 'n': out_schar ('\n'); break;
case 'q': out_schar ('"'); break;
case 'r': out_schar ('\r'); break;
case 't': out_schar ('\t'); break;
case '\\': out_schar ('\\'); break;
default: break;
}
}
fflush (stdout);
break;
case 'R' :
if (pc.pc_func != 0)
{
pop_vars(functions[pc.pc_func].f_autos);
pop_vars(functions[pc.pc_func].f_params);
fpop ();
pc.pc_addr = fpop ();
pc.pc_func = fpop ();
}
else
rt_error ("Return from main program.");
break;
case 'S' :
var_name = byte(&pc);
if ((var_name & 0x80) != 0)
var_name = ((var_name & 0x7f ) << 8) + byte(&pc);
store_array (var_name);
break;
case 'T' :
c_code = bc_is_zero (ex_stack->s_num);
assign (c_code);
break;
case 'W' :
case 'P' :
bc_out_num (ex_stack->s_num, o_base, out_char, std_only);
if (inst == 'W') out_char ('\n');
store_var (4);
fflush (stdout);
pop ();
break;
case 'c' :
new_func = byte(&pc);
switch (new_func)
{
case 'L':
if (ex_stack->s_num->n_len == 1 &&
ex_stack->s_num->n_scale != 0 &&
ex_stack->s_num->n_value[0] == 0 )
bc_int2num (&ex_stack->s_num, ex_stack->s_num->n_scale);
else
bc_int2num (&ex_stack->s_num, ex_stack->s_num->n_len
+ ex_stack->s_num->n_scale);
break;
case 'S':
bc_int2num (&ex_stack->s_num, ex_stack->s_num->n_scale);
break;
case 'R':
if (!bc_sqrt (&ex_stack->s_num, scale))
rt_error ("Square root of a negative number");
break;
case 'I':
push_constant (input_char, i_base);
break;
}
break;
case 'd' :
var_name = byte(&pc);
if ((var_name & 0x80) != 0)
var_name = ((var_name & 0x7f) << 8) + byte(&pc);
decr_var (var_name);
break;
case 'h' :
exit (0);
case 'i' :
var_name = byte(&pc);
if ((var_name & 0x80) != 0)
var_name = ((var_name & 0x7f) << 8) + byte(&pc);
incr_var (var_name);
break;
case 'l' :
var_name = byte(&pc);
if ((var_name & 0x80) != 0)
var_name = ((var_name & 0x7f) << 8) + byte(&pc);
load_var (var_name);
break;
case 'n' :
bc_sub (_zero_, ex_stack->s_num, &ex_stack->s_num, 0);
break;
case 'p' :
pop ();
break;
case 's' :
var_name = byte(&pc);
if ((var_name & 0x80) != 0)
var_name = ((var_name & 0x7f) << 8) + byte(&pc);
store_var (var_name);
break;
case 'w' :
while ((ch = byte(&pc)) != '"') out_schar (ch);
fflush (stdout);
break;
case 'x' :
if (check_stack(2)) {
bc_num temp = ex_stack->s_num;
ex_stack->s_num = ex_stack->s_next->s_num;
ex_stack->s_next->s_num = temp;
}
break;
case '0' :
push_copy (_zero_);
break;
case '1' :
push_copy (_one_);
break;
case '!' :
c_code = bc_is_zero (ex_stack->s_num);
assign (c_code);
break;
case '&' :
if (check_stack(2))
{
c_code = !bc_is_zero (ex_stack->s_next->s_num)
&& !bc_is_zero (ex_stack->s_num);
pop ();
assign (c_code);
}
break;
case '|' :
if (check_stack(2))
{
c_code = !bc_is_zero (ex_stack->s_next->s_num)
|| !bc_is_zero (ex_stack->s_num);
pop ();
assign (c_code);
}
break;
case '+' :
if (check_stack(2))
{
bc_add (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num, 0);
pop();
pop();
push_num (temp_num);
bc_init_num (&temp_num);
}
break;
case '-' :
if (check_stack(2))
{
bc_sub (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num, 0);
pop();
pop();
push_num (temp_num);
bc_init_num (&temp_num);
}
break;
case '*' :
if (check_stack(2))
{
bc_multiply (ex_stack->s_next->s_num, ex_stack->s_num,
&temp_num, scale);
pop();
pop();
push_num (temp_num);
bc_init_num (&temp_num);
}
break;
case '/' :
if (check_stack(2))
{
if (bc_divide (ex_stack->s_next->s_num,
ex_stack->s_num, &temp_num, scale) == 0)
{
pop();
pop();
push_num (temp_num);
bc_init_num (&temp_num);
}
else
rt_error ("Divide by zero");
}
break;
case '%' :
if (check_stack(2))
{
if (bc_is_zero (ex_stack->s_num))
rt_error ("Modulo by zero");
else
{
bc_modulo (ex_stack->s_next->s_num,
ex_stack->s_num, &temp_num, scale);
pop();
pop();
push_num (temp_num);
bc_init_num (&temp_num);
}
}
break;
case '^' :
if (check_stack(2))
{
bc_raise (ex_stack->s_next->s_num,
ex_stack->s_num, &temp_num, scale);
if (bc_is_zero (ex_stack->s_next->s_num) && bc_is_neg (ex_stack->s_num))
rt_error ("divide by zero");
pop();
pop();
push_num (temp_num);
bc_init_num (&temp_num);
}
break;
case '=' :
if (check_stack(2))
{
c_code = bc_compare (ex_stack->s_next->s_num,
ex_stack->s_num) == 0;
pop ();
assign (c_code);
}
break;
case '#' :
if (check_stack(2))
{
c_code = bc_compare (ex_stack->s_next->s_num,
ex_stack->s_num) != 0;
pop ();
assign (c_code);
}
break;
case '<' :
if (check_stack(2))
{
c_code = bc_compare (ex_stack->s_next->s_num,
ex_stack->s_num) == -1;
pop ();
assign (c_code);
}
break;
case '{' :
if (check_stack(2))
{
c_code = bc_compare (ex_stack->s_next->s_num,
ex_stack->s_num) <= 0;
pop ();
assign (c_code);
}
break;
case '>' :
if (check_stack(2))
{
c_code = bc_compare (ex_stack->s_next->s_num,
ex_stack->s_num) == 1;
pop ();
assign (c_code);
}
break;
case '}' :
if (check_stack(2))
{
c_code = bc_compare (ex_stack->s_next->s_num,
ex_stack->s_num) >= 0;
pop ();
assign (c_code);
}
break;
default :
rt_error ("bad instruction: inst=%c", inst);
}
}
while (pc.pc_func != 0)
{
pop_vars(functions[pc.pc_func].f_autos);
pop_vars(functions[pc.pc_func].f_params);
fpop ();
pc.pc_addr = fpop ();
pc.pc_func = fpop ();
}
while (ex_stack != NULL) pop();
if (interactive)
{
signal (SIGINT, use_quit);
if (had_sigint)
printf ("Interruption completed.\n");
}
}
char
prog_char ()
{
return byte(&pc);
}
char
input_char ()
{
char in_ch;
in_ch = getchar();
if (in_ch == '\\')
{
in_ch = getchar();
if (in_ch == '\n')
in_ch = getchar();
}
if (isdigit((int)in_ch))
return (in_ch - '0');
if (in_ch >= 'A' && in_ch <= 'F')
return (in_ch + 10 - 'A');
if (in_ch >= 'a' && in_ch <= 'f')
return (in_ch + 10 - 'a');
if (in_ch == '.' || in_ch == '+' || in_ch == '-')
return (in_ch);
if (in_ch <= ' ')
return (' ');
return (':');
}
void
push_constant (in_char, conv_base)
char (*in_char)(VOID);
int conv_base;
{
int digits;
bc_num build, temp, result, mult, divisor;
char in_ch, first_ch;
char negative;
bc_init_num (&temp);
bc_init_num (&result);
bc_init_num (&mult);
build = bc_copy_num (_zero_);
negative = FALSE;
bc_int2num (&mult, conv_base);
in_ch = in_char();
while (in_ch == ' ')
in_ch = in_char();
if (in_ch == '+')
in_ch = in_char();
else
if (in_ch == '-')
{
negative = TRUE;
in_ch = in_char();
}
if (in_ch < 16)
{
first_ch = in_ch;
in_ch = in_char();
if (in_ch < 16 && first_ch >= conv_base)
first_ch = conv_base - 1;
bc_int2num (&build, (int) first_ch);
}
while (in_ch < 16)
{
if (in_ch < 16 && in_ch >= conv_base) in_ch = conv_base-1;
bc_multiply (build, mult, &result, 0);
bc_int2num (&temp, (int) in_ch);
bc_add (result, temp, &build, 0);
in_ch = in_char();
}
if (in_ch == '.')
{
in_ch = in_char();
if (in_ch >= conv_base) in_ch = conv_base-1;
bc_free_num (&result);
bc_free_num (&temp);
divisor = bc_copy_num (_one_);
result = bc_copy_num (_zero_);
digits = 0;
while (in_ch < 16)
{
bc_multiply (result, mult, &result, 0);
bc_int2num (&temp, (int) in_ch);
bc_add (result, temp, &result, 0);
bc_multiply (divisor, mult, &divisor, 0);
digits++;
in_ch = in_char();
if (in_ch < 16 && in_ch >= conv_base) in_ch = conv_base-1;
}
bc_divide (result, divisor, &result, digits);
bc_add (build, result, &build, 0);
}
if (negative)
bc_sub (_zero_, build, &build, 0);
push_num (build);
bc_free_num (&temp);
bc_free_num (&result);
bc_free_num (&mult);
}
void
push_b10_const (pc)
program_counter *pc;
{
bc_num build;
program_counter look_pc;
int kdigits, kscale;
char inchar;
char *ptr;
look_pc = *pc;
kdigits = 0;
kscale = 0;
inchar = byte (&look_pc);
while (inchar != '.' && inchar != ':')
{
kdigits++;
inchar = byte(&look_pc);
}
if (inchar == '.' )
{
inchar = byte(&look_pc);
while (inchar != ':')
{
kscale++;
inchar = byte(&look_pc);
}
}
inchar = byte(pc);
if (kdigits == 1 && kscale == 0)
{
if (inchar == 0)
{
push_copy (_zero_);
inchar = byte(pc);
return;
}
if (inchar == 1) {
push_copy (_one_);
inchar = byte(pc);
return;
}
if (inchar > 9)
{
bc_init_num (&build);
bc_int2num (&build, inchar);
push_num (build);
inchar = byte(pc);
return;
}
}
if (kdigits == 0)
{
build = bc_new_num (1,kscale);
ptr = build->n_value;
*ptr++ = 0;
}
else
{
build = bc_new_num (kdigits,kscale);
ptr = build->n_value;
}
while (inchar != ':')
{
if (inchar != '.')
{
if (inchar > 9)
*ptr++ = 9;
else
*ptr++ = inchar;
}
inchar = byte(pc);
}
push_num (build);
}
void
assign (c_code)
char c_code;
{
bc_free_num (&ex_stack->s_num);
if (c_code)
ex_stack->s_num = bc_copy_num (_one_);
else
ex_stack->s_num = bc_copy_num (_zero_);
}