Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / contrib / bc / bc / execute.c
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
39 int had_sigint;
40
41 void
42 stop_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
53 unsigned char
54 byte (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
63 void
64 execute ()
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
553 char
554 prog_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
563 char
564 input_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
599 void
600 push_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
691 void
692 push_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
778 void
779 assign (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