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