|
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 |
/* execute.c - run a bc program. */
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
#include "bcdefs.h"
|
|
Packit |
70b277 |
#include <signal.h>
|
|
Packit |
70b277 |
#include "proto.h"
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* The SIGINT interrupt handling routine. */
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
int had_sigint;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
void
|
|
Packit |
70b277 |
stop_execution ( int sig )
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
had_sigint = TRUE;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Get the current byte and advance the PC counter. */
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
unsigned char
|
|
Packit |
70b277 |
byte ( program_counter *p )
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
return (functions[p->pc_func].f_body[p->pc_addr++]);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* The routine that actually runs the machine. */
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
void
|
|
Packit |
70b277 |
execute (void)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
unsigned long label_num, l_gp, l_off;
|
|
Packit |
70b277 |
bc_label_group *gp;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
char inst, ch;
|
|
Packit |
70b277 |
long new_func;
|
|
Packit |
70b277 |
long var_name;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
long const_base;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
bc_num temp_num;
|
|
Packit |
70b277 |
arg_list *auto_list;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Initialize this run... */
|
|
Packit |
70b277 |
pc.pc_func = 0;
|
|
Packit |
70b277 |
pc.pc_addr = 0;
|
|
Packit |
70b277 |
runtime_error = FALSE;
|
|
Packit |
70b277 |
bc_init_num (&temp_num);
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Set up the interrupt mechanism for an interactive session. */
|
|
Packit |
70b277 |
if (interactive)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
signal (SIGINT, stop_execution);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
had_sigint = FALSE;
|
|
Packit |
70b277 |
while (pc.pc_addr < functions[pc.pc_func].f_code_size
|
|
Packit |
70b277 |
&& !runtime_error && !had_sigint)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
inst = byte(&pc);
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
#if DEBUG > 3
|
|
Packit |
70b277 |
{ /* Print out address and the stack before each instruction.*/
|
|
Packit |
70b277 |
int depth; estack_rec *temp = ex_stack;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
printf ("func=%d addr=%d inst=%c\n",pc.pc_func, pc.pc_addr, inst);
|
|
Packit |
70b277 |
if (temp == NULL) printf ("empty stack.\n", inst);
|
|
Packit |
70b277 |
else
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
depth = 1;
|
|
Packit |
70b277 |
while (temp != NULL)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
printf (" %d = ", depth);
|
|
Packit |
70b277 |
bc_out_num (temp->s_num, 10, out_char, std_only);
|
|
Packit |
70b277 |
depth++;
|
|
Packit |
70b277 |
temp = temp->s_next;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
out_char ('\n');
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
#endif
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
switch ( inst )
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'A' : /* increment array variable (Add one). */
|
|
Packit |
70b277 |
var_name = byte(&pc);
|
|
Packit |
70b277 |
if ((var_name & 0x80) != 0)
|
|
Packit |
70b277 |
var_name = ((var_name & 0x7f) << 8) + byte(&pc);
|
|
Packit |
70b277 |
incr_array (var_name);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'B' : /* Branch to a label if TOS != 0. Remove value on TOS. */
|
|
Packit |
70b277 |
case 'Z' : /* Branch to a label if TOS == 0. Remove value on TOS. */
|
|
Packit |
70b277 |
c_code = !bc_is_zero (ex_stack->s_num);
|
|
Packit |
70b277 |
pop ();
|
|
Packit |
70b277 |
/*FALLTHROUGH*/ /* common branch and jump code */
|
|
Packit |
70b277 |
case 'J' : /* Jump to a label. */
|
|
Packit |
70b277 |
label_num = byte(&pc); /* Low order bits first. */
|
|
Packit |
70b277 |
label_num += byte(&pc) << 8;
|
|
Packit |
70b277 |
if (inst == 'J' || (inst == 'B' && c_code)
|
|
Packit |
70b277 |
|| (inst == 'Z' && !c_code)) {
|
|
Packit |
70b277 |
gp = functions[pc.pc_func].f_label;
|
|
Packit |
70b277 |
l_gp = label_num >> BC_LABEL_LOG;
|
|
Packit |
70b277 |
l_off = label_num % BC_LABEL_GROUP;
|
|
Packit |
70b277 |
while (l_gp-- > 0) gp = gp->l_next;
|
|
Packit |
70b277 |
if (gp)
|
|
Packit |
70b277 |
pc.pc_addr = gp->l_adrs[l_off];
|
|
Packit |
70b277 |
else {
|
|
Packit |
70b277 |
rt_error ("Internal error.");
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'C' : /* Call a function. */
|
|
Packit |
70b277 |
/* Get the function number. */
|
|
Packit |
70b277 |
new_func = byte(&pc);
|
|
Packit |
70b277 |
if ((new_func & 0x80) != 0)
|
|
Packit |
70b277 |
new_func = ((new_func & 0x7f) << 8) + byte(&pc);
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Check to make sure it is defined. */
|
|
Packit |
70b277 |
if (!functions[new_func].f_defined)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
rt_error ("Function %s not defined.", f_names[new_func]);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Check and push parameters. */
|
|
Packit |
70b277 |
process_params (&pc, new_func);
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Push auto variables. */
|
|
Packit |
70b277 |
for (auto_list = functions[new_func].f_autos;
|
|
Packit |
70b277 |
auto_list != NULL;
|
|
Packit |
70b277 |
auto_list = auto_list->next)
|
|
Packit |
70b277 |
auto_var (auto_list->av_name);
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Push pc and ibase. */
|
|
Packit |
70b277 |
fpush (pc.pc_func);
|
|
Packit |
70b277 |
fpush (pc.pc_addr);
|
|
Packit |
70b277 |
fpush (i_base);
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Reset pc to start of function. */
|
|
Packit |
70b277 |
pc.pc_func = new_func;
|
|
Packit |
70b277 |
pc.pc_addr = 0;
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'D' : /* Duplicate top of stack */
|
|
Packit |
70b277 |
push_copy (ex_stack->s_num);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'K' : /* Push a constant */
|
|
Packit |
70b277 |
/* Get the input base and convert it to a bc number. */
|
|
Packit |
70b277 |
if (pc.pc_func == 0)
|
|
Packit |
70b277 |
const_base = i_base;
|
|
Packit |
70b277 |
else
|
|
Packit |
70b277 |
const_base = fn_stack->s_val;
|
|
Packit |
70b277 |
if (const_base == 10)
|
|
Packit |
70b277 |
push_b10_const (&pc);
|
|
Packit |
70b277 |
else
|
|
Packit |
70b277 |
push_constant (prog_char, const_base);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'L' : /* load array variable */
|
|
Packit |
70b277 |
var_name = byte(&pc);
|
|
Packit |
70b277 |
if ((var_name & 0x80) != 0)
|
|
Packit |
70b277 |
var_name = ((var_name & 0x7f) << 8) + byte(&pc);
|
|
Packit |
70b277 |
load_array (var_name);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'M' : /* decrement array variable (Minus!) */
|
|
Packit |
70b277 |
var_name = byte(&pc);
|
|
Packit |
70b277 |
if ((var_name & 0x80) != 0)
|
|
Packit |
70b277 |
var_name = ((var_name & 0x7f) << 8) + byte(&pc);
|
|
Packit |
70b277 |
decr_array (var_name);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'O' : /* Write a string to the output with processing. */
|
|
Packit |
70b277 |
while ((ch = byte(&pc)) != '"')
|
|
Packit |
70b277 |
if (ch != '\\')
|
|
Packit |
70b277 |
out_schar (ch);
|
|
Packit |
70b277 |
else
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
ch = byte(&pc);
|
|
Packit |
70b277 |
if (ch == '"') break;
|
|
Packit |
70b277 |
switch (ch)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
case 'a': out_schar (007); break;
|
|
Packit |
70b277 |
case 'b': out_schar ('\b'); break;
|
|
Packit |
70b277 |
case 'f': out_schar ('\f'); break;
|
|
Packit |
70b277 |
case 'n': out_schar ('\n'); break;
|
|
Packit |
70b277 |
case 'q': out_schar ('"'); break;
|
|
Packit |
70b277 |
case 'r': out_schar ('\r'); break;
|
|
Packit |
70b277 |
case 't': out_schar ('\t'); break;
|
|
Packit |
70b277 |
case '\\': out_schar ('\\'); break;
|
|
Packit |
70b277 |
default: break;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
fflush (stdout);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'R' : /* Return from function */
|
|
Packit |
70b277 |
if (pc.pc_func != 0)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
/* "Pop" autos and parameters. */
|
|
Packit |
70b277 |
pop_vars(functions[pc.pc_func].f_autos);
|
|
Packit |
70b277 |
pop_vars(functions[pc.pc_func].f_params);
|
|
Packit |
70b277 |
/* reset the pc. */
|
|
Packit |
70b277 |
fpop ();
|
|
Packit |
70b277 |
pc.pc_addr = fpop ();
|
|
Packit |
70b277 |
pc.pc_func = fpop ();
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
else
|
|
Packit |
70b277 |
rt_error ("Return from main program.");
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'S' : /* store array variable */
|
|
Packit |
70b277 |
var_name = byte(&pc);
|
|
Packit |
70b277 |
if ((var_name & 0x80) != 0)
|
|
Packit |
70b277 |
var_name = ((var_name & 0x7f ) << 8) + byte(&pc);
|
|
Packit |
70b277 |
store_array (var_name);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'T' : /* Test tos for zero */
|
|
Packit |
70b277 |
c_code = bc_is_zero (ex_stack->s_num);
|
|
Packit |
70b277 |
assign (c_code);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'W' : /* Write the value on the top of the stack. */
|
|
Packit |
70b277 |
case 'P' : /* Write the value on the top of the stack. No newline. */
|
|
Packit |
70b277 |
bc_out_num (ex_stack->s_num, o_base, out_char, std_only);
|
|
Packit |
70b277 |
if (inst == 'W') out_char ('\n');
|
|
Packit |
70b277 |
store_var (4); /* Special variable "last". */
|
|
Packit |
70b277 |
fflush (stdout);
|
|
Packit |
70b277 |
pop ();
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'c' : /* Call special function. */
|
|
Packit |
70b277 |
new_func = byte(&pc);
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
switch (new_func)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
case 'L': /* Length function. */
|
|
Packit |
70b277 |
/* For the number 0.xxxx, 0 is not significant. */
|
|
Packit |
70b277 |
if (ex_stack->s_num->n_len == 1 &&
|
|
Packit |
70b277 |
ex_stack->s_num->n_scale != 0 &&
|
|
Packit |
70b277 |
ex_stack->s_num->n_value[0] == 0 )
|
|
Packit |
70b277 |
bc_int2num (&ex_stack->s_num, ex_stack->s_num->n_scale);
|
|
Packit |
70b277 |
else
|
|
Packit |
70b277 |
bc_int2num (&ex_stack->s_num, ex_stack->s_num->n_len
|
|
Packit |
70b277 |
+ ex_stack->s_num->n_scale);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'S': /* Scale function. */
|
|
Packit |
70b277 |
bc_int2num (&ex_stack->s_num, ex_stack->s_num->n_scale);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'R': /* Square Root function. */
|
|
Packit |
70b277 |
if (!bc_sqrt (&ex_stack->s_num, scale))
|
|
Packit |
70b277 |
rt_error ("Square root of a negative number");
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'I': /* Read function. */
|
|
Packit |
70b277 |
push_constant (input_char, i_base);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'X': /* Random function. */
|
|
Packit |
70b277 |
push_copy (_zero_);
|
|
Packit |
70b277 |
bc_int2num (&ex_stack->s_num, random());
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'd' : /* Decrement number */
|
|
Packit |
70b277 |
var_name = byte(&pc);
|
|
Packit |
70b277 |
if ((var_name & 0x80) != 0)
|
|
Packit |
70b277 |
var_name = ((var_name & 0x7f) << 8) + byte(&pc);
|
|
Packit |
70b277 |
decr_var (var_name);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'h' : /* Halt the machine. */
|
|
Packit |
70b277 |
bc_exit (0);
|
|
Packit |
70b277 |
/* NOTREACHED */
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'i' : /* increment number */
|
|
Packit |
70b277 |
var_name = byte(&pc);
|
|
Packit |
70b277 |
if ((var_name & 0x80) != 0)
|
|
Packit |
70b277 |
var_name = ((var_name & 0x7f) << 8) + byte(&pc);
|
|
Packit |
70b277 |
incr_var (var_name);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'l' : /* load variable */
|
|
Packit |
70b277 |
var_name = byte(&pc);
|
|
Packit |
70b277 |
if ((var_name & 0x80) != 0)
|
|
Packit |
70b277 |
var_name = ((var_name & 0x7f) << 8) + byte(&pc);
|
|
Packit |
70b277 |
load_var (var_name);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'n' : /* Negate top of stack. */
|
|
Packit |
70b277 |
bc_sub (_zero_, ex_stack->s_num, &ex_stack->s_num, 0);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'p' : /* Pop the execution stack. */
|
|
Packit |
70b277 |
pop ();
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 's' : /* store variable */
|
|
Packit |
70b277 |
var_name = byte(&pc);
|
|
Packit |
70b277 |
if ((var_name & 0x80) != 0)
|
|
Packit |
70b277 |
var_name = ((var_name & 0x7f) << 8) + byte(&pc);
|
|
Packit |
70b277 |
store_var (var_name);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'w' : /* Write a string to the output. */
|
|
Packit |
70b277 |
while ((ch = byte(&pc)) != '"') out_schar (ch);
|
|
Packit |
70b277 |
fflush (stdout);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'x' : /* Exchange Top of Stack with the one under the tos. */
|
|
Packit |
70b277 |
if (check_stack(2)) {
|
|
Packit |
70b277 |
bc_num temp = ex_stack->s_num;
|
|
Packit |
70b277 |
ex_stack->s_num = ex_stack->s_next->s_num;
|
|
Packit |
70b277 |
ex_stack->s_next->s_num = temp;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case '0' : /* Load Constant 0. */
|
|
Packit |
70b277 |
push_copy (_zero_);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case '1' : /* Load Constant 1. */
|
|
Packit |
70b277 |
push_copy (_one_);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case '!' : /* Negate the boolean value on top of the stack. */
|
|
Packit |
70b277 |
c_code = bc_is_zero (ex_stack->s_num);
|
|
Packit |
70b277 |
assign (c_code);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case '&' : /* compare greater than */
|
|
Packit |
70b277 |
if (check_stack(2))
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
c_code = !bc_is_zero (ex_stack->s_next->s_num)
|
|
Packit |
70b277 |
&& !bc_is_zero (ex_stack->s_num);
|
|
Packit |
70b277 |
pop ();
|
|
Packit |
70b277 |
assign (c_code);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case '|' : /* compare greater than */
|
|
Packit |
70b277 |
if (check_stack(2))
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
c_code = !bc_is_zero (ex_stack->s_next->s_num)
|
|
Packit |
70b277 |
|| !bc_is_zero (ex_stack->s_num);
|
|
Packit |
70b277 |
pop ();
|
|
Packit |
70b277 |
assign (c_code);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case '+' : /* add */
|
|
Packit |
70b277 |
if (check_stack(2))
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
bc_add (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num, 0);
|
|
Packit |
70b277 |
pop();
|
|
Packit |
70b277 |
pop();
|
|
Packit |
70b277 |
push_num (temp_num);
|
|
Packit |
70b277 |
bc_init_num (&temp_num);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case '-' : /* subtract */
|
|
Packit |
70b277 |
if (check_stack(2))
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
bc_sub (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num, 0);
|
|
Packit |
70b277 |
pop();
|
|
Packit |
70b277 |
pop();
|
|
Packit |
70b277 |
push_num (temp_num);
|
|
Packit |
70b277 |
bc_init_num (&temp_num);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case '*' : /* multiply */
|
|
Packit |
70b277 |
if (check_stack(2))
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
bc_multiply (ex_stack->s_next->s_num, ex_stack->s_num,
|
|
Packit |
70b277 |
&temp_num, scale);
|
|
Packit |
70b277 |
pop();
|
|
Packit |
70b277 |
pop();
|
|
Packit |
70b277 |
push_num (temp_num);
|
|
Packit |
70b277 |
bc_init_num (&temp_num);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case '/' : /* divide */
|
|
Packit |
70b277 |
if (check_stack(2))
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
if (bc_divide (ex_stack->s_next->s_num,
|
|
Packit |
70b277 |
ex_stack->s_num, &temp_num, scale) == 0)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
pop();
|
|
Packit |
70b277 |
pop();
|
|
Packit |
70b277 |
push_num (temp_num);
|
|
Packit |
70b277 |
bc_init_num (&temp_num);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
else
|
|
Packit |
70b277 |
rt_error ("Divide by zero");
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case '%' : /* remainder */
|
|
Packit |
70b277 |
if (check_stack(2))
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
if (bc_is_zero (ex_stack->s_num))
|
|
Packit |
70b277 |
rt_error ("Modulo by zero");
|
|
Packit |
70b277 |
else
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
bc_modulo (ex_stack->s_next->s_num,
|
|
Packit |
70b277 |
ex_stack->s_num, &temp_num, scale);
|
|
Packit |
70b277 |
pop();
|
|
Packit |
70b277 |
pop();
|
|
Packit |
70b277 |
push_num (temp_num);
|
|
Packit |
70b277 |
bc_init_num (&temp_num);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case '^' : /* raise */
|
|
Packit |
70b277 |
if (check_stack(2))
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
bc_raise (ex_stack->s_next->s_num,
|
|
Packit |
70b277 |
ex_stack->s_num, &temp_num, scale);
|
|
Packit |
70b277 |
if (bc_is_zero (ex_stack->s_next->s_num) && bc_is_neg (ex_stack->s_num))
|
|
Packit |
70b277 |
rt_error ("divide by zero");
|
|
Packit |
70b277 |
pop();
|
|
Packit |
70b277 |
pop();
|
|
Packit |
70b277 |
push_num (temp_num);
|
|
Packit |
70b277 |
bc_init_num (&temp_num);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case '=' : /* compare equal */
|
|
Packit |
70b277 |
if (check_stack(2))
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
c_code = bc_compare (ex_stack->s_next->s_num,
|
|
Packit |
70b277 |
ex_stack->s_num) == 0;
|
|
Packit |
70b277 |
pop ();
|
|
Packit |
70b277 |
assign (c_code);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case '#' : /* compare not equal */
|
|
Packit |
70b277 |
if (check_stack(2))
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
c_code = bc_compare (ex_stack->s_next->s_num,
|
|
Packit |
70b277 |
ex_stack->s_num) != 0;
|
|
Packit |
70b277 |
pop ();
|
|
Packit |
70b277 |
assign (c_code);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case '<' : /* compare less than */
|
|
Packit |
70b277 |
if (check_stack(2))
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
c_code = bc_compare (ex_stack->s_next->s_num,
|
|
Packit |
70b277 |
ex_stack->s_num) == -1;
|
|
Packit |
70b277 |
pop ();
|
|
Packit |
70b277 |
assign (c_code);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case '{' : /* compare less than or equal */
|
|
Packit |
70b277 |
if (check_stack(2))
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
c_code = bc_compare (ex_stack->s_next->s_num,
|
|
Packit |
70b277 |
ex_stack->s_num) <= 0;
|
|
Packit |
70b277 |
pop ();
|
|
Packit |
70b277 |
assign (c_code);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case '>' : /* compare greater than */
|
|
Packit |
70b277 |
if (check_stack(2))
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
c_code = bc_compare (ex_stack->s_next->s_num,
|
|
Packit |
70b277 |
ex_stack->s_num) == 1;
|
|
Packit |
70b277 |
pop ();
|
|
Packit |
70b277 |
assign (c_code);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case '}' : /* compare greater than or equal */
|
|
Packit |
70b277 |
if (check_stack(2))
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
c_code = bc_compare (ex_stack->s_next->s_num,
|
|
Packit |
70b277 |
ex_stack->s_num) >= 0;
|
|
Packit |
70b277 |
pop ();
|
|
Packit |
70b277 |
assign (c_code);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
default : /* error! */
|
|
Packit |
70b277 |
rt_error ("bad instruction: inst=%c", inst);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Clean up the function stack and pop all autos/parameters. */
|
|
Packit |
70b277 |
while (pc.pc_func != 0)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
pop_vars(functions[pc.pc_func].f_autos);
|
|
Packit |
70b277 |
pop_vars(functions[pc.pc_func].f_params);
|
|
Packit |
70b277 |
fpop ();
|
|
Packit |
70b277 |
pc.pc_addr = fpop ();
|
|
Packit |
70b277 |
pc.pc_func = fpop ();
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Clean up the execution stack. */
|
|
Packit |
70b277 |
while (ex_stack != NULL) pop();
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Clean up the interrupt stuff. */
|
|
Packit |
70b277 |
if (interactive)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
signal (SIGINT, use_quit);
|
|
Packit |
70b277 |
if (had_sigint)
|
|
Packit |
70b277 |
printf ("\ninterrupted execution.\n");
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Prog_char gets another byte from the program. It is used for
|
|
Packit |
70b277 |
conversion of text constants in the code to numbers. */
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
int
|
|
Packit |
70b277 |
prog_char (void)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
return (int) byte(&pc);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Read a character from the standard input. This function is used
|
|
Packit |
70b277 |
by the "read" function. */
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
int
|
|
Packit |
70b277 |
input_char (void)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
int in_ch;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Get a character from the standard input for the read function. */
|
|
Packit |
70b277 |
in_ch = getchar();
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Check for a \ quoted newline. */
|
|
Packit |
70b277 |
if (in_ch == '\\')
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
in_ch = getchar();
|
|
Packit |
70b277 |
if (in_ch == '\n') {
|
|
Packit |
70b277 |
in_ch = getchar();
|
|
Packit |
70b277 |
out_col = 0; /* Saw a new line */
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Classify and preprocess the input character. */
|
|
Packit |
70b277 |
if (isdigit(in_ch))
|
|
Packit |
70b277 |
return (in_ch - '0');
|
|
Packit |
70b277 |
if (in_ch >= 'A' && in_ch <= 'Z')
|
|
Packit |
70b277 |
return (in_ch + 10 - 'A');
|
|
Packit |
70b277 |
if (in_ch >= 'a' && in_ch <= 'z')
|
|
Packit |
70b277 |
return (in_ch + 10 - 'a');
|
|
Packit |
70b277 |
if (in_ch == '.' || in_ch == '+' || in_ch == '-')
|
|
Packit |
70b277 |
return (in_ch);
|
|
Packit |
70b277 |
if (in_ch == '~')
|
|
Packit |
70b277 |
return (':');
|
|
Packit |
70b277 |
if (in_ch <= ' ')
|
|
Packit |
70b277 |
return ('~');
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
return (':');
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Push_constant converts a sequence of input characters as returned
|
|
Packit |
70b277 |
by IN_CHAR into a number. The number is pushed onto the execution
|
|
Packit |
70b277 |
stack. The number is converted as a number in base CONV_BASE. */
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
void
|
|
Packit |
70b277 |
push_constant (int (*in_char)(VOID), int conv_base)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
int digits;
|
|
Packit |
70b277 |
bc_num build, temp, result, mult, divisor;
|
|
Packit |
70b277 |
int in_ch, first_ch;
|
|
Packit |
70b277 |
char negative;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Initialize all bc numbers */
|
|
Packit |
70b277 |
bc_init_num (&temp);
|
|
Packit |
70b277 |
bc_init_num (&result);
|
|
Packit |
70b277 |
bc_init_num (&mult);
|
|
Packit |
70b277 |
build = bc_copy_num (_zero_);
|
|
Packit |
70b277 |
negative = FALSE;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* The conversion base. */
|
|
Packit |
70b277 |
bc_int2num (&mult, conv_base);
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Get things ready. */
|
|
Packit |
70b277 |
in_ch = in_char();
|
|
Packit |
70b277 |
/* ~ is space returned by input_char(), prog_char does not return spaces. */
|
|
Packit |
70b277 |
while (in_ch == '~')
|
|
Packit |
70b277 |
in_ch = in_char();
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
if (in_ch == '+')
|
|
Packit |
70b277 |
in_ch = in_char();
|
|
Packit |
70b277 |
else
|
|
Packit |
70b277 |
if (in_ch == '-')
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
negative = TRUE;
|
|
Packit |
70b277 |
in_ch = in_char();
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Check for the special case of a single digit. */
|
|
Packit |
70b277 |
if (in_ch < 36)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
first_ch = in_ch;
|
|
Packit |
70b277 |
in_ch = in_char();
|
|
Packit |
70b277 |
if (in_ch < 36 && first_ch >= conv_base)
|
|
Packit |
70b277 |
first_ch = conv_base - 1;
|
|
Packit |
70b277 |
bc_int2num (&build, (int) first_ch);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Convert the integer part. */
|
|
Packit |
70b277 |
while (in_ch < 36)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
if (in_ch < 36 && in_ch >= conv_base) in_ch = conv_base-1;
|
|
Packit |
70b277 |
bc_multiply (build, mult, &result, 0);
|
|
Packit |
70b277 |
bc_int2num (&temp, (int) in_ch);
|
|
Packit |
70b277 |
bc_add (result, temp, &build, 0);
|
|
Packit |
70b277 |
in_ch = in_char();
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
if (in_ch == '.')
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
in_ch = in_char();
|
|
Packit |
70b277 |
if (in_ch >= conv_base) in_ch = conv_base-1;
|
|
Packit |
70b277 |
bc_free_num (&result);
|
|
Packit |
70b277 |
bc_free_num (&temp);
|
|
Packit |
70b277 |
divisor = bc_copy_num (_one_);
|
|
Packit |
70b277 |
result = bc_copy_num (_zero_);
|
|
Packit |
70b277 |
digits = 0;
|
|
Packit |
70b277 |
while (in_ch < 36)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
bc_multiply (result, mult, &result, 0);
|
|
Packit |
70b277 |
bc_int2num (&temp, (int) in_ch);
|
|
Packit |
70b277 |
bc_add (result, temp, &result, 0);
|
|
Packit |
70b277 |
bc_multiply (divisor, mult, &divisor, 0);
|
|
Packit |
70b277 |
digits++;
|
|
Packit |
70b277 |
in_ch = in_char();
|
|
Packit |
70b277 |
if (in_ch < 36 && in_ch >= conv_base) in_ch = conv_base-1;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
bc_divide (result, divisor, &result, digits);
|
|
Packit |
70b277 |
bc_add (build, result, &build, 0);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Final work. */
|
|
Packit |
70b277 |
if (negative)
|
|
Packit |
70b277 |
bc_sub (_zero_, build, &build, 0);
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
push_num (build);
|
|
Packit |
70b277 |
bc_free_num (&temp);
|
|
Packit |
70b277 |
bc_free_num (&result);
|
|
Packit |
70b277 |
bc_free_num (&mult);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* When converting base 10 constants from the program, we use this
|
|
Packit |
70b277 |
more efficient way to convert them to numbers. PC tells where
|
|
Packit |
70b277 |
the constant starts and is expected to be advanced to after
|
|
Packit |
70b277 |
the constant. */
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
void
|
|
Packit |
70b277 |
push_b10_const (program_counter *progctr)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
bc_num build;
|
|
Packit |
70b277 |
program_counter look_pc;
|
|
Packit |
70b277 |
int kdigits, kscale;
|
|
Packit |
70b277 |
unsigned char inchar;
|
|
Packit |
70b277 |
char *ptr;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Count the digits and get things ready. */
|
|
Packit |
70b277 |
look_pc = *progctr;
|
|
Packit |
70b277 |
kdigits = 0;
|
|
Packit |
70b277 |
kscale = 0;
|
|
Packit |
70b277 |
inchar = byte (&look_pc);
|
|
Packit |
70b277 |
while (inchar != '.' && inchar != ':')
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
kdigits++;
|
|
Packit |
70b277 |
inchar = byte(&look_pc);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
if (inchar == '.' )
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
inchar = byte(&look_pc);
|
|
Packit |
70b277 |
while (inchar != ':')
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
kscale++;
|
|
Packit |
70b277 |
inchar = byte(&look_pc);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Get the first character again and move the progctr. */
|
|
Packit |
70b277 |
inchar = byte(progctr);
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Secial cases of 0, 1, and A-F single inputs. */
|
|
Packit |
70b277 |
if (kdigits == 1 && kscale == 0)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
if (inchar == 0)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
push_copy (_zero_);
|
|
Packit |
70b277 |
inchar = byte(progctr);
|
|
Packit |
70b277 |
return;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
if (inchar == 1) {
|
|
Packit |
70b277 |
push_copy (_one_);
|
|
Packit |
70b277 |
inchar = byte(progctr);
|
|
Packit |
70b277 |
return;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
if (inchar > 9)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
bc_init_num (&build);
|
|
Packit |
70b277 |
bc_int2num (&build, inchar);
|
|
Packit |
70b277 |
push_num (build);
|
|
Packit |
70b277 |
inchar = byte(progctr);
|
|
Packit |
70b277 |
return;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Build the new number. */
|
|
Packit |
70b277 |
if (kdigits == 0)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
build = bc_new_num (1,kscale);
|
|
Packit |
70b277 |
ptr = build->n_value;
|
|
Packit |
70b277 |
*ptr++ = 0;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
else
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
build = bc_new_num (kdigits,kscale);
|
|
Packit |
70b277 |
ptr = build->n_value;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
while (inchar != ':')
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
if (inchar != '.')
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
if (inchar > 9)
|
|
Packit |
70b277 |
*ptr++ = 9;
|
|
Packit |
70b277 |
else
|
|
Packit |
70b277 |
*ptr++ = inchar;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
inchar = byte(progctr);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
push_num (build);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Put the correct value on the stack for C_CODE. Frees TOS num. */
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
void
|
|
Packit |
70b277 |
assign (char code)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
bc_free_num (&ex_stack->s_num);
|
|
Packit |
70b277 |
if (code)
|
|
Packit |
70b277 |
ex_stack->s_num = bc_copy_num (_one_);
|
|
Packit |
70b277 |
else
|
|
Packit |
70b277 |
ex_stack->s_num = bc_copy_num (_zero_);
|
|
Packit |
70b277 |
}
|