1 /* execute.c - run a bc program. */
3 /* This file is part of GNU bc.
4 Copyright (C) 1991-1994, 1997, 2000 Free Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License , or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; see the file COPYING. If not, write to
18 The Free Software Foundation, Inc.
19 59 Temple Place, Suite 330
22 You may contact the author by:
23 e-mail: philnelson@acm.org
24 us-mail: Philip A. Nelson
25 Computer Science Department, 9062
26 Western Washington University
27 Bellingham, WA 98226-9062
29 *************************************************************************/
37 /* The SIGINT interrupt handling routine. */
47 rt_error ("interrupted execution");
51 /* Get the current byte and advance the PC counter. */
57 return (functions[pc->pc_func].f_body[pc->pc_addr++]);
61 /* The routine that actually runs the machine. */
66 int label_num, l_gp, l_off;
78 /* Initialize this run... */
81 runtime_error = FALSE;
82 bc_init_num (&temp_num);
84 /* Set up the interrupt mechanism for an interactive session. */
87 signal (SIGINT, stop_execution);
91 while (pc.pc_addr < functions[pc.pc_func].f_code_size && !runtime_error)
96 { /* Print out address and the stack before each instruction.*/
97 int depth; estack_rec *temp = ex_stack;
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);
106 printf (" %d = ", depth);
107 bc_out_num (temp->s_num, 10, out_char, std_only);
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);
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);
130 case 'J' : /* Jump to a label. */
131 label_num = byte(&pc); /* Low order bits first. */
132 label_num += byte(&pc) << 8;
133 if (inst == 'J' || (inst == 'B' && c_code)
134 || (inst == 'Z' && !c_code)) {
135 gp = functions[pc.pc_func].f_label;
136 l_gp = label_num >> BC_LABEL_LOG;
137 l_off = label_num % BC_LABEL_GROUP;
138 while (l_gp-- > 0) gp = gp->l_next;
139 pc.pc_addr = gp->l_adrs[l_off];
143 case 'C' : /* Call a function. */
144 /* Get the function number. */
145 new_func = byte(&pc);
146 if ((new_func & 0x80) != 0)
147 new_func = ((new_func & 0x7f) << 8) + byte(&pc);
149 /* Check to make sure it is defined. */
150 if (!functions[new_func].f_defined)
152 rt_error ("Function %s not defined.", f_names[new_func]);
156 /* Check and push parameters. */
157 process_params (&pc, new_func);
159 /* Push auto variables. */
160 for (auto_list = functions[new_func].f_autos;
162 auto_list = auto_list->next)
163 auto_var (auto_list->av_name);
165 /* Push pc and ibase. */
170 /* Reset pc to start of function. */
171 pc.pc_func = new_func;
175 case 'D' : /* Duplicate top of stack */
176 push_copy (ex_stack->s_num);
179 case 'K' : /* Push a constant */
180 /* Get the input base and convert it to a bc number. */
184 const_base = fn_stack->s_val;
185 if (const_base == 10)
186 push_b10_const (&pc);
188 push_constant (prog_char, const_base);
191 case 'L' : /* load array variable */
192 var_name = byte(&pc);
193 if ((var_name & 0x80) != 0)
194 var_name = ((var_name & 0x7f) << 8) + byte(&pc);
195 load_array (var_name);
198 case 'M' : /* decrement array variable (Minus!) */
199 var_name = byte(&pc);
200 if ((var_name & 0x80) != 0)
201 var_name = ((var_name & 0x7f) << 8) + byte(&pc);
202 decr_array (var_name);
205 case 'O' : /* Write a string to the output with processing. */
206 while ((ch = byte(&pc)) != '"')
212 if (ch == '"') break;
215 case 'a': out_schar (007); break;
216 case 'b': out_schar ('\b'); break;
217 case 'f': out_schar ('\f'); break;
218 case 'n': out_schar ('\n'); break;
219 case 'q': out_schar ('"'); break;
220 case 'r': out_schar ('\r'); break;
221 case 't': out_schar ('\t'); break;
222 case '\\': out_schar ('\\'); break;
229 case 'R' : /* Return from function */
232 /* "Pop" autos and parameters. */
233 pop_vars(functions[pc.pc_func].f_autos);
234 pop_vars(functions[pc.pc_func].f_params);
237 pc.pc_addr = fpop ();
238 pc.pc_func = fpop ();
241 rt_error ("Return from main program.");
244 case 'S' : /* store array variable */
245 var_name = byte(&pc);
246 if ((var_name & 0x80) != 0)
247 var_name = ((var_name & 0x7f ) << 8) + byte(&pc);
248 store_array (var_name);
251 case 'T' : /* Test tos for zero */
252 c_code = bc_is_zero (ex_stack->s_num);
256 case 'W' : /* Write the value on the top of the stack. */
257 case 'P' : /* Write the value on the top of the stack. No newline. */
258 bc_out_num (ex_stack->s_num, o_base, out_char, std_only);
259 if (inst == 'W') out_char ('\n');
260 store_var (4); /* Special variable "last". */
265 case 'c' : /* Call special function. */
266 new_func = byte(&pc);
270 case 'L': /* Length function. */
271 /* For the number 0.xxxx, 0 is not significant. */
272 if (ex_stack->s_num->n_len == 1 &&
273 ex_stack->s_num->n_scale != 0 &&
274 ex_stack->s_num->n_value[0] == 0 )
275 bc_int2num (&ex_stack->s_num, ex_stack->s_num->n_scale);
277 bc_int2num (&ex_stack->s_num, ex_stack->s_num->n_len
278 + ex_stack->s_num->n_scale);
281 case 'S': /* Scale function. */
282 bc_int2num (&ex_stack->s_num, ex_stack->s_num->n_scale);
285 case 'R': /* Square Root function. */
286 if (!bc_sqrt (&ex_stack->s_num, scale))
287 rt_error ("Square root of a negative number");
290 case 'I': /* Read function. */
291 push_constant (input_char, i_base);
296 case 'd' : /* Decrement number */
297 var_name = byte(&pc);
298 if ((var_name & 0x80) != 0)
299 var_name = ((var_name & 0x7f) << 8) + byte(&pc);
303 case 'h' : /* Halt the machine. */
306 case 'i' : /* increment number */
307 var_name = byte(&pc);
308 if ((var_name & 0x80) != 0)
309 var_name = ((var_name & 0x7f) << 8) + byte(&pc);
313 case 'l' : /* load variable */
314 var_name = byte(&pc);
315 if ((var_name & 0x80) != 0)
316 var_name = ((var_name & 0x7f) << 8) + byte(&pc);
320 case 'n' : /* Negate top of stack. */
321 bc_sub (_zero_, ex_stack->s_num, &ex_stack->s_num, 0);
324 case 'p' : /* Pop the execution stack. */
328 case 's' : /* store variable */
329 var_name = byte(&pc);
330 if ((var_name & 0x80) != 0)
331 var_name = ((var_name & 0x7f) << 8) + byte(&pc);
332 store_var (var_name);
335 case 'w' : /* Write a string to the output. */
336 while ((ch = byte(&pc)) != '"') out_schar (ch);
340 case 'x' : /* Exchange Top of Stack with the one under the tos. */
341 if (check_stack(2)) {
342 bc_num temp = ex_stack->s_num;
343 ex_stack->s_num = ex_stack->s_next->s_num;
344 ex_stack->s_next->s_num = temp;
348 case '0' : /* Load Constant 0. */
352 case '1' : /* Load Constant 0. */
356 case '!' : /* Negate the boolean value on top of the stack. */
357 c_code = bc_is_zero (ex_stack->s_num);
361 case '&' : /* compare greater than */
364 c_code = !bc_is_zero (ex_stack->s_next->s_num)
365 && !bc_is_zero (ex_stack->s_num);
371 case '|' : /* compare greater than */
374 c_code = !bc_is_zero (ex_stack->s_next->s_num)
375 || !bc_is_zero (ex_stack->s_num);
384 bc_add (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num, 0);
388 bc_init_num (&temp_num);
392 case '-' : /* subtract */
395 bc_sub (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num, 0);
399 bc_init_num (&temp_num);
403 case '*' : /* multiply */
406 bc_multiply (ex_stack->s_next->s_num, ex_stack->s_num,
411 bc_init_num (&temp_num);
415 case '/' : /* divide */
418 if (bc_divide (ex_stack->s_next->s_num,
419 ex_stack->s_num, &temp_num, scale) == 0)
424 bc_init_num (&temp_num);
427 rt_error ("Divide by zero");
431 case '%' : /* remainder */
434 if (bc_is_zero (ex_stack->s_num))
435 rt_error ("Modulo by zero");
438 bc_modulo (ex_stack->s_next->s_num,
439 ex_stack->s_num, &temp_num, scale);
443 bc_init_num (&temp_num);
448 case '^' : /* raise */
451 bc_raise (ex_stack->s_next->s_num,
452 ex_stack->s_num, &temp_num, scale);
453 if (bc_is_zero (ex_stack->s_next->s_num) && bc_is_neg (ex_stack->s_num))
454 rt_error ("divide by zero");
458 bc_init_num (&temp_num);
462 case '=' : /* compare equal */
465 c_code = bc_compare (ex_stack->s_next->s_num,
466 ex_stack->s_num) == 0;
472 case '#' : /* compare not equal */
475 c_code = bc_compare (ex_stack->s_next->s_num,
476 ex_stack->s_num) != 0;
482 case '<' : /* compare less than */
485 c_code = bc_compare (ex_stack->s_next->s_num,
486 ex_stack->s_num) == -1;
492 case '{' : /* compare less than or equal */
495 c_code = bc_compare (ex_stack->s_next->s_num,
496 ex_stack->s_num) <= 0;
502 case '>' : /* compare greater than */
505 c_code = bc_compare (ex_stack->s_next->s_num,
506 ex_stack->s_num) == 1;
512 case '}' : /* compare greater than or equal */
515 c_code = bc_compare (ex_stack->s_next->s_num,
516 ex_stack->s_num) >= 0;
522 default : /* error! */
523 rt_error ("bad instruction: inst=%c", inst);
527 /* Clean up the function stack and pop all autos/parameters. */
528 while (pc.pc_func != 0)
530 pop_vars(functions[pc.pc_func].f_autos);
531 pop_vars(functions[pc.pc_func].f_params);
533 pc.pc_addr = fpop ();
534 pc.pc_func = fpop ();
537 /* Clean up the execution stack. */
538 while (ex_stack != NULL) pop();
540 /* Clean up the interrupt stuff. */
543 signal (SIGINT, use_quit);
545 printf ("Interruption completed.\n");
550 /* Prog_char gets another byte from the program. It is used for
551 conversion of text constants in the code to numbers. */
560 /* Read a character from the standard input. This function is used
561 by the "read" function. */
568 /* Get a character from the standard input for the read function. */
571 /* Check for a \ quoted newline. */
579 /* Classify and preprocess the input character. */
580 if (isdigit((int)in_ch))
581 return (in_ch - '0');
582 if (in_ch >= 'A' && in_ch <= 'F')
583 return (in_ch + 10 - 'A');
584 if (in_ch >= 'a' && in_ch <= 'f')
585 return (in_ch + 10 - 'a');
586 if (in_ch == '.' || in_ch == '+' || in_ch == '-')
595 /* Push_constant converts a sequence of input characters as returned
596 by IN_CHAR into a number. The number is pushed onto the execution
597 stack. The number is converted as a number in base CONV_BASE. */
600 push_constant (in_char, conv_base)
601 char (*in_char)(VOID);
605 bc_num build, temp, result, mult, divisor;
606 char in_ch, first_ch;
609 /* Initialize all bc numbers */
611 bc_init_num (&result);
613 build = bc_copy_num (_zero_);
616 /* The conversion base. */
617 bc_int2num (&mult, conv_base);
619 /* Get things ready. */
633 /* Check for the special case of a single digit. */
638 if (in_ch < 16 && first_ch >= conv_base)
639 first_ch = conv_base - 1;
640 bc_int2num (&build, (int) first_ch);
643 /* Convert the integer part. */
646 if (in_ch < 16 && in_ch >= conv_base) in_ch = conv_base-1;
647 bc_multiply (build, mult, &result, 0);
648 bc_int2num (&temp, (int) in_ch);
649 bc_add (result, temp, &build, 0);
655 if (in_ch >= conv_base) in_ch = conv_base-1;
656 bc_free_num (&result);
658 divisor = bc_copy_num (_one_);
659 result = bc_copy_num (_zero_);
663 bc_multiply (result, mult, &result, 0);
664 bc_int2num (&temp, (int) in_ch);
665 bc_add (result, temp, &result, 0);
666 bc_multiply (divisor, mult, &divisor, 0);
669 if (in_ch < 16 && in_ch >= conv_base) in_ch = conv_base-1;
671 bc_divide (result, divisor, &result, digits);
672 bc_add (build, result, &build, 0);
677 bc_sub (_zero_, build, &build, 0);
681 bc_free_num (&result);
686 /* When converting base 10 constants from the program, we use this
687 more efficient way to convert them to numbers. PC tells where
688 the constant starts and is expected to be advanced to after
696 program_counter look_pc;
701 /* Count the digits and get things ready. */
705 inchar = byte (&look_pc);
706 while (inchar != '.' && inchar != ':')
709 inchar = byte(&look_pc);
713 inchar = byte(&look_pc);
714 while (inchar != ':')
717 inchar = byte(&look_pc);
721 /* Get the first character again and move the pc. */
724 /* Secial cases of 0, 1, and A-F single inputs. */
725 if (kdigits == 1 && kscale == 0)
740 bc_init_num (&build);
741 bc_int2num (&build, inchar);
748 /* Build the new number. */
751 build = bc_new_num (1,kscale);
752 ptr = build->n_value;
757 build = bc_new_num (kdigits,kscale);
758 ptr = build->n_value;
761 while (inchar != ':')
776 /* Put the correct value on the stack for C_CODE. Frees TOS num. */
782 bc_free_num (&ex_stack->s_num);
784 ex_stack->s_num = bc_copy_num (_one_);
786 ex_stack->s_num = bc_copy_num (_zero_);