Initial revision
This commit is contained in:
Executable
+783
@@ -0,0 +1,783 @@
|
||||
/* execute.c - run a bc program. */
|
||||
|
||||
/* This file is part of bc written for MINIX.
|
||||
Copyright (C) 1991, 1992 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 'n': out_char ('\n'); break;
|
||||
case 't': out_char ('\t'); break;
|
||||
case 'r': out_char ('\r'); break;
|
||||
case 'b': out_char (007); break;
|
||||
case 'f': out_char ('\f'); 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_);
|
||||
}
|
||||
Reference in New Issue
Block a user