1 /* This file is part of GNU bc.
2
3 Copyright (C) 1991-1994, 1997, 2006, 2008, 2012-2017 Free Software Foundation, Inc.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License , or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING. If not, see
17 <http://www.gnu.org/licenses>.
18
19 You may contact the author by:
20 e-mail: philnelson@acm.org
21 us-mail: Philip A. Nelson
22 Computer Science Department, 9062
23 Western Washington University
24 Bellingham, WA 98226-9062
25
26 *************************************************************************/
27
28 /* util.c: Utility routines for bc. */
29
30 #include "bcdefs.h"
31 #ifndef VARARGS
32 #include <stdarg.h>
33 #else
34 #include <varargs.h>
35 #endif
36 #include "proto.h"
37
38
39 /* strcopyof mallocs new memory and copies a string to to the new
40 memory. */
41
42 char *
strcopyof(const char * str)43 strcopyof (const char *str)
44 {
45 char *temp;
46
47 temp = bc_malloc (strlen (str)+1);
48 return (strcpy (temp,str));
49 }
50
51
52 /* nextarg adds another value to the list of arguments. */
53
54 arg_list *
nextarg(arg_list * args,int val,int is_var)55 nextarg (arg_list *args, int val, int is_var)
56 { arg_list *temp;
57
58 temp = bc_malloc (sizeof (arg_list));
59 temp->av_name = val;
60 temp->arg_is_var = is_var;
61 temp->next = args;
62
63 return (temp);
64 }
65
66
67 /* For generate, we must produce a string in the form
68 "val,val,...,val". We also need a couple of static variables
69 for retaining old generated strings. It also uses a recursive
70 function that builds the string. */
71
72 static char *arglist1 = NULL, *arglist2 = NULL;
73
74
75 /* make_arg_str does the actual construction of the argument string.
76 ARGS is the pointer to the list and LEN is the maximum number of
77 characters needed. 1 char is the minimum needed.
78 */
79
80 static char *make_arg_str (arg_list *args, int len);
81
82 static char *
make_arg_str(arg_list * args,int len)83 make_arg_str (arg_list *args, int len)
84 {
85 char *temp;
86 char sval[30];
87
88 /* Recursive call. */
89 if (args != NULL)
90 temp = make_arg_str (args->next, len+12);
91 else
92 {
93 temp = bc_malloc (len);
94 *temp = 0;
95 return temp;
96 }
97
98 /* Add the current number to the end of the string. */
99 if (args->arg_is_var)
100 if (len != 1)
101 snprintf (sval, sizeof(sval), "*%d,", args->av_name);
102 else
103 snprintf (sval, sizeof(sval), "*%d", args->av_name);
104 else
105 if (len != 1)
106 snprintf (sval, sizeof(sval), "%d,", args->av_name);
107 else
108 snprintf (sval, sizeof(sval), "%d", args->av_name);
109 temp = strcat (temp, sval);
110 return (temp);
111 }
112
113 char *
arg_str(arg_list * args)114 arg_str (arg_list *args)
115 {
116 if (arglist2 != NULL)
117 free (arglist2);
118 arglist2 = arglist1;
119 arglist1 = make_arg_str (args, 1);
120 return (arglist1);
121 }
122
123 char *
call_str(arg_list * args)124 call_str (arg_list *args)
125 {
126 arg_list *temp;
127 int arg_count;
128 int ix;
129
130 if (arglist2 != NULL)
131 free (arglist2);
132 arglist2 = arglist1;
133
134 /* Count the number of args and add the 0's and 1's. */
135 for (temp = args, arg_count = 0; temp != NULL; temp = temp->next)
136 arg_count++;
137 arglist1 = bc_malloc(arg_count+1);
138 for (temp = args, ix=0; temp != NULL; temp = temp->next)
139 arglist1[ix++] = ( temp->av_name ? '1' : '0');
140 arglist1[ix] = 0;
141
142 return (arglist1);
143 }
144
145 /* free_args frees an argument list ARGS. */
146
147 void
free_args(arg_list * args)148 free_args (arg_list *args)
149 {
150 arg_list *temp;
151
152 temp = args;
153 while (temp != NULL)
154 {
155 args = args->next;
156 free (temp);
157 temp = args;
158 }
159 }
160
161
162 /* Check for valid parameter (PARAMS) and auto (AUTOS) lists.
163 There must be no duplicates any where. Also, this is where
164 warnings are generated for array parameters. */
165
166 void
check_params(arg_list * params,arg_list * autos)167 check_params (arg_list *params, arg_list *autos)
168 {
169 arg_list *tmp1, *tmp2;
170
171 /* Check for duplicate parameters. */
172 if (params != NULL)
173 {
174 tmp1 = params;
175 while (tmp1 != NULL)
176 {
177 tmp2 = tmp1->next;
178 while (tmp2 != NULL)
179 {
180 if (tmp2->av_name == tmp1->av_name)
181 yyerror ("duplicate parameter names");
182 tmp2 = tmp2->next;
183 }
184 if (tmp1->arg_is_var)
185 ct_warn ("Variable array parameter");
186 tmp1 = tmp1->next;
187 }
188 }
189
190 /* Check for duplicate autos. */
191 if (autos != NULL)
192 {
193 tmp1 = autos;
194 while (tmp1 != NULL)
195 {
196 tmp2 = tmp1->next;
197 while (tmp2 != NULL)
198 {
199 if (tmp2->av_name == tmp1->av_name)
200 yyerror ("duplicate auto variable names");
201 tmp2 = tmp2->next;
202 }
203 if (tmp1->arg_is_var)
204 yyerror ("* not allowed here");
205 tmp1 = tmp1->next;
206 }
207 }
208
209 /* Check for duplicate between parameters and autos. */
210 if ((params != NULL) && (autos != NULL))
211 {
212 tmp1 = params;
213 while (tmp1 != NULL)
214 {
215 tmp2 = autos;
216 while (tmp2 != NULL)
217 {
218 if (tmp2->av_name == tmp1->av_name)
219 yyerror ("variable in both parameter and auto lists");
220 tmp2 = tmp2->next;
221 }
222 tmp1 = tmp1->next;
223 }
224 }
225 }
226
227 /* genstr management to avoid buffer overflow. */
228 void
set_genstr_size(int size)229 set_genstr_size (int size)
230 {
231 if (size > genlen) {
232 if (genstr != NULL)
233 free(genstr);
234 genstr = bc_malloc (size);
235 genlen = size;
236 }
237 }
238
239
240 /* Initialize the code generator the parser. */
241
242 void
init_gen(void)243 init_gen (void)
244 {
245 /* Get things ready. */
246 break_label = 0;
247 continue_label = 0;
248 next_label = 1;
249 out_count = 2;
250 if (compile_only)
251 printf ("@i");
252 else
253 init_load ();
254 had_error = FALSE;
255 did_gen = FALSE;
256 set_genstr_size (64);
257 }
258
259
260 /* generate code STR for the machine. */
261
262 void
generate(const char * str)263 generate (const char *str)
264 {
265 did_gen = TRUE;
266 if (compile_only)
267 {
268 printf ("%s",str);
269 out_count += strlen(str);
270 if (out_count > 60)
271 {
272 printf ("\n");
273 out_count = 0;
274 }
275 }
276 else
277 load_code (str);
278 }
279
280
281 /* Execute the current code as loaded. */
282
283 void
run_code(void)284 run_code(void)
285 {
286 /* If no compile errors run the current code. */
287 if (!had_error && did_gen)
288 {
289 if (compile_only)
290 {
291 printf ("@r\n");
292 out_count = 0;
293 }
294 else
295 execute ();
296 }
297
298 /* Reinitialize the code generation and machine. */
299 if (did_gen)
300 init_gen();
301 else
302 had_error = FALSE;
303 }
304
305
306 /* Output routines: Write a character CH to the standard output.
307 It keeps track of the number of characters output and may
308 break the output with a "\<cr>". Always used for numbers. */
309
310 void
out_char(int ch)311 out_char (int ch)
312 {
313 if (ch == '\n')
314 {
315 out_col = 0;
316 putchar ('\n');
317 }
318 else
319 {
320 out_col++;
321 if (out_col == line_size-1 && line_size != 0)
322 {
323 putchar ('\\');
324 putchar ('\n');
325 out_col = 1;
326 }
327 putchar (ch);
328 }
329 }
330
331 /* Output routines: Write a character CH to the standard output.
332 It keeps track of the number of characters output and may
333 break the output with a "\<cr>". This one is for strings.
334 In POSIX bc, strings are not broken across lines. */
335
336 void
out_schar(int ch)337 out_schar (int ch)
338 {
339 if (ch == '\n')
340 {
341 out_col = 0;
342 putchar ('\n');
343 }
344 else
345 {
346 if (!std_only)
347 {
348 out_col++;
349 if (out_col == line_size-1 && line_size != 0)
350 {
351 putchar ('\\');
352 putchar ('\n');
353 out_col = 1;
354 }
355 }
356 putchar (ch);
357 }
358 }
359
360
361 /* The following are "Symbol Table" routines for the parser. */
362
363 /* find_id returns a pointer to node in TREE that has the correct
364 ID. If there is no node in TREE with ID, NULL is returned. */
365
366 id_rec *
find_id(id_rec * tree,const char * id)367 find_id (id_rec *tree, const char *id)
368 {
369 int cmp_result;
370
371 /* Check for an empty tree. */
372 if (tree == NULL)
373 return NULL;
374
375 /* Recursively search the tree. */
376 cmp_result = strcmp (id, tree->id);
377 if (cmp_result == 0)
378 return tree; /* This is the item. */
379 else if (cmp_result < 0)
380 return find_id (tree->left, id);
381 else
382 return find_id (tree->right, id);
383 }
384
385
386 /* insert_id_rec inserts a NEW_ID rec into the tree whose ROOT is
387 provided. insert_id_rec returns TRUE if the tree height from
388 ROOT down is increased otherwise it returns FALSE. This is a
389 recursive balanced binary tree insertion algorithm. */
390
insert_id_rec(id_rec ** root,id_rec * new_id)391 int insert_id_rec (id_rec **root, id_rec *new_id)
392 {
393 id_rec *A, *B;
394
395 /* If root is NULL, this where it is to be inserted. */
396 if (*root == NULL)
397 {
398 *root = new_id;
399 new_id->left = NULL;
400 new_id->right = NULL;
401 new_id->balance = 0;
402 return (TRUE);
403 }
404
405 /* We need to search for a leaf. */
406 if (strcmp (new_id->id, (*root)->id) < 0)
407 {
408 /* Insert it on the left. */
409 if (insert_id_rec (&((*root)->left), new_id))
410 {
411 /* The height increased. */
412 (*root)->balance --;
413
414 switch ((*root)->balance)
415 {
416 case 0: /* no height increase. */
417 return (FALSE);
418 case -1: /* height increase. */
419 return (TRUE);
420 case -2: /* we need to do a rebalancing act. */
421 A = *root;
422 B = (*root)->left;
423 if (B->balance <= 0)
424 {
425 /* Single Rotate. */
426 A->left = B->right;
427 B->right = A;
428 *root = B;
429 A->balance = 0;
430 B->balance = 0;
431 }
432 else
433 {
434 /* Double Rotate. */
435 *root = B->right;
436 B->right = (*root)->left;
437 A->left = (*root)->right;
438 (*root)->left = B;
439 (*root)->right = A;
440 switch ((*root)->balance)
441 {
442 case -1:
443 A->balance = 1;
444 B->balance = 0;
445 break;
446 case 0:
447 A->balance = 0;
448 B->balance = 0;
449 break;
450 case 1:
451 A->balance = 0;
452 B->balance = -1;
453 break;
454 }
455 (*root)->balance = 0;
456 }
457 }
458 }
459 }
460 else
461 {
462 /* Insert it on the right. */
463 if (insert_id_rec (&((*root)->right), new_id))
464 {
465 /* The height increased. */
466 (*root)->balance ++;
467
468 switch ((*root)->balance)
469 {
470 case 0: /* no height increase. */
471 return (FALSE);
472 case 1: /* height increase. */
473 return (TRUE);
474 case 2: /* we need to do a rebalancing act. */
475 A = *root;
476 B = (*root)->right;
477 if (B->balance >= 0)
478 {
479 /* Single Rotate. */
480 A->right = B->left;
481 B->left = A;
482 *root = B;
483 A->balance = 0;
484 B->balance = 0;
485 }
486 else
487 {
488 /* Double Rotate. */
489 *root = B->left;
490 B->left = (*root)->right;
491 A->right = (*root)->left;
492 (*root)->left = A;
493 (*root)->right = B;
494 switch ((*root)->balance)
495 {
496 case -1:
497 A->balance = 0;
498 B->balance = 1;
499 break;
500 case 0:
501 A->balance = 0;
502 B->balance = 0;
503 break;
504 case 1:
505 A->balance = -1;
506 B->balance = 0;
507 break;
508 }
509 (*root)->balance = 0;
510 }
511 }
512 }
513 }
514
515 /* If we fall through to here, the tree did not grow in height. */
516 return (FALSE);
517 }
518
519
520 /* Initialize variables for the symbol table tree. */
521
522 void
init_tree(void)523 init_tree(void)
524 {
525 name_tree = NULL;
526 next_array = 1;
527 next_func = 1;
528 /* 0 => ibase, 1 => obase, 2 => scale, 3 => history, 4 => last. */
529 next_var = 5;
530 }
531
532
533 /* Lookup routines for symbol table names. */
534
535 int
lookup(char * name,int namekind)536 lookup (char *name, int namekind)
537 {
538 id_rec *id;
539
540 /* Warn about non-standard name. */
541 if (strlen(name) != 1)
542 ct_warn ("multiple letter name - %s", name);
543
544 /* Look for the id. */
545 id = find_id (name_tree, name);
546 if (id == NULL)
547 {
548 /* We need to make a new item. */
549 id = bc_malloc (sizeof (id_rec));
550 id->id = strcopyof (name);
551 id->a_name = 0;
552 id->f_name = 0;
553 id->v_name = 0;
554 insert_id_rec (&name_tree, id);
555 }
556
557 /* Return the correct value. */
558 switch (namekind)
559 {
560
561 case ARRAY:
562 /* ARRAY variable numbers are returned as negative numbers. */
563 if (id->a_name != 0)
564 {
565 free (name);
566 return (-id->a_name);
567 }
568 id->a_name = next_array++;
569 if (id->a_name < MAX_STORE)
570 {
571 if (id->a_name >= a_count)
572 more_arrays ();
573 a_names[id->a_name] = name;
574 return (-id->a_name);
575 }
576 yyerror ("Too many array variables");
577 bc_exit (1);
578 /*NOTREACHED*/
579
580 case FUNCT:
581 case FUNCTDEF:
582 if (id->f_name != 0)
583 {
584 free(name);
585 /* Check to see if we are redefining a math lib function. */
586 if (use_math && namekind == FUNCTDEF && id->f_name <= 6)
587 id->f_name = next_func++;
588 return (id->f_name);
589 }
590 id->f_name = next_func++;
591 if (id->f_name < MAX_STORE)
592 {
593 if (id->f_name >= f_count)
594 more_functions ();
595 f_names[id->f_name] = name;
596 return (id->f_name);
597 }
598 yyerror ("Too many functions");
599 bc_exit (1);
600 /*NOTREACHED*/
601
602 case SIMPLE:
603 if (id->v_name != 0)
604 {
605 free(name);
606 return (id->v_name);
607 }
608 id->v_name = next_var++;
609 if (id->v_name <= MAX_STORE)
610 {
611 if (id->v_name >= v_count)
612 more_variables ();
613 v_names[id->v_name - 1] = name;
614 return (id->v_name);
615 }
616 yyerror ("Too many variables");
617 bc_exit (1);
618 /*NOTREACHED*/
619
620 }
621
622 yyerror ("End of util.c/lookup() reached. Please report this bug.");
623 bc_exit (1);
624 /*NOTREACHED*/
625 return 0;
626 }
627
628 /* Print out the limits of this program. */
629
630 void
limits(void)631 limits(void)
632 {
633 printf ("BC_BASE_MAX = %d\n", BC_BASE_MAX);
634 printf ("BC_DIM_MAX = %ld\n", (long) BC_DIM_MAX);
635 printf ("BC_SCALE_MAX = %d\n", BC_SCALE_MAX);
636 printf ("BC_STRING_MAX = %d\n", BC_STRING_MAX);
637 printf ("MAX Exponent = %ld\n", (long) LONG_MAX);
638 printf ("Number of vars = %ld\n", (long) MAX_STORE);
639 #ifdef OLD_EQ_OP
640 printf ("Old assignment operatiors are valid. (=-, =+, ...)\n");
641 #endif
642 }
643
644 /* bc_malloc will check the return value so all other places do not
645 have to do it! SIZE is the number of bytes to allocate. */
646
647 void *
bc_malloc(size_t size)648 bc_malloc (size_t size)
649 {
650 void *ptr;
651
652 ptr = (void *) malloc (size);
653 if (ptr == NULL)
654 out_of_memory ();
655
656 return ptr;
657 }
658
659
660 /* The following routines are error routines for various problems. */
661
662 /* Malloc could not get enought memory. */
663
664 void
out_of_memory(void)665 out_of_memory(void)
666 {
667 fprintf (stderr, "Fatal error: Out of memory for malloc.\n");
668 bc_exit (1);
669 /*NOTREACHED*/
670 }
671
672
673
674 /* The standard yyerror routine. Built with variable number of argumnets. */
675
676 #ifndef VARARGS
677 #ifdef __STDC__
678 void
yyerror(const char * str,...)679 yyerror (const char *str, ...)
680 #else
681 void
682 yyerror (str)
683 const char *str;
684 #endif
685 #else
686 void
687 yyerror (str, va_alist)
688 const char *str;
689 #endif
690 {
691 const char *name;
692 va_list args;
693
694 #ifndef VARARGS
695 va_start (args, str);
696 #else
697 va_start (args);
698 #endif
699 if (is_std_in)
700 name = "(standard_in)";
701 else
702 name = file_name;
703 fprintf (stderr,"%s %d: ",name,line_no);
704 vfprintf (stderr, str, args);
705 fprintf (stderr, "\n");
706 had_error = TRUE;
707 va_end (args);
708 }
709
710
711 /* The routine to produce warnings about non-standard features
712 found during parsing. */
713
714 #ifndef VARARGS
715 #ifdef __STDC__
716 void
ct_warn(const char * mesg,...)717 ct_warn (const char *mesg, ...)
718 #else
719 void
720 ct_warn (mesg)
721 const char *mesg;
722 #endif
723 #else
724 void
725 ct_warn (mesg, va_alist)
726 const char *mesg;
727 #endif
728 {
729 const char *name;
730 va_list args;
731
732 #ifndef VARARGS
733 va_start (args, mesg);
734 #else
735 va_start (args);
736 #endif
737 if (std_only)
738 {
739 if (is_std_in)
740 name = "(standard_in)";
741 else
742 name = file_name;
743 fprintf (stderr,"%s %d: Error: ",name,line_no);
744 vfprintf (stderr, mesg, args);
745 fprintf (stderr, "\n");
746 had_error = TRUE;
747 }
748 else
749 if (warn_not_std)
750 {
751 if (is_std_in)
752 name = "(standard_in)";
753 else
754 name = file_name;
755 fprintf (stderr,"%s %d: (Warning) ",name,line_no);
756 vfprintf (stderr, mesg, args);
757 fprintf (stderr, "\n");
758 }
759 va_end (args);
760 }
761
762 /* Runtime error will print a message and stop the machine. */
763
764 #ifndef VARARGS
765 #ifdef __STDC__
766 void
rt_error(const char * mesg,...)767 rt_error (const char *mesg, ...)
768 #else
769 void
770 rt_error (mesg)
771 const char *mesg;
772 #endif
773 #else
774 void
775 rt_error (mesg, va_alist)
776 const char *mesg;
777 #endif
778 {
779 va_list args;
780
781 fprintf (stderr, "Runtime error (func=%s, adr=%d): ",
782 f_names[pc.pc_func], pc.pc_addr);
783 #ifndef VARARGS
784 va_start (args, mesg);
785 #else
786 va_start (args);
787 #endif
788 vfprintf (stderr, mesg, args);
789 va_end (args);
790
791 fprintf (stderr, "\n");
792 runtime_error = TRUE;
793 }
794
795
796 /* A runtime warning tells of some action taken by the processor that
797 may change the program execution but was not enough of a problem
798 to stop the execution. */
799
800 #ifndef VARARGS
801 #ifdef __STDC__
802 void
rt_warn(const char * mesg,...)803 rt_warn (const char *mesg, ...)
804 #else
805 void
806 rt_warn (const char *mesg)
807 #endif
808 #else
809 void
810 rt_warn (const char *mesg)
811 #endif
812 {
813 va_list args;
814
815 fprintf (stderr, "Runtime warning (func=%s, adr=%d): ",
816 f_names[pc.pc_func], pc.pc_addr);
817 #ifndef VARARGS
818 va_start (args, mesg);
819 #else
820 va_start (args);
821 #endif
822 vfprintf (stderr, mesg, args);
823 va_end (args);
824
825 fprintf (stderr, "\n");
826 }
827
828 /* bc_exit: Make sure to reset the edit state. */
829
bc_exit(int val)830 void bc_exit(int val)
831 {
832 #if defined(LIBEDIT)
833 if (edit != NULL)
834 el_end(edit);
835 #endif
836 exit(val);
837 /*NOTREACHED*/
838 }
839