* reordered a little bit
[mascara-docs.git] / i86 / elks / elkscmd / bc / util.c
blobc0adf914d4b5cdee05f7f5ed5875cbc3959dd677
1 /* util.c: Utility routines for bc. */
3 /* This file is part of bc written for MINIX.
4 Copyright (C) 1991, 1992 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, 675 Mass Ave, Cambridge, MA 02139, USA.
20 You may contact the author by:
21 e-mail: phil@cs.wwu.edu
22 us-mail: Philip A. Nelson
23 Computer Science Department, 9062
24 Western Washington University
25 Bellingham, WA 98226-9062
27 *************************************************************************/
30 #include "bcdefs.h"
31 #ifndef VARARGS
32 #include <stdarg.h>
33 #else
34 #include <varargs.h>
35 #endif
36 #include "global.h"
37 #include "proto.h"
40 /* strcopyof mallocs new memory and copies a string to to the new
41 memory. */
43 char *
44 strcopyof (str)
45 char *str;
47 char *temp;
49 temp = (char *) bc_malloc (strlen (str)+1);
50 return (strcpy (temp,str));
54 /* nextarg adds another value to the list of arguments. */
56 arg_list *
57 nextarg (args, val)
58 arg_list *args;
59 char val;
60 { arg_list *temp;
62 temp = (arg_list *) bc_malloc (sizeof (arg_list));
63 temp->av_name = val;
64 temp->next = args;
66 return (temp);
70 /* For generate, we must produce a string in the form
71 "val,val,...,val". We also need a couple of static variables
72 for retaining old generated strings. It also uses a recursive
73 function that builds the string. */
75 static char *arglist1 = NULL, *arglist2 = NULL;
78 /* make_arg_str does the actual construction of the argument string.
79 ARGS is the pointer to the list and LEN is the maximum number of
80 characters needed. 1 char is the minimum needed. COMMAS tells
81 if each number should be seperated by commas.*/
83 _PROTOTYPE (static char *make_arg_str, (arg_list *args, int len, int commas));
85 static char *
86 make_arg_str (args, len, commas)
87 arg_list *args;
88 int len;
89 int commas;
91 char *temp;
92 char sval[20];
94 /* Recursive call. */
95 if (args != NULL)
96 temp = make_arg_str (args->next, len+11, commas);
97 else
99 temp = (char *) bc_malloc (len);
100 *temp = 0;
101 return temp;
104 /* Add the current number to the end of the string. */
105 if (len != 1 && commas)
106 sprintf (sval, "%d,", args->av_name);
107 else
108 sprintf (sval, "%d", args->av_name);
109 temp = strcat (temp, sval);
110 return (temp);
113 char *
114 arg_str (args, commas)
115 arg_list *args;
116 int commas;
118 if (arglist2 != NULL)
119 free (arglist2);
120 arglist2 = arglist1;
121 arglist1 = make_arg_str (args, 1, commas);
122 return (arglist1);
126 /* free_args frees an argument list ARGS. */
128 void
129 free_args (args)
130 arg_list *args;
132 arg_list *temp;
134 temp = args;
135 while (temp != NULL)
137 args = args->next;
138 free (temp);
139 temp = args;
144 /* Check for valid parameter (PARAMS) and auto (AUTOS) lists.
145 There must be no duplicates any where. Also, this is where
146 warnings are generated for array parameters. */
148 void
149 check_params ( params, autos )
150 arg_list *params, *autos;
152 arg_list *tmp1, *tmp2;
154 /* Check for duplicate parameters. */
155 if (params != NULL)
157 tmp1 = params;
158 while (tmp1 != NULL)
160 tmp2 = tmp1->next;
161 while (tmp2 != NULL)
163 if (tmp2->av_name == tmp1->av_name)
164 yyerror ("duplicate parameter names");
165 tmp2 = tmp2->next;
167 if (tmp1->av_name < 0)
168 warn ("Array parameter");
169 tmp1 = tmp1->next;
173 /* Check for duplicate autos. */
174 if (autos != NULL)
176 tmp1 = autos;
177 while (tmp1 != NULL)
179 tmp2 = tmp1->next;
180 while (tmp2 != NULL)
182 if (tmp2->av_name == tmp1->av_name)
183 yyerror ("duplicate auto variable names");
184 tmp2 = tmp2->next;
186 tmp1 = tmp1->next;
190 /* Check for duplicate between parameters and autos. */
191 if ((params != NULL) && (autos != NULL))
193 tmp1 = params;
194 while (tmp1 != NULL)
196 tmp2 = autos;
197 while (tmp2 != NULL)
199 if (tmp2->av_name == tmp1->av_name)
200 yyerror ("variable in both parameter and auto lists");
201 tmp2 = tmp2->next;
203 tmp1 = tmp1->next;
209 /* Initialize the code generator the parser. */
211 void
212 init_gen ()
214 /* Get things ready. */
215 break_label = 0;
216 continue_label = 0;
217 next_label = 1;
218 out_count = 2;
219 if (compile_only)
220 printf ("@i");
221 else
222 init_load ();
223 had_error = FALSE;
224 did_gen = FALSE;
228 /* generate code STR for the machine. */
230 void
231 generate (str)
232 char *str;
234 did_gen = TRUE;
235 if (compile_only)
237 printf ("%s",str);
238 out_count += strlen(str);
239 if (out_count > 60)
241 printf ("\n");
242 out_count = 0;
245 else
246 load_code (str);
250 /* Execute the current code as loaded. */
252 void
253 run_code()
255 /* If no compile errors run the current code. */
256 if (!had_error && did_gen)
258 if (compile_only)
260 printf ("@r\n");
261 out_count = 0;
263 else
264 execute ();
267 /* Reinitialize the code generation and machine. */
268 if (did_gen)
269 init_gen();
270 else
271 had_error = FALSE;
275 /* Output routines: Write a character CH to the standard output.
276 It keeps track of the number of characters output and may
277 break the output with a "\<cr>". */
279 void
280 out_char (ch)
281 char ch;
283 if (ch == '\n')
285 out_col = 0;
286 putchar ('\n');
288 else
290 out_col++;
291 if (out_col == 70)
293 putchar ('\\');
294 putchar ('\n');
295 out_col = 1;
297 putchar (ch);
302 /* The following are "Symbol Table" routines for the parser. */
304 /* find_id returns a pointer to node in TREE that has the correct
305 ID. If there is no node in TREE with ID, NULL is returned. */
307 id_rec *
308 find_id (tree, id)
309 id_rec *tree;
310 char *id;
312 int cmp_result;
314 /* Check for an empty tree. */
315 if (tree == NULL)
316 return NULL;
318 /* Recursively search the tree. */
319 cmp_result = strcmp (id, tree->id);
320 if (cmp_result == 0)
321 return tree; /* This is the item. */
322 else if (cmp_result < 0)
323 return find_id (tree->left, id);
324 else
325 return find_id (tree->right, id);
329 /* insert_id_rec inserts a NEW_ID rec into the tree whose ROOT is
330 provided. insert_id_rec returns TRUE if the tree height from
331 ROOT down is increased otherwise it returns FALSE. This is a
332 recursive balanced binary tree insertion algorithm. */
334 int insert_id_rec (root, new_id)
335 id_rec **root;
336 id_rec *new_id;
338 id_rec *A, *B;
340 /* If root is NULL, this where it is to be inserted. */
341 if (*root == NULL)
343 *root = new_id;
344 new_id->left = NULL;
345 new_id->right = NULL;
346 new_id->balance = 0;
347 return (TRUE);
350 /* We need to search for a leaf. */
351 if (strcmp (new_id->id, (*root)->id) < 0)
353 /* Insert it on the left. */
354 if (insert_id_rec (&((*root)->left), new_id))
356 /* The height increased. */
357 (*root)->balance --;
359 switch ((*root)->balance)
361 case 0: /* no height increase. */
362 return (FALSE);
363 case -1: /* height increase. */
364 return (FALSE);
365 case -2: /* we need to do a rebalancing act. */
366 A = *root;
367 B = (*root)->left;
368 if (B->balance <= 0)
370 /* Single Rotate. */
371 A->left = B->right;
372 B->right = A;
373 *root = B;
374 A->balance = 0;
375 B->balance = 0;
377 else
379 /* Double Rotate. */
380 *root = B->right;
381 B->right = (*root)->left;
382 A->left = (*root)->right;
383 (*root)->left = B;
384 (*root)->right = A;
385 switch ((*root)->balance)
387 case -1:
388 A->balance = 1;
389 B->balance = 0;
390 break;
391 case 0:
392 A->balance = 0;
393 B->balance = 0;
394 break;
395 case 1:
396 A->balance = 0;
397 B->balance = -1;
398 break;
400 (*root)->balance = 0;
405 else
407 /* Insert it on the right. */
408 if (insert_id_rec (&((*root)->right), new_id))
410 /* The height increased. */
411 (*root)->balance ++;
412 switch ((*root)->balance)
414 case 0: /* no height increase. */
415 return (FALSE);
416 case 1: /* height increase. */
417 return (FALSE);
418 case 2: /* we need to do a rebalancing act. */
419 A = *root;
420 B = (*root)->right;
421 if (B->balance >= 0)
423 /* Single Rotate. */
424 A->right = B->left;
425 B->left = A;
426 *root = B;
427 A->balance = 0;
428 B->balance = 0;
430 else
432 /* Double Rotate. */
433 *root = B->left;
434 B->left = (*root)->right;
435 A->right = (*root)->left;
436 (*root)->left = A;
437 (*root)->right = B;
438 switch ((*root)->balance)
440 case -1:
441 A->balance = 0;
442 B->balance = 1;
443 break;
444 case 0:
445 A->balance = 0;
446 B->balance = 0;
447 break;
448 case 1:
449 A->balance = -1;
450 B->balance = 0;
451 break;
453 (*root)->balance = 0;
459 /* If we fall through to here, the tree did not grow in height. */
460 return (FALSE);
464 /* Initialize variables for the symbol table tree. */
466 void
467 init_tree()
469 name_tree = NULL;
470 next_array = 1;
471 next_func = 1;
472 next_var = 4; /* 0 => ibase, 1 => obase, 2 => scale, 3 => last. */
476 /* Lookup routines for symbol table names. */
479 lookup (name, namekind)
480 char *name;
481 int namekind;
483 id_rec *id;
485 /* Warn about non-standard name. */
486 if (strlen(name) != 1)
487 warn ("multiple letter name - %s", name);
489 /* Look for the id. */
490 id = find_id (name_tree, name);
491 if (id == NULL)
493 /* We need to make a new item. */
494 id = (id_rec *) bc_malloc (sizeof (id_rec));
495 id->id = strcopyof (name);
496 id->a_name = 0;
497 id->f_name = 0;
498 id->v_name = 0;
499 insert_id_rec (&name_tree, id);
502 /* Return the correct value. */
503 switch (namekind)
506 case ARRAY:
507 /* ARRAY variable numbers are returned as negative numbers. */
508 if (id->a_name != 0)
510 free (name);
511 return (-id->a_name);
513 id->a_name = next_array++;
514 a_names[id->a_name] = name;
515 if (id->a_name < MAX_STORE)
517 if (id->a_name >= a_count)
518 more_arrays ();
519 return (-id->a_name);
521 yyerror ("Too many array variables");
522 exit (1);
524 case FUNCT:
525 if (id->f_name != 0)
527 free(name);
528 return (id->f_name);
530 id->f_name = next_func++;
531 f_names[id->f_name] = name;
532 if (id->f_name < MAX_STORE)
534 if (id->f_name >= f_count)
535 more_functions ();
536 return (id->f_name);
538 yyerror ("Too many functions");
539 exit (1);
541 case SIMPLE:
542 if (id->v_name != 0)
544 free(name);
545 return (id->v_name);
547 id->v_name = next_var++;
548 v_names[id->v_name - 1] = name;
549 if (id->v_name <= MAX_STORE)
551 if (id->v_name >= v_count)
552 more_variables ();
553 return (id->v_name);
555 yyerror ("Too many variables");
556 exit (1);
561 /* Print the welcome banner. */
563 void
564 welcome()
566 #if !__minix
567 printf ("This is free software with ABSOLUTELY NO WARRANTY.\n");
568 printf ("For details type `warranty'. \n");
569 #endif
573 /* Print out the warranty information. */
575 void
576 warranty(prefix)
577 char *prefix;
579 printf ("\n%s%s\n\n", prefix, BC_VERSION);
580 printf ("%s%s%s%s%s%s%s%s%s%s%s",
581 " This program is free software; you can redistribute it and/or modify\n",
582 " it under the terms of the GNU General Public License as published by\n",
583 " the Free Software Foundation; either version 2 of the License , or\n",
584 " (at your option) any later version.\n\n",
585 " This program is distributed in the hope that it will be useful,\n",
586 " but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
587 " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n",
588 " GNU General Public License for more details.\n\n",
589 " You should have received a copy of the GNU General Public License\n",
590 " along with this program. If not, write to the Free Software\n",
591 " Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.\n\n");
594 /* Print out the limits of this program. */
596 void
597 limits()
599 printf ("BC_BASE_MAX = %d\n", BC_BASE_MAX);
600 printf ("BC_DIM_MAX = %ld\n", (long) BC_DIM_MAX);
601 printf ("BC_SCALE_MAX = %d\n", BC_SCALE_MAX);
602 printf ("BC_STRING_MAX = %d\n", BC_STRING_MAX);
603 printf ("MAX Exponent = %ld\n", (long) LONG_MAX);
604 printf ("MAX code = %ld\n", (long) BC_MAX_SEGS * (long) BC_SEG_SIZE);
605 printf ("multiply digits = %ld\n", (long) LONG_MAX / (long) 90);
606 printf ("Number of vars = %ld\n", (long) MAX_STORE);
607 #ifdef OLD_EQ_OP
608 printf ("Old assignment operatiors are valid. (=-, =+, ...)\n");
609 #endif
612 /* bc_malloc will check the return value so all other places do not
613 have to do it! SIZE is the number of types to allocate. */
615 char *
616 bc_malloc (size)
617 int size;
619 char *ptr;
621 ptr = (char *) malloc (size);
622 if (ptr == NULL)
623 out_of_memory ();
625 return ptr;
629 /* The following routines are error routines for various problems. */
631 /* Malloc could not get enought memory. */
633 void
634 out_of_memory()
636 fprintf (stderr, "Fatal error: Out of memory for malloc.\n");
637 exit (1);
642 /* The standard yyerror routine. Built with variable number of argumnets. */
644 #ifndef VARARGS
645 #ifdef __STDC__
646 void
647 yyerror (char *str, ...)
648 #else
649 void
650 yyerror (str)
651 char *str;
652 #endif
653 #else
654 void
655 yyerror (str, va_alist)
656 char *str;
657 #endif
659 char *name;
660 va_list args;
662 #ifndef VARARGS
663 va_start (args, str);
664 #else
665 va_start (args);
666 #endif
667 if (is_std_in)
668 name = "(standard_in)";
669 else
670 name = g_argv[optind-1];
671 fprintf (stderr,"%s %d: ",name,line_no);
672 vfprintf (stderr, str, args);
673 fprintf (stderr, "\n");
674 had_error = TRUE;
675 va_end (args);
679 /* The routine to produce warnings about non-standard features
680 found during parsing. */
682 #ifndef VARARGS
683 #ifdef __STDC__
684 void
685 warn (char *mesg, ...)
686 #else
687 void
688 warn (mesg)
689 char *mesg;
690 #endif
691 #else
692 void
693 warn (mesg, va_alist)
694 char *mesg;
695 #endif
697 char *name;
698 va_list args;
700 #ifndef VARARGS
701 va_start (args, mesg);
702 #else
703 va_start (args);
704 #endif
705 if (std_only)
707 if (is_std_in)
708 name = "(standard_in)";
709 else
710 name = g_argv[optind-1];
711 fprintf (stderr,"%s %d: ",name,line_no);
712 vfprintf (stderr, mesg, args);
713 fprintf (stderr, "\n");
714 had_error = TRUE;
716 else
717 if (warn_not_std)
719 if (is_std_in)
720 name = "(standard_in)";
721 else
722 name = g_argv[optind-1];
723 fprintf (stderr,"%s %d: (Warning) ",name,line_no);
724 vfprintf (stderr, mesg, args);
725 fprintf (stderr, "\n");
727 va_end (args);
730 /* Runtime error will print a message and stop the machine. */
732 #ifndef VARARGS
733 #ifdef __STDC__
734 void
735 rt_error (char *mesg, ...)
736 #else
737 void
738 rt_error (mesg)
739 char *mesg;
740 #endif
741 #else
742 void
743 rt_error (mesg, va_alist)
744 char *mesg;
745 #endif
747 va_list args;
748 char error_mesg [255];
750 #ifndef VARARGS
751 va_start (args, mesg);
752 #else
753 va_start (args);
754 #endif
755 vsprintf (error_mesg, mesg, args);
756 va_end (args);
758 fprintf (stderr, "Runtime error (func=%s, adr=%d): %s\n",
759 f_names[pc.pc_func], pc.pc_addr, error_mesg);
760 runtime_error = TRUE;
764 /* A runtime warning tells of some action taken by the processor that
765 may change the program execution but was not enough of a problem
766 to stop the execution. */
768 #ifndef VARARGS
769 #ifdef __STDC__
770 void
771 rt_warn (char *mesg, ...)
772 #else
773 void
774 rt_warn (mesg)
775 char *mesg;
776 #endif
777 #else
778 void
779 rt_warn (mesg, va_alist)
780 char *mesg;
781 #endif
783 va_list args;
784 char error_mesg [255];
786 #ifndef VARARGS
787 va_start (args, mesg);
788 #else
789 va_start (args);
790 #endif
791 vsprintf (error_mesg, mesg, args);
792 va_end (args);
794 fprintf (stderr, "Runtime warning (func=%s, adr=%d): %s\n",
795 f_names[pc.pc_func], pc.pc_addr, error_mesg);