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 *************************************************************************/
40 /* strcopyof mallocs new memory and copies a string to to the new
49 temp
= (char *) bc_malloc (strlen (str
)+1);
50 return (strcpy (temp
,str
));
54 /* nextarg adds another value to the list of arguments. */
62 temp
= (arg_list
*) bc_malloc (sizeof (arg_list
));
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
));
86 make_arg_str (args
, len
, commas
)
96 temp
= make_arg_str (args
->next
, len
+11, commas
);
99 temp
= (char *) bc_malloc (len
);
104 /* Add the current number to the end of the string. */
105 if (len
!= 1 && commas
)
106 sprintf (sval
, "%d,", args
->av_name
);
108 sprintf (sval
, "%d", args
->av_name
);
109 temp
= strcat (temp
, sval
);
114 arg_str (args
, commas
)
118 if (arglist2
!= NULL
)
121 arglist1
= make_arg_str (args
, 1, commas
);
126 /* free_args frees an argument list 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. */
149 check_params ( params
, autos
)
150 arg_list
*params
, *autos
;
152 arg_list
*tmp1
, *tmp2
;
154 /* Check for duplicate parameters. */
163 if (tmp2
->av_name
== tmp1
->av_name
)
164 yyerror ("duplicate parameter names");
167 if (tmp1
->av_name
< 0)
168 warn ("Array parameter");
173 /* Check for duplicate autos. */
182 if (tmp2
->av_name
== tmp1
->av_name
)
183 yyerror ("duplicate auto variable names");
190 /* Check for duplicate between parameters and autos. */
191 if ((params
!= NULL
) && (autos
!= NULL
))
199 if (tmp2
->av_name
== tmp1
->av_name
)
200 yyerror ("variable in both parameter and auto lists");
209 /* Initialize the code generator the parser. */
214 /* Get things ready. */
228 /* generate code STR for the machine. */
238 out_count
+= strlen(str
);
250 /* Execute the current code as loaded. */
255 /* If no compile errors run the current code. */
256 if (!had_error
&& did_gen
)
267 /* Reinitialize the code generation and machine. */
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>". */
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. */
314 /* Check for an empty tree. */
318 /* Recursively search the tree. */
319 cmp_result
= strcmp (id
, tree
->id
);
321 return tree
; /* This is the item. */
322 else if (cmp_result
< 0)
323 return find_id (tree
->left
, id
);
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
)
340 /* If root is NULL, this where it is to be inserted. */
345 new_id
->right
= NULL
;
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. */
359 switch ((*root
)->balance
)
361 case 0: /* no height increase. */
363 case -1: /* height increase. */
365 case -2: /* we need to do a rebalancing act. */
381 B
->right
= (*root
)->left
;
382 A
->left
= (*root
)->right
;
385 switch ((*root
)->balance
)
400 (*root
)->balance
= 0;
407 /* Insert it on the right. */
408 if (insert_id_rec (&((*root
)->right
), new_id
))
410 /* The height increased. */
412 switch ((*root
)->balance
)
414 case 0: /* no height increase. */
416 case 1: /* height increase. */
418 case 2: /* we need to do a rebalancing act. */
434 B
->left
= (*root
)->right
;
435 A
->right
= (*root
)->left
;
438 switch ((*root
)->balance
)
453 (*root
)->balance
= 0;
459 /* If we fall through to here, the tree did not grow in height. */
464 /* Initialize variables for the symbol table tree. */
472 next_var
= 4; /* 0 => ibase, 1 => obase, 2 => scale, 3 => last. */
476 /* Lookup routines for symbol table names. */
479 lookup (name
, namekind
)
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
);
493 /* We need to make a new item. */
494 id
= (id_rec
*) bc_malloc (sizeof (id_rec
));
495 id
->id
= strcopyof (name
);
499 insert_id_rec (&name_tree
, id
);
502 /* Return the correct value. */
507 /* ARRAY variable numbers are returned as negative numbers. */
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
)
519 return (-id
->a_name
);
521 yyerror ("Too many array variables");
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
)
538 yyerror ("Too many functions");
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
)
555 yyerror ("Too many variables");
561 /* Print the welcome banner. */
567 printf ("This is free software with ABSOLUTELY NO WARRANTY.\n");
568 printf ("For details type `warranty'. \n");
573 /* Print out the warranty information. */
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. */
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
);
608 printf ("Old assignment operatiors are valid. (=-, =+, ...)\n");
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. */
621 ptr
= (char *) malloc (size
);
629 /* The following routines are error routines for various problems. */
631 /* Malloc could not get enought memory. */
636 fprintf (stderr
, "Fatal error: Out of memory for malloc.\n");
642 /* The standard yyerror routine. Built with variable number of argumnets. */
647 yyerror (char *str
, ...)
655 yyerror (str
, va_alist
)
663 va_start (args
, str
);
668 name
= "(standard_in)";
670 name
= g_argv
[optind
-1];
671 fprintf (stderr
,"%s %d: ",name
,line_no
);
672 vfprintf (stderr
, str
, args
);
673 fprintf (stderr
, "\n");
679 /* The routine to produce warnings about non-standard features
680 found during parsing. */
685 warn (char *mesg
, ...)
693 warn (mesg
, va_alist
)
701 va_start (args
, mesg
);
708 name
= "(standard_in)";
710 name
= g_argv
[optind
-1];
711 fprintf (stderr
,"%s %d: ",name
,line_no
);
712 vfprintf (stderr
, mesg
, args
);
713 fprintf (stderr
, "\n");
720 name
= "(standard_in)";
722 name
= g_argv
[optind
-1];
723 fprintf (stderr
,"%s %d: (Warning) ",name
,line_no
);
724 vfprintf (stderr
, mesg
, args
);
725 fprintf (stderr
, "\n");
730 /* Runtime error will print a message and stop the machine. */
735 rt_error (char *mesg
, ...)
743 rt_error (mesg
, va_alist
)
748 char error_mesg
[255];
751 va_start (args
, mesg
);
755 vsprintf (error_mesg
, mesg
, 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. */
771 rt_warn (char *mesg
, ...)
779 rt_warn (mesg
, va_alist
)
784 char error_mesg
[255];
787 va_start (args
, mesg
);
791 vsprintf (error_mesg
, mesg
, args
);
794 fprintf (stderr
, "Runtime warning (func=%s, adr=%d): %s\n",
795 f_names
[pc
.pc_func
], pc
.pc_addr
, error_mesg
);