1/* execute.c - run a bc program. */
2
3/*  This file is part of GNU bc.
4    Copyright (C) 1991-1994, 1997, 2000 Free Software Foundation, Inc.
5
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.
10
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.
15
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
20      Boston, MA 02111 USA
21
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
28
29*************************************************************************/
30
31#include "bcdefs.h"
32#include <signal.h>
33#include "global.h"
34#include "proto.h"
35
36
37/* The SIGINT interrupt handling routine. */
38
39int had_sigint;
40
41void
42stop_execution (sig)
43     int sig;
44{
45  had_sigint = TRUE;
46  printf ("\n");
47  rt_error ("interrupted execution");
48}
49
50
51/* Get the current byte and advance the PC counter. */
52
53unsigned char
54byte (pc)
55     program_counter *pc;
56{
57  return (functions[pc->pc_func].f_body[pc->pc_addr++]);
58}
59
60
61/* The routine that actually runs the machine. */
62
63void
64execute ()
65{
66  int label_num, l_gp, l_off;
67  bc_label_group *gp;
68
69  char inst, ch;
70  int  new_func;
71  int  var_name;
72
73  int const_base;
74
75  bc_num temp_num;
76  arg_list *auto_list;
77
78  /* Initialize this run... */
79  pc.pc_func = 0;
80  pc.pc_addr = 0;
81  runtime_error = FALSE;
82  bc_init_num (&temp_num);
83
84  /* Set up the interrupt mechanism for an interactive session. */
85  if (interactive)
86    {
87      signal (SIGINT, stop_execution);
88      had_sigint = FALSE;
89    }
90
91  while (pc.pc_addr < functions[pc.pc_func].f_code_size && !runtime_error)
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      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];
140	}
141	break;
142
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);
148
149	/* Check to make sure it is defined. */
150	if (!functions[new_func].f_defined)
151	  {
152	    rt_error ("Function %s not defined.", f_names[new_func]);
153	    break;
154	  }
155
156	/* Check and push parameters. */
157	process_params (&pc, new_func);
158
159	/* Push auto variables. */
160	for (auto_list = functions[new_func].f_autos;
161	     auto_list != NULL;
162	     auto_list = auto_list->next)
163	  auto_var (auto_list->av_name);
164
165	/* Push pc and ibase. */
166	fpush (pc.pc_func);
167	fpush (pc.pc_addr);
168	fpush (i_base);
169
170	/* Reset pc to start of function. */
171	pc.pc_func = new_func;
172	pc.pc_addr = 0;
173	break;
174
175      case 'D' : /* Duplicate top of stack */
176	push_copy (ex_stack->s_num);
177	break;
178
179      case 'K' : /* Push a constant */
180	/* Get the input base and convert it to a bc number. */
181	if (pc.pc_func == 0)
182	  const_base = i_base;
183	else
184	  const_base = fn_stack->s_val;
185	if (const_base == 10)
186	  push_b10_const (&pc);
187	else
188	  push_constant (prog_char, const_base);
189	break;
190
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);
196	break;
197
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);
203	break;
204
205      case 'O' : /* Write a string to the output with processing. */
206	while ((ch = byte(&pc)) != '"')
207	  if (ch != '\\')
208	    out_schar (ch);
209	  else
210	    {
211	      ch = byte(&pc);
212	      if (ch == '"') break;
213	      switch (ch)
214		{
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;
223		default:  break;
224		}
225	    }
226	fflush (stdout);
227	break;
228
229      case 'R' : /* Return from function */
230	if (pc.pc_func != 0)
231	  {
232	    /* "Pop" autos and parameters. */
233	    pop_vars(functions[pc.pc_func].f_autos);
234	    pop_vars(functions[pc.pc_func].f_params);
235	    /* reset the pc. */
236	    fpop ();
237	    pc.pc_addr = fpop ();
238	    pc.pc_func = fpop ();
239	  }
240	else
241	  rt_error ("Return from main program.");
242	break;
243
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);
249	break;
250
251      case 'T' : /* Test tos for zero */
252	c_code = bc_is_zero (ex_stack->s_num);
253	assign (c_code);
254	break;
255
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". */
261	fflush (stdout);
262	pop ();
263	break;
264
265      case 'c' : /* Call special function. */
266	new_func = byte(&pc);
267
268      switch (new_func)
269	{
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);
276	  else
277	    bc_int2num (&ex_stack->s_num, ex_stack->s_num->n_len
278		     + ex_stack->s_num->n_scale);
279	  break;
280
281	case 'S':  /* Scale function. */
282	  bc_int2num (&ex_stack->s_num, ex_stack->s_num->n_scale);
283	  break;
284
285	case 'R':  /* Square Root function. */
286	  if (!bc_sqrt (&ex_stack->s_num, scale))
287	    rt_error ("Square root of a negative number");
288	  break;
289
290	case 'I': /* Read function. */
291	  push_constant (input_char, i_base);
292	  break;
293	}
294	break;
295
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);
300	decr_var (var_name);
301	break;
302
303      case 'h' : /* Halt the machine. */
304	exit (0);
305
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);
310	incr_var (var_name);
311	break;
312
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);
317	load_var (var_name);
318	break;
319
320      case 'n' : /* Negate top of stack. */
321	bc_sub (_zero_, ex_stack->s_num, &ex_stack->s_num, 0);
322	break;
323
324      case 'p' : /* Pop the execution stack. */
325	pop ();
326	break;
327
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);
333	break;
334
335      case 'w' : /* Write a string to the output. */
336	while ((ch = byte(&pc)) != '"') out_schar (ch);
337	fflush (stdout);
338	break;
339
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;
345	}
346	break;
347
348      case '0' : /* Load Constant 0. */
349	push_copy (_zero_);
350	break;
351
352      case '1' : /* Load Constant 0. */
353	push_copy (_one_);
354	break;
355
356      case '!' : /* Negate the boolean value on top of the stack. */
357	c_code = bc_is_zero (ex_stack->s_num);
358	assign (c_code);
359	break;
360
361      case '&' : /* compare greater than */
362	if (check_stack(2))
363	  {
364	    c_code = !bc_is_zero (ex_stack->s_next->s_num)
365	      && !bc_is_zero (ex_stack->s_num);
366	    pop ();
367	    assign (c_code);
368	  }
369	break;
370
371      case '|' : /* compare greater than */
372	if (check_stack(2))
373	  {
374	    c_code = !bc_is_zero (ex_stack->s_next->s_num)
375	      || !bc_is_zero (ex_stack->s_num);
376	    pop ();
377	    assign (c_code);
378	  }
379	break;
380
381      case '+' : /* add */
382	if (check_stack(2))
383	  {
384	    bc_add (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num, 0);
385	    pop();
386	    pop();
387	    push_num (temp_num);
388	    bc_init_num (&temp_num);
389	  }
390	break;
391
392      case '-' : /* subtract */
393	if (check_stack(2))
394	  {
395	    bc_sub (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num, 0);
396	    pop();
397	    pop();
398	    push_num (temp_num);
399	    bc_init_num (&temp_num);
400	  }
401	break;
402
403      case '*' : /* multiply */
404	if (check_stack(2))
405	  {
406	    bc_multiply (ex_stack->s_next->s_num, ex_stack->s_num,
407			 &temp_num, scale);
408	    pop();
409	    pop();
410	    push_num (temp_num);
411	    bc_init_num (&temp_num);
412	  }
413	break;
414
415      case '/' : /* divide */
416	if (check_stack(2))
417	  {
418	    if (bc_divide (ex_stack->s_next->s_num,
419			   ex_stack->s_num, &temp_num, scale) == 0)
420	      {
421		pop();
422		pop();
423		push_num (temp_num);
424		bc_init_num (&temp_num);
425	      }
426	    else
427	      rt_error ("Divide by zero");
428	  }
429	break;
430
431      case '%' : /* remainder */
432	if (check_stack(2))
433	  {
434	    if (bc_is_zero (ex_stack->s_num))
435	      rt_error ("Modulo by zero");
436	    else
437	      {
438		bc_modulo (ex_stack->s_next->s_num,
439			   ex_stack->s_num, &temp_num, scale);
440		pop();
441		pop();
442		push_num (temp_num);
443		bc_init_num (&temp_num);
444	      }
445	  }
446	break;
447
448      case '^' : /* raise */
449	if (check_stack(2))
450	  {
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");
455	    pop();
456	    pop();
457	    push_num (temp_num);
458	    bc_init_num (&temp_num);
459	  }
460	break;
461
462      case '=' : /* compare equal */
463	if (check_stack(2))
464	  {
465	    c_code = bc_compare (ex_stack->s_next->s_num,
466				 ex_stack->s_num) == 0;
467	    pop ();
468	    assign (c_code);
469	  }
470	break;
471
472      case '#' : /* compare not equal */
473	if (check_stack(2))
474	  {
475	    c_code = bc_compare (ex_stack->s_next->s_num,
476				 ex_stack->s_num) != 0;
477	    pop ();
478	    assign (c_code);
479	  }
480	break;
481
482      case '<' : /* compare less than */
483	if (check_stack(2))
484	  {
485	    c_code = bc_compare (ex_stack->s_next->s_num,
486				 ex_stack->s_num) == -1;
487	    pop ();
488	    assign (c_code);
489	  }
490	break;
491
492      case '{' : /* compare less than or equal */
493	if (check_stack(2))
494	  {
495	    c_code = bc_compare (ex_stack->s_next->s_num,
496				 ex_stack->s_num) <= 0;
497	    pop ();
498	    assign (c_code);
499	  }
500	break;
501
502      case '>' : /* compare greater than */
503	if (check_stack(2))
504	  {
505	    c_code = bc_compare (ex_stack->s_next->s_num,
506				 ex_stack->s_num) == 1;
507	    pop ();
508	    assign (c_code);
509	  }
510	break;
511
512      case '}' : /* compare greater than or equal */
513	if (check_stack(2))
514	  {
515	    c_code = bc_compare (ex_stack->s_next->s_num,
516				 ex_stack->s_num) >= 0;
517	    pop ();
518	    assign (c_code);
519	  }
520	break;
521
522	default  : /* error! */
523	  rt_error ("bad instruction: inst=%c", inst);
524      }
525    }
526
527  /* Clean up the function stack and pop all autos/parameters. */
528  while (pc.pc_func != 0)
529    {
530      pop_vars(functions[pc.pc_func].f_autos);
531      pop_vars(functions[pc.pc_func].f_params);
532      fpop ();
533      pc.pc_addr = fpop ();
534      pc.pc_func = fpop ();
535    }
536
537  /* Clean up the execution stack. */
538  while (ex_stack != NULL) pop();
539
540  /* Clean up the interrupt stuff. */
541  if (interactive)
542    {
543      signal (SIGINT, use_quit);
544      if (had_sigint)
545	printf ("Interruption completed.\n");
546    }
547}
548
549
550/* Prog_char gets another byte from the program.  It is used for
551   conversion of text constants in the code to numbers. */
552
553char
554prog_char ()
555{
556  return byte(&pc);
557}
558
559
560/* Read a character from the standard input.  This function is used
561   by the "read" function. */
562
563char
564input_char ()
565{
566  char in_ch;
567
568  /* Get a character from the standard input for the read function. */
569  in_ch = getchar();
570
571  /* Check for a \ quoted newline. */
572  if (in_ch == '\\')
573    {
574      in_ch = getchar();
575      if (in_ch == '\n')
576	in_ch = getchar();
577    }
578
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 == '-')
587    return (in_ch);
588  if (in_ch <= ' ')
589    return (' ');
590
591  return (':');
592}
593
594
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. */
598
599void
600push_constant (in_char, conv_base)
601   char (*in_char)(VOID);
602   int conv_base;
603{
604  int digits;
605  bc_num build, temp, result, mult, divisor;
606  char  in_ch, first_ch;
607  char  negative;
608
609  /* Initialize all bc numbers */
610  bc_init_num (&temp);
611  bc_init_num (&result);
612  bc_init_num (&mult);
613  build = bc_copy_num (_zero_);
614  negative = FALSE;
615
616  /* The conversion base. */
617  bc_int2num (&mult, conv_base);
618
619  /* Get things ready. */
620  in_ch = in_char();
621  while (in_ch == ' ')
622    in_ch = in_char();
623
624  if (in_ch == '+')
625    in_ch = in_char();
626  else
627    if (in_ch == '-')
628      {
629	negative = TRUE;
630	in_ch = in_char();
631      }
632
633  /* Check for the special case of a single digit. */
634  if (in_ch < 16)
635    {
636      first_ch = in_ch;
637      in_ch = in_char();
638      if (in_ch < 16 && first_ch >= conv_base)
639	first_ch = conv_base - 1;
640      bc_int2num (&build, (int) first_ch);
641    }
642
643  /* Convert the integer part. */
644  while (in_ch < 16)
645    {
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);
650      in_ch = in_char();
651    }
652  if (in_ch == '.')
653    {
654      in_ch = in_char();
655      if (in_ch >= conv_base) in_ch = conv_base-1;
656      bc_free_num (&result);
657      bc_free_num (&temp);
658      divisor = bc_copy_num (_one_);
659      result = bc_copy_num (_zero_);
660      digits = 0;
661      while (in_ch < 16)
662	{
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);
667	  digits++;
668	  in_ch = in_char();
669	  if (in_ch < 16 && in_ch >= conv_base) in_ch = conv_base-1;
670	}
671      bc_divide (result, divisor, &result, digits);
672      bc_add (build, result, &build, 0);
673    }
674
675  /* Final work.  */
676  if (negative)
677    bc_sub (_zero_, build, &build, 0);
678
679  push_num (build);
680  bc_free_num (&temp);
681  bc_free_num (&result);
682  bc_free_num (&mult);
683}
684
685
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
689   the constant. */
690
691void
692push_b10_const (pc)
693     program_counter *pc;
694{
695  bc_num build;
696  program_counter look_pc;
697  int kdigits, kscale;
698  char inchar;
699  char *ptr;
700
701  /* Count the digits and get things ready. */
702  look_pc = *pc;
703  kdigits = 0;
704  kscale  = 0;
705  inchar = byte (&look_pc);
706  while (inchar != '.' && inchar != ':')
707    {
708      kdigits++;
709      inchar = byte(&look_pc);
710    }
711  if (inchar == '.' )
712    {
713      inchar = byte(&look_pc);
714      while (inchar != ':')
715	{
716	  kscale++;
717	  inchar = byte(&look_pc);
718	}
719    }
720
721  /* Get the first character again and move the pc. */
722  inchar = byte(pc);
723
724  /* Secial cases of 0, 1, and A-F single inputs. */
725  if (kdigits == 1 && kscale == 0)
726    {
727      if (inchar == 0)
728	{
729	  push_copy (_zero_);
730	  inchar = byte(pc);
731	  return;
732	}
733      if (inchar == 1) {
734      push_copy (_one_);
735      inchar = byte(pc);
736      return;
737    }
738    if (inchar > 9)
739      {
740	bc_init_num (&build);
741	bc_int2num (&build, inchar);
742	push_num (build);
743	inchar = byte(pc);
744	return;
745      }
746    }
747
748  /* Build the new number. */
749  if (kdigits == 0)
750    {
751      build = bc_new_num (1,kscale);
752      ptr = build->n_value;
753      *ptr++ = 0;
754    }
755  else
756    {
757      build = bc_new_num (kdigits,kscale);
758      ptr = build->n_value;
759    }
760
761  while (inchar != ':')
762    {
763      if (inchar != '.')
764	{
765	  if (inchar > 9)
766	    *ptr++ = 9;
767	  else
768	    *ptr++ = inchar;
769	}
770      inchar = byte(pc);
771    }
772  push_num (build);
773}
774
775
776/* Put the correct value on the stack for C_CODE.  Frees TOS num. */
777
778void
779assign (c_code)
780     char c_code;
781{
782  bc_free_num (&ex_stack->s_num);
783  if (c_code)
784    ex_stack->s_num = bc_copy_num (_one_);
785  else
786    ex_stack->s_num = bc_copy_num (_zero_);
787}
788
789