787 lines
17 KiB
C
787 lines
17 KiB
C
/* execute.c - run a bc program. */
|
|
|
|
/* This file is part of GNU bc.
|
|
Copyright (C) 1991, 1992, 1993, 1994, 1997 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_schar (ch);
|
|
else
|
|
{
|
|
ch = byte(&pc);
|
|
if (ch == '"') break;
|
|
switch (ch)
|
|
{
|
|
case 'a': out_schar (007); break;
|
|
case 'b': out_schar ('\b'); break;
|
|
case 'f': out_schar ('\f'); break;
|
|
case 'n': out_schar ('\n'); break;
|
|
case 'q': out_schar ('"'); break;
|
|
case 'r': out_schar ('\r'); break;
|
|
case 't': out_schar ('\t'); break;
|
|
case '\\': out_schar ('\\'); break;
|
|
default: break;
|
|
}
|
|
}
|
|
fflush (stdout);
|
|
break;
|
|
|
|
case 'R' : /* 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 (4); /* Special variable "last". */
|
|
fflush (stdout);
|
|
pop ();
|
|
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, 0);
|
|
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_schar (ch);
|
|
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, 0);
|
|
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, 0);
|
|
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, 0);
|
|
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, 0);
|
|
bc_multiply (divisor, mult, &divisor, 0);
|
|
digits++;
|
|
in_ch = in_char();
|
|
if (in_ch < 16 && in_ch >= conv_base) in_ch = conv_base-1;
|
|
}
|
|
bc_divide (result, divisor, &result, digits);
|
|
bc_add (build, result, &build, 0);
|
|
}
|
|
|
|
/* Final work. */
|
|
if (negative)
|
|
bc_sub (_zero_, build, &build, 0);
|
|
|
|
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_);
|
|
}
|