aboutsummaryrefslogtreecommitdiff
path: root/gnu/usr.bin/bc/execute.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/usr.bin/bc/execute.c')
-rw-r--r--gnu/usr.bin/bc/execute.c785
1 files changed, 0 insertions, 785 deletions
diff --git a/gnu/usr.bin/bc/execute.c b/gnu/usr.bin/bc/execute.c
deleted file mode 100644
index 1a895068602d..000000000000
--- a/gnu/usr.bin/bc/execute.c
+++ /dev/null
@@ -1,785 +0,0 @@
-/* execute.c - run a bc program. */
-
-/* This file is part of bc written for MINIX.
- Copyright (C) 1991, 1992, 1993, 1994 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:
- e-mail: phil@cs.wwu.edu
- us-mail: Philip A. Nelson
- Computer Science Department, 9062
- Western Washington University
- Bellingham, WA 98226-9062
-
-*************************************************************************/
-
-#include "bcdefs.h"
-#include <signal.h>
-#include "global.h"
-#include "proto.h"
-
-
-/* The SIGINT interrupt handling routine. */
-
-int had_sigint;
-
-void
-stop_execution (sig)
- int sig;
-{
- had_sigint = TRUE;
- printf ("\n");
- rt_error ("interrupted execution");
-}
-
-
-/* Get the current byte and advance the PC counter. */
-
-unsigned char
-byte (pc)
- program_counter *pc;
-{
- int seg, offset;
-
- seg = pc->pc_addr >> BC_SEG_LOG;
- offset = pc->pc_addr++ % BC_SEG_SIZE;
- return (functions[pc->pc_func].f_body[seg][offset]);
-}
-
-
-/* The routine that actually runs the machine. */
-
-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;
-
- /* Initialize this run... */
- pc.pc_func = 0;
- pc.pc_addr = 0;
- runtime_error = FALSE;
- init_num (&temp_num);
-
- /* Set up the interrupt mechanism for an interactive session. */
- 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
- { /* Print out address and the stack before each instruction.*/
- 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);
- out_num (temp->s_num, 10, out_char);
- depth++;
- temp = temp->s_next;
- }
- }
- }
-#endif
-
- switch ( inst )
- {
-
- case 'A' : /* increment array variable (Add one). */
- var_name = byte(&pc);
- if ((var_name & 0x80) != 0)
- var_name = ((var_name << 8) & 0x7f) + byte(&pc);
- incr_array (var_name);
- break;
-
- case 'B' : /* Branch to a label if TOS != 0. Remove value on TOS. */
- case 'Z' : /* Branch to a label if TOS == 0. Remove value on TOS. */
- c_code = !is_zero (ex_stack->s_num);
- pop ();
- case 'J' : /* Jump to a label. */
- label_num = byte(&pc); /* Low order bits first. */
- 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' : /* Call a function. */
- /* Get the function number. */
- new_func = byte(&pc);
- if ((new_func & 0x80) != 0)
- new_func = ((new_func << 8) & 0x7f) + byte(&pc);
-
- /* Check to make sure it is defined. */
- if (!functions[new_func].f_defined)
- {
- rt_error ("Function %s not defined.", f_names[new_func]);
- break;
- }
-
- /* Check and push parameters. */
- process_params (&pc, new_func);
-
- /* Push auto variables. */
- for (auto_list = functions[new_func].f_autos;
- auto_list != NULL;
- auto_list = auto_list->next)
- auto_var (auto_list->av_name);
-
- /* Push pc and ibase. */
- fpush (pc.pc_func);
- fpush (pc.pc_addr);
- fpush (i_base);
-
- /* Reset pc to start of function. */
- pc.pc_func = new_func;
- pc.pc_addr = 0;
- break;
-
- case 'D' : /* Duplicate top of stack */
- push_copy (ex_stack->s_num);
- break;
-
- case 'K' : /* Push a constant */
- /* Get the input base and convert it to a bc number. */
- 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' : /* load array variable */
- var_name = byte(&pc);
- if ((var_name & 0x80) != 0)
- var_name = ((var_name << 8) & 0x7f) + byte(&pc);
- load_array (var_name);
- break;
-
- case 'M' : /* decrement array variable (Minus!) */
- var_name = byte(&pc);
- if ((var_name & 0x80) != 0)
- var_name = ((var_name << 8) & 0x7f) + byte(&pc);
- decr_array (var_name);
- break;
-
- case 'O' : /* Write a string to the output with processing. */
- while ((ch = byte(&pc)) != '"')
- if (ch != '\\')
- out_char (ch);
- else
- {
- ch = byte(&pc);
- if (ch == '"') break;
- switch (ch)
- {
- case 'a': out_char (007); break;
- case 'b': out_char ('\b'); break;
- case 'f': out_char ('\f'); break;
- case 'n': out_char ('\n'); break;
- case 'q': out_char ('"'); break;
- case 'r': out_char ('\r'); break;
- case 't': out_char ('\t'); break;
- case '\\': out_char ('\\'); break;
- default: break;
- }
- }
- if (interactive) fflush (stdout);
- break;
-
- case 'R' : /* Return from function */
- if (pc.pc_func != 0)
- {
- /* "Pop" autos and parameters. */
- pop_vars(functions[pc.pc_func].f_autos);
- pop_vars(functions[pc.pc_func].f_params);
- /* reset the pc. */
- fpop ();
- pc.pc_addr = fpop ();
- pc.pc_func = fpop ();
- }
- else
- rt_error ("Return from main program.");
- break;
-
- case 'S' : /* store array variable */
- var_name = byte(&pc);
- if ((var_name & 0x80) != 0)
- var_name = ((var_name << 8) & 0x7f) + byte(&pc);
- store_array (var_name);
- break;
-
- case 'T' : /* Test tos for zero */
- c_code = is_zero (ex_stack->s_num);
- assign (c_code);
- break;
-
- case 'W' : /* Write the value on the top of the stack. */
- case 'P' : /* Write the value on the top of the stack. No newline. */
- out_num (ex_stack->s_num, o_base, out_char);
- if (inst == 'W') out_char ('\n');
- store_var (3); /* Special variable "last". */
- if (interactive) fflush (stdout);
- break;
-
- case 'c' : /* Call special function. */
- new_func = byte(&pc);
-
- switch (new_func)
- {
- case 'L': /* Length function. */
- /* For the number 0.xxxx, 0 is not significant. */
- if (ex_stack->s_num->n_len == 1 &&
- ex_stack->s_num->n_scale != 0 &&
- ex_stack->s_num->n_value[0] == 0 )
- int2num (&ex_stack->s_num, ex_stack->s_num->n_scale);
- else
- int2num (&ex_stack->s_num, ex_stack->s_num->n_len
- + ex_stack->s_num->n_scale);
- break;
-
- case 'S': /* Scale function. */
- int2num (&ex_stack->s_num, ex_stack->s_num->n_scale);
- break;
-
- case 'R': /* Square Root function. */
- if (!bc_sqrt (&ex_stack->s_num, scale))
- rt_error ("Square root of a negative number");
- break;
-
- case 'I': /* Read function. */
- push_constant (input_char, i_base);
- break;
- }
- break;
-
- case 'd' : /* Decrement number */
- var_name = byte(&pc);
- if ((var_name & 0x80) != 0)
- var_name = ((var_name << 8) & 0x7f) + byte(&pc);
- decr_var (var_name);
- break;
-
- case 'h' : /* Halt the machine. */
- exit (0);
-
- case 'i' : /* increment number */
- var_name = byte(&pc);
- if ((var_name & 0x80) != 0)
- var_name = ((var_name << 8) & 0x7f) + byte(&pc);
- incr_var (var_name);
- break;
-
- case 'l' : /* load variable */
- var_name = byte(&pc);
- if ((var_name & 0x80) != 0)
- var_name = ((var_name << 8) & 0x7f) + byte(&pc);
- load_var (var_name);
- break;
-
- case 'n' : /* Negate top of stack. */
- bc_sub (_zero_, ex_stack->s_num, &ex_stack->s_num);
- break;
-
- case 'p' : /* Pop the execution stack. */
- pop ();
- break;
-
- case 's' : /* store variable */
- var_name = byte(&pc);
- if ((var_name & 0x80) != 0)
- var_name = ((var_name << 8) & 0x7f) + byte(&pc);
- store_var (var_name);
- break;
-
- case 'w' : /* Write a string to the output. */
- while ((ch = byte(&pc)) != '"') out_char (ch);
- if (interactive) fflush (stdout);
- break;
-
- case 'x' : /* Exchange Top of Stack with the one under the tos. */
- 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' : /* Load Constant 0. */
- push_copy (_zero_);
- break;
-
- case '1' : /* Load Constant 0. */
- push_copy (_one_);
- break;
-
- case '!' : /* Negate the boolean value on top of the stack. */
- c_code = is_zero (ex_stack->s_num);
- assign (c_code);
- break;
-
- case '&' : /* compare greater than */
- if (check_stack(2))
- {
- c_code = !is_zero (ex_stack->s_next->s_num)
- && !is_zero (ex_stack->s_num);
- pop ();
- assign (c_code);
- }
- break;
-
- case '|' : /* compare greater than */
- if (check_stack(2))
- {
- c_code = !is_zero (ex_stack->s_next->s_num)
- || !is_zero (ex_stack->s_num);
- pop ();
- assign (c_code);
- }
- break;
-
- case '+' : /* add */
- if (check_stack(2))
- {
- bc_add (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num);
- pop();
- pop();
- push_num (temp_num);
- init_num (&temp_num);
- }
- break;
-
- case '-' : /* subtract */
- if (check_stack(2))
- {
- bc_sub (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num);
- pop();
- pop();
- push_num (temp_num);
- init_num (&temp_num);
- }
- break;
-
- case '*' : /* multiply */
- 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);
- init_num (&temp_num);
- }
- break;
-
- case '/' : /* divide */
- 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);
- init_num (&temp_num);
- }
- else
- rt_error ("Divide by zero");
- }
- break;
-
- case '%' : /* remainder */
- if (check_stack(2))
- {
- if (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);
- init_num (&temp_num);
- }
- }
- break;
-
- case '^' : /* raise */
- if (check_stack(2))
- {
- bc_raise (ex_stack->s_next->s_num,
- ex_stack->s_num, &temp_num, scale);
- if (is_zero (ex_stack->s_next->s_num) && is_neg (ex_stack->s_num))
- rt_error ("divide by zero");
- pop();
- pop();
- push_num (temp_num);
- init_num (&temp_num);
- }
- break;
-
- case '=' : /* compare equal */
- 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 '#' : /* compare not equal */
- 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 '<' : /* compare less than */
- 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 '{' : /* compare less than or equal */
- 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 '>' : /* compare greater than */
- 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 '}' : /* compare greater than or equal */
- 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 : /* error! */
- rt_error ("bad instruction: inst=%c", inst);
- }
- }
-
- /* Clean up the function stack and pop all autos/parameters. */
- 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 ();
- }
-
- /* Clean up the execution stack. */
- while (ex_stack != NULL) pop();
-
- /* Clean up the interrupt stuff. */
- if (interactive)
- {
- signal (SIGINT, use_quit);
- if (had_sigint)
- printf ("Interruption completed.\n");
- }
-}
-
-
-/* Prog_char gets another byte from the program. It is used for
- conversion of text constants in the code to numbers. */
-
-char
-prog_char ()
-{
- return byte(&pc);
-}
-
-
-/* Read a character from the standard input. This function is used
- by the "read" function. */
-
-char
-input_char ()
-{
- char in_ch;
-
- /* Get a character from the standard input for the read function. */
- in_ch = getchar();
-
- /* Check for a \ quoted newline. */
- if (in_ch == '\\')
- {
- in_ch = getchar();
- if (in_ch == '\n')
- in_ch = getchar();
- }
-
- /* Classify and preprocess the input character. */
- if (isdigit(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 (':');
-}
-
-
-/* Push_constant converts a sequence of input characters as returned
- by IN_CHAR into a number. The number is pushed onto the execution
- stack. The number is converted as a number in base CONV_BASE. */
-
-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;
-
- /* Initialize all bc numbers */
- init_num (&temp);
- init_num (&result);
- init_num (&mult);
- build = copy_num (_zero_);
- negative = FALSE;
-
- /* The conversion base. */
- int2num (&mult, conv_base);
-
- /* Get things ready. */
- 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();
- }
-
- /* Check for the special case of a single digit. */
- 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;
- int2num (&build, (int) first_ch);
- }
-
- /* Convert the integer part. */
- while (in_ch < 16)
- {
- if (in_ch < 16 && in_ch >= conv_base) in_ch = conv_base-1;
- bc_multiply (build, mult, &result, 0);
- int2num (&temp, (int) in_ch);
- bc_add (result, temp, &build);
- in_ch = in_char();
- }
- if (in_ch == '.')
- {
- in_ch = in_char();
- if (in_ch >= conv_base) in_ch = conv_base-1;
- free_num (&result);
- free_num (&temp);
- divisor = copy_num (_one_);
- result = copy_num (_zero_);
- digits = 0;
- while (in_ch < 16)
- {
- bc_multiply (result, mult, &result, 0);
- int2num (&temp, (int) in_ch);
- bc_add (result, temp, &result);
- 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);
- }
-
- /* Final work. */
- if (negative)
- bc_sub (_zero_, build, &build);
-
- push_num (build);
- free_num (&temp);
- free_num (&result);
- free_num (&mult);
-}
-
-
-/* When converting base 10 constants from the program, we use this
- more efficient way to convert them to numbers. PC tells where
- the constant starts and is expected to be advanced to after
- the constant. */
-
-void
-push_b10_const (pc)
- program_counter *pc;
-{
- bc_num build;
- program_counter look_pc;
- int kdigits, kscale;
- char inchar;
- char *ptr;
-
- /* Count the digits and get things ready. */
- 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);
- }
- }
-
- /* Get the first character again and move the pc. */
- inchar = byte(pc);
-
- /* Secial cases of 0, 1, and A-F single inputs. */
- 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)
- {
- init_num (&build);
- int2num (&build, inchar);
- push_num (build);
- inchar = byte(pc);
- return;
- }
- }
-
- /* Build the new number. */
- if (kdigits == 0)
- {
- build = new_num (1,kscale);
- ptr = build->n_value;
- *ptr++ = 0;
- }
- else
- {
- build = 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);
-}
-
-
-/* Put the correct value on the stack for C_CODE. Frees TOS num. */
-
-void
-assign (c_code)
- char c_code;
-{
- free_num (&ex_stack->s_num);
- if (c_code)
- ex_stack->s_num = copy_num (_one_);
- else
- ex_stack->s_num = copy_num (_zero_);
-}