source: trunk/minix/commands/bc/util.c@ 20

Last change on this file since 20 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 16.0 KB
Line 
1/* util.c: Utility routines for bc. */
2
3/* This file is part of bc written for MINIX.
4 Copyright (C) 1991, 1992 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, 675 Mass Ave, Cambridge, MA 02139, USA.
19
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
26
27*************************************************************************/
28
29
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"
38
39
40/* strcopyof mallocs new memory and copies a string to to the new
41 memory. */
42
43char *
44strcopyof (str)
45 char *str;
46{
47 char *temp;
48
49 temp = (char *) bc_malloc (strlen (str)+1);
50 return (strcpy (temp,str));
51}
52
53
54/* nextarg adds another value to the list of arguments. */
55
56arg_list *
57nextarg (args, val)
58 arg_list *args;
59 char val;
60{ arg_list *temp;
61
62 temp = (arg_list *) bc_malloc (sizeof (arg_list));
63 temp->av_name = val;
64 temp->next = args;
65
66 return (temp);
67}
68
69
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. */
74
75static char *arglist1 = NULL, *arglist2 = NULL;
76
77
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.*/
82
83_PROTOTYPE (static char *make_arg_str, (arg_list *args, int len, int commas));
84
85static char *
86make_arg_str (args, len, commas)
87 arg_list *args;
88 int len;
89 int commas;
90{
91 char *temp;
92 char sval[20];
93
94 /* Recursive call. */
95 if (args != NULL)
96 temp = make_arg_str (args->next, len+11, commas);
97 else
98 {
99 temp = (char *) bc_malloc (len);
100 *temp = 0;
101 return temp;
102 }
103
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);
111}
112
113char *
114arg_str (args, commas)
115 arg_list *args;
116 int commas;
117{
118 if (arglist2 != NULL)
119 free (arglist2);
120 arglist2 = arglist1;
121 arglist1 = make_arg_str (args, 1, commas);
122 return (arglist1);
123}
124
125
126/* free_args frees an argument list ARGS. */
127
128void
129free_args (args)
130 arg_list *args;
131{
132 arg_list *temp;
133
134 temp = args;
135 while (temp != NULL)
136 {
137 args = args->next;
138 free (temp);
139 temp = args;
140 }
141}
142
143
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. */
147
148void
149check_params ( params, autos )
150 arg_list *params, *autos;
151{
152 arg_list *tmp1, *tmp2;
153
154 /* Check for duplicate parameters. */
155 if (params != NULL)
156 {
157 tmp1 = params;
158 while (tmp1 != NULL)
159 {
160 tmp2 = tmp1->next;
161 while (tmp2 != NULL)
162 {
163 if (tmp2->av_name == tmp1->av_name)
164 yyerror ("duplicate parameter names");
165 tmp2 = tmp2->next;
166 }
167 if (tmp1->av_name < 0)
168 warn ("Array parameter");
169 tmp1 = tmp1->next;
170 }
171 }
172
173 /* Check for duplicate autos. */
174 if (autos != NULL)
175 {
176 tmp1 = autos;
177 while (tmp1 != NULL)
178 {
179 tmp2 = tmp1->next;
180 while (tmp2 != NULL)
181 {
182 if (tmp2->av_name == tmp1->av_name)
183 yyerror ("duplicate auto variable names");
184 tmp2 = tmp2->next;
185 }
186 tmp1 = tmp1->next;
187 }
188 }
189
190 /* Check for duplicate between parameters and autos. */
191 if ((params != NULL) && (autos != NULL))
192 {
193 tmp1 = params;
194 while (tmp1 != NULL)
195 {
196 tmp2 = autos;
197 while (tmp2 != NULL)
198 {
199 if (tmp2->av_name == tmp1->av_name)
200 yyerror ("variable in both parameter and auto lists");
201 tmp2 = tmp2->next;
202 }
203 tmp1 = tmp1->next;
204 }
205 }
206}
207
208
209/* Initialize the code generator the parser. */
210
211void
212init_gen ()
213{
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;
225}
226
227
228/* generate code STR for the machine. */
229
230void
231generate (str)
232 char *str;
233{
234 did_gen = TRUE;
235 if (compile_only)
236 {
237 printf ("%s",str);
238 out_count += strlen(str);
239 if (out_count > 60)
240 {
241 printf ("\n");
242 out_count = 0;
243 }
244 }
245 else
246 load_code (str);
247}
248
249
250/* Execute the current code as loaded. */
251
252void
253run_code()
254{
255 /* If no compile errors run the current code. */
256 if (!had_error && did_gen)
257 {
258 if (compile_only)
259 {
260 printf ("@r\n");
261 out_count = 0;
262 }
263 else
264 execute ();
265 }
266
267 /* Reinitialize the code generation and machine. */
268 if (did_gen)
269 init_gen();
270 else
271 had_error = FALSE;
272}
273
274
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>". */
278
279void
280out_char (ch)
281 char ch;
282{
283 if (ch == '\n')
284 {
285 out_col = 0;
286 putchar ('\n');
287 }
288 else
289 {
290 out_col++;
291 if (out_col == 70)
292 {
293 putchar ('\\');
294 putchar ('\n');
295 out_col = 1;
296 }
297 putchar (ch);
298 }
299}
300
301
302/* The following are "Symbol Table" routines for the parser. */
303
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. */
306
307id_rec *
308find_id (tree, id)
309 id_rec *tree;
310 char *id;
311{
312 int cmp_result;
313
314 /* Check for an empty tree. */
315 if (tree == NULL)
316 return NULL;
317
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);
326}
327
328
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. */
333
334int insert_id_rec (root, new_id)
335 id_rec **root;
336 id_rec *new_id;
337{
338 id_rec *A, *B;
339
340 /* If root is NULL, this where it is to be inserted. */
341 if (*root == NULL)
342 {
343 *root = new_id;
344 new_id->left = NULL;
345 new_id->right = NULL;
346 new_id->balance = 0;
347 return (TRUE);
348 }
349
350 /* We need to search for a leaf. */
351 if (strcmp (new_id->id, (*root)->id) < 0)
352 {
353 /* Insert it on the left. */
354 if (insert_id_rec (&((*root)->left), new_id))
355 {
356 /* The height increased. */
357 (*root)->balance --;
358
359 switch ((*root)->balance)
360 {
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)
369 {
370 /* Single Rotate. */
371 A->left = B->right;
372 B->right = A;
373 *root = B;
374 A->balance = 0;
375 B->balance = 0;
376 }
377 else
378 {
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)
386 {
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;
399 }
400 (*root)->balance = 0;
401 }
402 }
403 }
404 }
405 else
406 {
407 /* Insert it on the right. */
408 if (insert_id_rec (&((*root)->right), new_id))
409 {
410 /* The height increased. */
411 (*root)->balance ++;
412 switch ((*root)->balance)
413 {
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)
422 {
423 /* Single Rotate. */
424 A->right = B->left;
425 B->left = A;
426 *root = B;
427 A->balance = 0;
428 B->balance = 0;
429 }
430 else
431 {
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)
439 {
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;
452 }
453 (*root)->balance = 0;
454 }
455 }
456 }
457 }
458
459 /* If we fall through to here, the tree did not grow in height. */
460 return (FALSE);
461}
462
463
464/* Initialize variables for the symbol table tree. */
465
466void
467init_tree()
468{
469 name_tree = NULL;
470 next_array = 1;
471 next_func = 1;
472 next_var = 4; /* 0 => ibase, 1 => obase, 2 => scale, 3 => last. */
473}
474
475
476/* Lookup routines for symbol table names. */
477
478int
479lookup (name, namekind)
480 char *name;
481 int namekind;
482{
483 id_rec *id;
484
485 /* Warn about non-standard name. */
486 if (strlen(name) != 1)
487 warn ("multiple letter name - %s", name);
488
489 /* Look for the id. */
490 id = find_id (name_tree, name);
491 if (id == NULL)
492 {
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);
500 }
501
502 /* Return the correct value. */
503 switch (namekind)
504 {
505
506 case ARRAY:
507 /* ARRAY variable numbers are returned as negative numbers. */
508 if (id->a_name != 0)
509 {
510 free (name);
511 return (-id->a_name);
512 }
513 id->a_name = next_array++;
514 a_names[id->a_name] = name;
515 if (id->a_name < MAX_STORE)
516 {
517 if (id->a_name >= a_count)
518 more_arrays ();
519 return (-id->a_name);
520 }
521 yyerror ("Too many array variables");
522 exit (1);
523
524 case FUNCT:
525 if (id->f_name != 0)
526 {
527 free(name);
528 return (id->f_name);
529 }
530 id->f_name = next_func++;
531 f_names[id->f_name] = name;
532 if (id->f_name < MAX_STORE)
533 {
534 if (id->f_name >= f_count)
535 more_functions ();
536 return (id->f_name);
537 }
538 yyerror ("Too many functions");
539 exit (1);
540
541 case SIMPLE:
542 if (id->v_name != 0)
543 {
544 free(name);
545 return (id->v_name);
546 }
547 id->v_name = next_var++;
548 v_names[id->v_name - 1] = name;
549 if (id->v_name <= MAX_STORE)
550 {
551 if (id->v_name >= v_count)
552 more_variables ();
553 return (id->v_name);
554 }
555 yyerror ("Too many variables");
556 exit (1);
557 }
558}
559
560
561/* Print the welcome banner. */
562
563void
564welcome()
565{
566#if !__minix
567 printf ("This is free software with ABSOLUTELY NO WARRANTY.\n");
568 printf ("For details type `warranty'. \n");
569#endif
570}
571
572
573/* Print out the warranty information. */
574
575void
576warranty(prefix)
577 char *prefix;
578{
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");
592}
593
594/* Print out the limits of this program. */
595
596void
597limits()
598{
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
610}
611
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. */
614
615char *
616bc_malloc (size)
617 int size;
618{
619 char *ptr;
620
621 ptr = (char *) malloc (size);
622 if (ptr == NULL)
623 out_of_memory ();
624
625 return ptr;
626}
627
628
629/* The following routines are error routines for various problems. */
630
631/* Malloc could not get enought memory. */
632
633void
634out_of_memory()
635{
636 fprintf (stderr, "Fatal error: Out of memory for malloc.\n");
637 exit (1);
638}
639
640
641
642/* The standard yyerror routine. Built with variable number of argumnets. */
643
644#ifndef VARARGS
645#ifdef __STDC__
646void
647yyerror (char *str, ...)
648#else
649void
650yyerror (str)
651 char *str;
652#endif
653#else
654void
655yyerror (str, va_alist)
656 char *str;
657#endif
658{
659 char *name;
660 va_list args;
661
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);
676}
677
678
679/* The routine to produce warnings about non-standard features
680 found during parsing. */
681
682#ifndef VARARGS
683#ifdef __STDC__
684void
685warn (char *mesg, ...)
686#else
687void
688warn (mesg)
689 char *mesg;
690#endif
691#else
692void
693warn (mesg, va_alist)
694 char *mesg;
695#endif
696{
697 char *name;
698 va_list args;
699
700#ifndef VARARGS
701 va_start (args, mesg);
702#else
703 va_start (args);
704#endif
705 if (std_only)
706 {
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;
715 }
716 else
717 if (warn_not_std)
718 {
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");
726 }
727 va_end (args);
728}
729
730/* Runtime error will print a message and stop the machine. */
731
732#ifndef VARARGS
733#ifdef __STDC__
734void
735rt_error (char *mesg, ...)
736#else
737void
738rt_error (mesg)
739 char *mesg;
740#endif
741#else
742void
743rt_error (mesg, va_alist)
744 char *mesg;
745#endif
746{
747 va_list args;
748 char error_mesg [255];
749
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);
757
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;
761}
762
763
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. */
767
768#ifndef VARARGS
769#ifdef __STDC__
770void
771rt_warn (char *mesg, ...)
772#else
773void
774rt_warn (mesg)
775 char *mesg;
776#endif
777#else
778void
779rt_warn (mesg, va_alist)
780 char *mesg;
781#endif
782{
783 va_list args;
784 char error_mesg [255];
785
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);
793
794 fprintf (stderr, "Runtime warning (func=%s, adr=%d): %s\n",
795 f_names[pc.pc_func], pc.pc_addr, error_mesg);
796}
Note: See TracBrowser for help on using the repository browser.