xref: /netbsd-src/external/bsd/bc/dist/execute.c (revision 341df6449e0758ecbc5c5009a483a1f5c365efea)
1 /*	$NetBSD: execute.c,v 1.2 2017/04/18 04:35:18 maya Exp $ */
2 
3 /*
4  * Copyright (C) 1991-1994, 1997, 2006, 2008, 2012-2017 Free Software Foundation, Inc.
5  * Copyright (C) 2016-2017 Philip A. Nelson.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. The names Philip A. Nelson and Free Software Foundation may not be
18  *    used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY PHILIP A. NELSON ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL PHILIP A. NELSON OR THE FREE SOFTWARE FOUNDATION BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31  * THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 /* execute.c - run a bc program. */
34 
35 #include "bcdefs.h"
36 #include <signal.h>
37 #include "proto.h"
38 
39 
40 /* The SIGINT interrupt handling routine. */
41 
42 int had_sigint;
43 
44 void
stop_execution(int sig)45 stop_execution ( int sig )
46 {
47   had_sigint = TRUE;
48 }
49 
50 
51 /* Get the current byte and advance the PC counter. */
52 
53 unsigned char
byte(program_counter * p)54 byte ( program_counter *p )
55 {
56   return (functions[p->pc_func].f_body[p->pc_addr++]);
57 }
58 
59 
60 /* The routine that actually runs the machine. */
61 
62 void
execute(void)63 execute (void)
64 {
65   unsigned long label_num, l_gp, l_off;
66   bc_label_group *gp;
67 
68   char inst, ch;
69   long  new_func;
70   long  var_name;
71 
72   long const_base;
73 
74   bc_num temp_num;
75   arg_list *auto_list;
76 
77   /* Initialize this run... */
78   pc.pc_func = 0;
79   pc.pc_addr = 0;
80   runtime_error = FALSE;
81   bc_init_num (&temp_num);
82 
83   /* Set up the interrupt mechanism for an interactive session. */
84   if (interactive)
85     {
86       signal (SIGINT, stop_execution);
87     }
88 
89   had_sigint = FALSE;
90   while (pc.pc_addr < functions[pc.pc_func].f_code_size
91 	 && !runtime_error && !had_sigint)
92     {
93       inst = byte(&pc);
94 
95 #if DEBUG > 3
96       { /* Print out address and the stack before each instruction.*/
97 	int depth; estack_rec *temp = ex_stack;
98 
99 	printf ("func=%d addr=%d inst=%c\n",pc.pc_func, pc.pc_addr, inst);
100 	if (temp == NULL) printf ("empty stack.\n", inst);
101 	else
102 	  {
103 	    depth = 1;
104 	    while (temp != NULL)
105 	      {
106 		printf ("  %d = ", depth);
107 		bc_out_num (temp->s_num, 10, out_char, std_only);
108 		depth++;
109 		temp = temp->s_next;
110 	      }
111 	    out_char ('\n');
112 	  }
113       }
114 #endif
115 
116     switch ( inst )
117       {
118 
119       case 'A' : /* increment array variable (Add one). */
120 	var_name = byte(&pc);
121 	if ((var_name & 0x80) != 0)
122 	  var_name = ((var_name & 0x7f) << 8) + byte(&pc);
123 	incr_array (var_name);
124 	break;
125 
126       case 'B' : /* Branch to a label if TOS != 0. Remove value on TOS. */
127       case 'Z' : /* Branch to a label if TOS == 0. Remove value on TOS. */
128 	c_code = !bc_is_zero (ex_stack->s_num);
129 	pop ();
130 	/*FALLTHROUGH*/ /* common branch and jump code */
131       case 'J' : /* Jump to a label. */
132 	label_num = byte(&pc);  /* Low order bits first. */
133 	label_num += byte(&pc) << 8;
134 	if (inst == 'J' || (inst == 'B' && c_code)
135 	    || (inst == 'Z' && !c_code)) {
136 	  gp = functions[pc.pc_func].f_label;
137 	  l_gp  = label_num >> BC_LABEL_LOG;
138 	  l_off = label_num % BC_LABEL_GROUP;
139 	  while (l_gp-- > 0) gp = gp->l_next;
140           if (gp)
141             pc.pc_addr = gp->l_adrs[l_off];
142           else {
143             rt_error ("Internal error.");
144             break;
145           }
146 	}
147 	break;
148 
149       case 'C' : /* Call a function. */
150 	/* Get the function number. */
151 	new_func = byte(&pc);
152 	if ((new_func & 0x80) != 0)
153 	  new_func = ((new_func & 0x7f) << 8) + byte(&pc);
154 
155 	/* Check to make sure it is defined. */
156 	if (!functions[new_func].f_defined)
157 	  {
158 	    rt_error ("Function %s not defined.", f_names[new_func]);
159 	    break;
160 	  }
161 
162 	/* Check and push parameters. */
163 	process_params (&pc, new_func);
164 
165 	/* Push auto variables. */
166 	for (auto_list = functions[new_func].f_autos;
167 	     auto_list != NULL;
168 	     auto_list = auto_list->next)
169 	  auto_var (auto_list->av_name);
170 
171 	/* Push pc and ibase. */
172 	fpush (pc.pc_func);
173 	fpush (pc.pc_addr);
174 	fpush (i_base);
175 
176 	/* Reset pc to start of function. */
177 	pc.pc_func = new_func;
178 	pc.pc_addr = 0;
179 	break;
180 
181       case 'D' : /* Duplicate top of stack */
182 	push_copy (ex_stack->s_num);
183 	break;
184 
185       case 'K' : /* Push a constant */
186 	/* Get the input base and convert it to a bc number. */
187 	if (pc.pc_func == 0)
188 	  const_base = i_base;
189 	else
190 	  const_base = fn_stack->s_val;
191 	if (const_base == 10)
192 	  push_b10_const (&pc);
193 	else
194 	  push_constant (prog_char, const_base);
195 	break;
196 
197       case 'L' : /* load array variable */
198 	var_name = byte(&pc);
199 	if ((var_name & 0x80) != 0)
200 	  var_name = ((var_name & 0x7f) << 8) + byte(&pc);
201 	load_array (var_name);
202 	break;
203 
204       case 'M' : /* decrement array variable (Minus!) */
205 	var_name = byte(&pc);
206 	if ((var_name & 0x80) != 0)
207 	  var_name = ((var_name & 0x7f) << 8) + byte(&pc);
208 	decr_array (var_name);
209 	break;
210 
211       case 'O' : /* Write a string to the output with processing. */
212 	while ((ch = byte(&pc)) != '"')
213 	  if (ch != '\\')
214 	    out_schar (ch);
215 	  else
216 	    {
217 	      ch = byte(&pc);
218 	      if (ch == '"') break;
219 	      switch (ch)
220 		{
221 		case 'a':  out_schar (007); break;
222 		case 'b':  out_schar ('\b'); break;
223 		case 'f':  out_schar ('\f'); break;
224 		case 'n':  out_schar ('\n'); break;
225 		case 'q':  out_schar ('"'); break;
226 		case 'r':  out_schar ('\r'); break;
227 		case 't':  out_schar ('\t'); break;
228 		case '\\': out_schar ('\\'); break;
229 		default:  break;
230 		}
231 	    }
232 	fflush (stdout);
233 	break;
234 
235       case 'R' : /* Return from function */
236 	if (pc.pc_func != 0)
237 	  {
238 	    /* "Pop" autos and parameters. */
239 	    pop_vars(functions[pc.pc_func].f_autos);
240 	    pop_vars(functions[pc.pc_func].f_params);
241 	    /* reset the pc. */
242 	    fpop ();
243 	    pc.pc_addr = fpop ();
244 	    pc.pc_func = fpop ();
245 	  }
246 	else
247 	  rt_error ("Return from main program.");
248 	break;
249 
250       case 'S' : /* store array variable */
251 	var_name = byte(&pc);
252 	if ((var_name & 0x80) != 0)
253 	  var_name = ((var_name & 0x7f ) << 8) + byte(&pc);
254 	store_array (var_name);
255 	break;
256 
257       case 'T' : /* Test tos for zero */
258 	c_code = bc_is_zero (ex_stack->s_num);
259 	assign (c_code);
260 	break;
261 
262       case 'W' : /* Write the value on the top of the stack. */
263       case 'P' : /* Write the value on the top of the stack.  No newline. */
264 	bc_out_num (ex_stack->s_num, o_base, out_char, std_only);
265 	if (inst == 'W') out_char ('\n');
266 	store_var (4);  /* Special variable "last". */
267 	fflush (stdout);
268 	pop ();
269 	break;
270 
271       case 'c' : /* Call special function. */
272 	new_func = byte(&pc);
273 
274       switch (new_func)
275 	{
276 	case 'L':  /* Length function. */
277 	  /* For the number 0.xxxx,  0 is not significant. */
278 	  if (ex_stack->s_num->n_len == 1 &&
279 	      ex_stack->s_num->n_scale != 0 &&
280 	      ex_stack->s_num->n_value[0] == 0 )
281 	    bc_int2num (&ex_stack->s_num, ex_stack->s_num->n_scale);
282 	  else
283 	    bc_int2num (&ex_stack->s_num, ex_stack->s_num->n_len
284 		     + ex_stack->s_num->n_scale);
285 	  break;
286 
287 	case 'S':  /* Scale function. */
288 	  bc_int2num (&ex_stack->s_num, ex_stack->s_num->n_scale);
289 	  break;
290 
291 	case 'R':  /* Square Root function. */
292 	  if (!bc_sqrt (&ex_stack->s_num, scale))
293 	    rt_error ("Square root of a negative number");
294 	  break;
295 
296 	case 'I': /* Read function. */
297 	  push_constant (input_char, i_base);
298 	  break;
299 
300 	case 'X': /* Random function. */
301 	  push_copy (_zero_);
302 	  bc_int2num (&ex_stack->s_num, random());
303 	  break;
304 	}
305 	break;
306 
307       case 'd' : /* Decrement number */
308 	var_name = byte(&pc);
309 	if ((var_name & 0x80) != 0)
310 	  var_name = ((var_name & 0x7f) << 8) + byte(&pc);
311 	decr_var (var_name);
312 	break;
313 
314       case 'h' : /* Halt the machine. */
315 	bc_exit (0);
316 	/* NOTREACHED */
317 
318       case 'i' : /* increment number */
319 	var_name = byte(&pc);
320 	if ((var_name & 0x80) != 0)
321 	  var_name = ((var_name & 0x7f) << 8) + byte(&pc);
322 	incr_var (var_name);
323 	break;
324 
325       case 'l' : /* load variable */
326 	var_name = byte(&pc);
327 	if ((var_name & 0x80) != 0)
328 	  var_name = ((var_name & 0x7f) << 8) + byte(&pc);
329 	load_var (var_name);
330 	break;
331 
332       case 'n' : /* Negate top of stack. */
333 	bc_sub (_zero_, ex_stack->s_num, &ex_stack->s_num, 0);
334 	break;
335 
336       case 'p' : /* Pop the execution stack. */
337 	pop ();
338 	break;
339 
340       case 's' : /* store variable */
341 	var_name = byte(&pc);
342 	if ((var_name & 0x80) != 0)
343 	  var_name = ((var_name & 0x7f) << 8) + byte(&pc);
344 	store_var (var_name);
345 	break;
346 
347       case 'w' : /* Write a string to the output. */
348 	while ((ch = byte(&pc)) != '"') out_schar (ch);
349 	fflush (stdout);
350 	break;
351 
352       case 'x' : /* Exchange Top of Stack with the one under the tos. */
353 	if (check_stack(2)) {
354 	  bc_num temp = ex_stack->s_num;
355 	  ex_stack->s_num = ex_stack->s_next->s_num;
356 	  ex_stack->s_next->s_num = temp;
357 	}
358 	break;
359 
360       case '0' : /* Load Constant 0. */
361 	push_copy (_zero_);
362 	break;
363 
364       case '1' : /* Load Constant 1. */
365 	push_copy (_one_);
366 	break;
367 
368       case '!' : /* Negate the boolean value on top of the stack. */
369 	c_code = bc_is_zero (ex_stack->s_num);
370 	assign (c_code);
371 	break;
372 
373       case '&' : /* compare greater than */
374 	if (check_stack(2))
375 	  {
376 	    c_code = !bc_is_zero (ex_stack->s_next->s_num)
377 	      && !bc_is_zero (ex_stack->s_num);
378 	    pop ();
379 	    assign (c_code);
380 	  }
381 	break;
382 
383       case '|' : /* compare greater than */
384 	if (check_stack(2))
385 	  {
386 	    c_code = !bc_is_zero (ex_stack->s_next->s_num)
387 	      || !bc_is_zero (ex_stack->s_num);
388 	    pop ();
389 	    assign (c_code);
390 	  }
391 	break;
392 
393       case '+' : /* add */
394 	if (check_stack(2))
395 	  {
396 	    bc_add (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num, 0);
397 	    pop();
398 	    pop();
399 	    push_num (temp_num);
400 	    bc_init_num (&temp_num);
401 	  }
402 	break;
403 
404       case '-' : /* subtract */
405 	if (check_stack(2))
406 	  {
407 	    bc_sub (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num, 0);
408 	    pop();
409 	    pop();
410 	    push_num (temp_num);
411 	    bc_init_num (&temp_num);
412 	  }
413 	break;
414 
415       case '*' : /* multiply */
416 	if (check_stack(2))
417 	  {
418 	    bc_multiply (ex_stack->s_next->s_num, ex_stack->s_num,
419 			 &temp_num, scale);
420 	    pop();
421 	    pop();
422 	    push_num (temp_num);
423 	    bc_init_num (&temp_num);
424 	  }
425 	break;
426 
427       case '/' : /* divide */
428 	if (check_stack(2))
429 	  {
430 	    if (bc_divide (ex_stack->s_next->s_num,
431 			   ex_stack->s_num, &temp_num, scale) == 0)
432 	      {
433 		pop();
434 		pop();
435 		push_num (temp_num);
436 		bc_init_num (&temp_num);
437 	      }
438 	    else
439 	      rt_error ("Divide by zero");
440 	  }
441 	break;
442 
443       case '%' : /* remainder */
444 	if (check_stack(2))
445 	  {
446 	    if (bc_is_zero (ex_stack->s_num))
447 	      rt_error ("Modulo by zero");
448 	    else
449 	      {
450 		bc_modulo (ex_stack->s_next->s_num,
451 			   ex_stack->s_num, &temp_num, scale);
452 		pop();
453 		pop();
454 		push_num (temp_num);
455 		bc_init_num (&temp_num);
456 	      }
457 	  }
458 	break;
459 
460       case '^' : /* raise */
461 	if (check_stack(2))
462 	  {
463 	    bc_raise (ex_stack->s_next->s_num,
464 		      ex_stack->s_num, &temp_num, scale);
465 	    if (bc_is_zero (ex_stack->s_next->s_num) && bc_is_neg (ex_stack->s_num))
466 	      rt_error ("divide by zero");
467 	    pop();
468 	    pop();
469 	    push_num (temp_num);
470 	    bc_init_num (&temp_num);
471 	  }
472 	break;
473 
474       case '=' : /* compare equal */
475 	if (check_stack(2))
476 	  {
477 	    c_code = bc_compare (ex_stack->s_next->s_num,
478 				 ex_stack->s_num) == 0;
479 	    pop ();
480 	    assign (c_code);
481 	  }
482 	break;
483 
484       case '#' : /* compare not equal */
485 	if (check_stack(2))
486 	  {
487 	    c_code = bc_compare (ex_stack->s_next->s_num,
488 				 ex_stack->s_num) != 0;
489 	    pop ();
490 	    assign (c_code);
491 	  }
492 	break;
493 
494       case '<' : /* compare less than */
495 	if (check_stack(2))
496 	  {
497 	    c_code = bc_compare (ex_stack->s_next->s_num,
498 				 ex_stack->s_num) == -1;
499 	    pop ();
500 	    assign (c_code);
501 	  }
502 	break;
503 
504       case '{' : /* compare less than or equal */
505 	if (check_stack(2))
506 	  {
507 	    c_code = bc_compare (ex_stack->s_next->s_num,
508 				 ex_stack->s_num) <= 0;
509 	    pop ();
510 	    assign (c_code);
511 	  }
512 	break;
513 
514       case '>' : /* compare greater than */
515 	if (check_stack(2))
516 	  {
517 	    c_code = bc_compare (ex_stack->s_next->s_num,
518 				 ex_stack->s_num) == 1;
519 	    pop ();
520 	    assign (c_code);
521 	  }
522 	break;
523 
524       case '}' : /* compare greater than or equal */
525 	if (check_stack(2))
526 	  {
527 	    c_code = bc_compare (ex_stack->s_next->s_num,
528 				 ex_stack->s_num) >= 0;
529 	    pop ();
530 	    assign (c_code);
531 	  }
532 	break;
533 
534 	default  : /* error! */
535 	  rt_error ("bad instruction: inst=%c", inst);
536       }
537     }
538 
539   /* Clean up the function stack and pop all autos/parameters. */
540   while (pc.pc_func != 0)
541     {
542       pop_vars(functions[pc.pc_func].f_autos);
543       pop_vars(functions[pc.pc_func].f_params);
544       fpop ();
545       pc.pc_addr = fpop ();
546       pc.pc_func = fpop ();
547     }
548 
549   /* Clean up the execution stack. */
550   while (ex_stack != NULL) pop();
551 
552   /* Clean up the interrupt stuff. */
553   if (interactive)
554     {
555       signal (SIGINT, use_quit);
556       if (had_sigint)
557 	printf ("\ninterrupted execution.\n");
558     }
559 }
560 
561 
562 /* Prog_char gets another byte from the program.  It is used for
563    conversion of text constants in the code to numbers. */
564 
565 int
prog_char(void)566 prog_char (void)
567 {
568   return (int) byte(&pc);
569 }
570 
571 
572 /* Read a character from the standard input.  This function is used
573    by the "read" function. */
574 
575 int
input_char(void)576 input_char (void)
577 {
578   int in_ch;
579 
580   /* Get a character from the standard input for the read function. */
581   in_ch = getchar();
582 
583   /* Check for a \ quoted newline. */
584   if (in_ch == '\\')
585     {
586       in_ch = getchar();
587       if (in_ch == '\n') {
588 	  in_ch = getchar();
589 	  out_col = 0;  /* Saw a new line */
590 	}
591     }
592 
593   /* Classify and preprocess the input character. */
594   if (isdigit(in_ch))
595     return (in_ch - '0');
596   if (in_ch >= 'A' && in_ch <= 'Z')
597     return (in_ch + 10 - 'A');
598   if (in_ch >= 'a' && in_ch <= 'z')
599     return (in_ch + 10 - 'a');
600   if (in_ch == '.' || in_ch == '+' || in_ch == '-')
601     return (in_ch);
602   if (in_ch == '~')
603     return (':');
604   if (in_ch <= ' ')
605     return ('~');
606 
607   return (':');
608 }
609 
610 
611 /* Push_constant converts a sequence of input characters as returned
612    by IN_CHAR into a number.  The number is pushed onto the execution
613    stack.  The number is converted as a number in base CONV_BASE. */
614 
615 void
push_constant(int (* in_char)(VOID),int conv_base)616 push_constant (int (*in_char)(VOID), int conv_base)
617 {
618   int digits;
619   bc_num build, temp, result, mult, divisor;
620   int   in_ch, first_ch;
621   char  negative;
622 
623   /* Initialize all bc numbers */
624   bc_init_num (&temp);
625   bc_init_num (&result);
626   bc_init_num (&mult);
627   build = bc_copy_num (_zero_);
628   negative = FALSE;
629 
630   /* The conversion base. */
631   bc_int2num (&mult, conv_base);
632 
633   /* Get things ready. */
634   in_ch = in_char();
635   /* ~ is space returned by input_char(), prog_char does not return spaces. */
636   while (in_ch == '~')
637     in_ch = in_char();
638 
639   if (in_ch == '+')
640     in_ch = in_char();
641   else
642     if (in_ch == '-')
643       {
644 	negative = TRUE;
645 	in_ch = in_char();
646       }
647 
648   /* Check for the special case of a single digit. */
649   if (in_ch < 36)
650     {
651       first_ch = in_ch;
652       in_ch = in_char();
653       if (in_ch < 36 && first_ch >= conv_base)
654 	first_ch = conv_base - 1;
655       bc_int2num (&build, (int) first_ch);
656     }
657 
658   /* Convert the integer part. */
659   while (in_ch < 36)
660     {
661       if (in_ch < 36 && in_ch >= conv_base) in_ch = conv_base-1;
662       bc_multiply (build, mult, &result, 0);
663       bc_int2num (&temp, (int) in_ch);
664       bc_add (result, temp, &build, 0);
665       in_ch = in_char();
666     }
667   if (in_ch == '.')
668     {
669       in_ch = in_char();
670       if (in_ch >= conv_base) in_ch = conv_base-1;
671       bc_free_num (&result);
672       bc_free_num (&temp);
673       divisor = bc_copy_num (_one_);
674       result = bc_copy_num (_zero_);
675       digits = 0;
676       while (in_ch < 36)
677 	{
678 	  bc_multiply (result, mult, &result, 0);
679 	  bc_int2num (&temp, (int) in_ch);
680 	  bc_add (result, temp, &result, 0);
681 	  bc_multiply (divisor, mult, &divisor, 0);
682 	  digits++;
683 	  in_ch = in_char();
684 	  if (in_ch < 36 && in_ch >= conv_base) in_ch = conv_base-1;
685 	}
686       bc_divide (result, divisor, &result, digits);
687       bc_add (build, result, &build, 0);
688     }
689 
690   /* Final work.  */
691   if (negative)
692     bc_sub (_zero_, build, &build, 0);
693 
694   push_num (build);
695   bc_free_num (&temp);
696   bc_free_num (&result);
697   bc_free_num (&mult);
698 }
699 
700 
701 /* When converting base 10 constants from the program, we use this
702    more efficient way to convert them to numbers.  PC tells where
703    the constant starts and is expected to be advanced to after
704    the constant. */
705 
706 void
push_b10_const(program_counter * progctr)707 push_b10_const (program_counter *progctr)
708 {
709   bc_num build;
710   program_counter look_pc;
711   int kdigits, kscale;
712   unsigned char inchar;
713   char *ptr;
714 
715   /* Count the digits and get things ready. */
716   look_pc = *progctr;
717   kdigits = 0;
718   kscale  = 0;
719   inchar = byte (&look_pc);
720   while (inchar != '.' && inchar != ':')
721     {
722       kdigits++;
723       inchar = byte(&look_pc);
724     }
725   if (inchar == '.' )
726     {
727       inchar = byte(&look_pc);
728       while (inchar != ':')
729 	{
730 	  kscale++;
731 	  inchar = byte(&look_pc);
732 	}
733     }
734 
735   /* Get the first character again and move the progctr. */
736   inchar = byte(progctr);
737 
738   /* Secial cases of 0, 1, and A-F single inputs. */
739   if (kdigits == 1 && kscale == 0)
740     {
741       if (inchar == 0)
742 	{
743 	  push_copy (_zero_);
744 	  inchar = byte(progctr);
745 	  return;
746 	}
747       if (inchar == 1) {
748       push_copy (_one_);
749       inchar = byte(progctr);
750       return;
751     }
752     if (inchar > 9)
753       {
754 	bc_init_num (&build);
755 	bc_int2num (&build, inchar);
756 	push_num (build);
757 	inchar = byte(progctr);
758 	return;
759       }
760     }
761 
762   /* Build the new number. */
763   if (kdigits == 0)
764     {
765       build = bc_new_num (1,kscale);
766       ptr = build->n_value;
767       *ptr++ = 0;
768     }
769   else
770     {
771       build = bc_new_num (kdigits,kscale);
772       ptr = build->n_value;
773     }
774 
775   while (inchar != ':')
776     {
777       if (inchar != '.')
778 	{
779 	  if (inchar > 9)
780 	    *ptr++ = 9;
781 	  else
782 	    *ptr++ = inchar;
783 	}
784       inchar = byte(progctr);
785     }
786   push_num (build);
787 }
788 
789 
790 /* Put the correct value on the stack for C_CODE.  Frees TOS num. */
791 
792 void
assign(char code)793 assign (char code)
794 {
795   bc_free_num (&ex_stack->s_num);
796   if (code)
797     ex_stack->s_num = bc_copy_num (_one_);
798   else
799     ex_stack->s_num = bc_copy_num (_zero_);
800 }
801