Blame bc/execute.c

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
}