1 %{ 2 /* $OpenBSD: bc.y,v 1.33 2009/10/27 23:59:36 deraadt Exp $ */ 3 4 /* 5 * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* 21 * This implementation of bc(1) uses concepts from the original 4.4 22 * BSD bc(1). The code itself is a complete rewrite, based on the 23 * Posix defined bc(1) grammar. Other differences include type safe 24 * usage of pointers to build the tree of emitted code, typed yacc 25 * rule values, dynamic allocation of all data structures and a 26 * completely rewritten lexical analyzer using lex(1). 27 * 28 * Some effort has been made to make sure that the generated code is 29 * the same as the code generated by the older version, to provide 30 * easy regression testing. 31 */ 32 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 #include <sys/types.h> 37 #include <sys/wait.h> 38 39 #include <ctype.h> 40 #include <err.h> 41 #include <errno.h> 42 #include <getopt.h> 43 #include <histedit.h> 44 #include <limits.h> 45 #include <search.h> 46 #include <signal.h> 47 #include <stdarg.h> 48 #include <stdbool.h> 49 #include <string.h> 50 #include <unistd.h> 51 #include <stdlib.h> 52 53 #include "extern.h" 54 #include "pathnames.h" 55 56 #define BC_VER "1.0-FreeBSD" 57 #define END_NODE ((ssize_t) -1) 58 #define CONST_STRING ((ssize_t) -2) 59 #define ALLOC_STRING ((ssize_t) -3) 60 61 extern char *yytext; 62 extern FILE *yyin; 63 64 struct tree { 65 union { 66 char *astr; 67 const char *cstr; 68 } u; 69 ssize_t index; 70 }; 71 72 int yywrap(void); 73 74 int fileindex; 75 int sargc; 76 const char **sargv; 77 const char *filename; 78 char *cmdexpr; 79 80 static void grow(void); 81 static ssize_t cs(const char *); 82 static ssize_t as(const char *); 83 static ssize_t node(ssize_t, ...); 84 static void emit(ssize_t); 85 static void emit_macro(int, ssize_t); 86 static void free_tree(void); 87 static ssize_t numnode(int); 88 static ssize_t lookup(char *, size_t, char); 89 static ssize_t letter_node(char *); 90 static ssize_t array_node(char *); 91 static ssize_t function_node(char *); 92 93 static void add_par(ssize_t); 94 static void add_local(ssize_t); 95 static void warning(const char *); 96 static void init(void); 97 static void usage(void); 98 static char *escape(const char *); 99 100 static ssize_t instr_sz = 0; 101 static struct tree *instructions = NULL; 102 static ssize_t current = 0; 103 static int macro_char = '0'; 104 static int reset_macro_char = '0'; 105 static int nesting = 0; 106 static int breakstack[16]; 107 static int breaksp = 0; 108 static ssize_t prologue; 109 static ssize_t epilogue; 110 static bool st_has_continue; 111 static char str_table[UCHAR_MAX][2]; 112 static bool do_fork = true; 113 static u_short var_count; 114 static pid_t dc; 115 116 static void sigchld(int); 117 118 extern char *__progname; 119 120 #define BREAKSTACK_SZ (sizeof(breakstack)/sizeof(breakstack[0])) 121 122 /* These values are 4.4BSD bc compatible */ 123 #define FUNC_CHAR 0x01 124 #define ARRAY_CHAR 0xa1 125 126 /* Skip '\0', [, \ and ] */ 127 #define ENCODE(c) ((c) < '[' ? (c) : (c) + 3); 128 #define VAR_BASE (256-4) 129 #define MAX_VARIABLES (VAR_BASE * VAR_BASE) 130 131 const struct option long_options[] = 132 { 133 {"expression", required_argument, NULL, 'e'}, 134 {"help", no_argument, NULL, 'h'}, 135 {"mathlib", no_argument, NULL, 'l'}, 136 /* compatibility option */ 137 {"quiet", no_argument, NULL, 'q'}, 138 {"version", no_argument, NULL, 'v'}, 139 {NULL, no_argument, NULL, 0} 140 }; 141 142 %} 143 144 %start program 145 146 %union { 147 struct lvalue lvalue; 148 const char *str; 149 char *astr; 150 ssize_t node; 151 } 152 153 %token COMMA SEMICOLON LPAR RPAR LBRACE RBRACE LBRACKET RBRACKET DOT 154 %token NEWLINE 155 %token <astr> LETTER 156 %token <str> NUMBER STRING 157 %token DEFINE BREAK QUIT LENGTH 158 %token RETURN FOR IF WHILE SQRT 159 %token SCALE IBASE OBASE AUTO 160 %token CONTINUE ELSE PRINT 161 162 %left BOOL_OR 163 %left BOOL_AND 164 %nonassoc BOOL_NOT 165 %nonassoc EQUALS LESS_EQ GREATER_EQ UNEQUALS LESS GREATER 166 %right <str> ASSIGN_OP 167 %left PLUS MINUS 168 %left MULTIPLY DIVIDE REMAINDER 169 %right EXPONENT 170 %nonassoc UMINUS 171 %nonassoc INCR DECR 172 173 %type <lvalue> named_expression 174 %type <node> argument_list 175 %type <node> alloc_macro 176 %type <node> expression 177 %type <node> function 178 %type <node> function_header 179 %type <node> input_item 180 %type <node> opt_argument_list 181 %type <node> opt_expression 182 %type <node> opt_relational_expression 183 %type <node> opt_statement 184 %type <node> print_expression 185 %type <node> print_expression_list 186 %type <node> relational_expression 187 %type <node> return_expression 188 %type <node> semicolon_list 189 %type <node> statement 190 %type <node> statement_list 191 192 %% 193 194 program : /* empty */ 195 | program input_item 196 ; 197 198 input_item : semicolon_list NEWLINE 199 { 200 emit($1); 201 macro_char = reset_macro_char; 202 putchar('\n'); 203 free_tree(); 204 st_has_continue = false; 205 } 206 | function 207 { 208 putchar('\n'); 209 free_tree(); 210 st_has_continue = false; 211 } 212 | error NEWLINE 213 { 214 yyerrok; 215 } 216 | error QUIT 217 { 218 yyerrok; 219 } 220 ; 221 222 semicolon_list : /* empty */ 223 { 224 $$ = cs(""); 225 } 226 | statement 227 | semicolon_list SEMICOLON statement 228 { 229 $$ = node($1, $3, END_NODE); 230 } 231 | semicolon_list SEMICOLON 232 ; 233 234 statement_list : /* empty */ 235 { 236 $$ = cs(""); 237 } 238 | statement 239 | statement_list NEWLINE 240 | statement_list NEWLINE statement 241 { 242 $$ = node($1, $3, END_NODE); 243 } 244 | statement_list SEMICOLON 245 | statement_list SEMICOLON statement 246 { 247 $$ = node($1, $3, END_NODE); 248 } 249 ; 250 251 252 opt_statement : /* empty */ 253 { 254 $$ = cs(""); 255 } 256 | statement 257 ; 258 259 statement : expression 260 { 261 $$ = node($1, cs("ps."), END_NODE); 262 } 263 | named_expression ASSIGN_OP expression 264 { 265 if ($2[0] == '\0') 266 $$ = node($3, cs($2), $1.store, 267 END_NODE); 268 else 269 $$ = node($1.load, $3, cs($2), $1.store, 270 END_NODE); 271 } 272 | STRING 273 { 274 $$ = node(cs("["), as($1), 275 cs("]P"), END_NODE); 276 } 277 | BREAK 278 { 279 if (breaksp == 0) { 280 warning("break not in for or while"); 281 YYERROR; 282 } else { 283 $$ = node( 284 numnode(nesting - 285 breakstack[breaksp-1]), 286 cs("Q"), END_NODE); 287 } 288 } 289 | CONTINUE 290 { 291 if (breaksp == 0) { 292 warning("continue not in for or while"); 293 YYERROR; 294 } else { 295 st_has_continue = true; 296 $$ = node(numnode(nesting - 297 breakstack[breaksp-1] - 1), 298 cs("J"), END_NODE); 299 } 300 } 301 | QUIT 302 { 303 sigset_t mask; 304 305 putchar('q'); 306 fflush(stdout); 307 if (dc) { 308 sigprocmask(SIG_BLOCK, NULL, &mask); 309 sigsuspend(&mask); 310 } else 311 exit(0); 312 } 313 | RETURN return_expression 314 { 315 if (nesting == 0) { 316 warning("return must be in a function"); 317 YYERROR; 318 } 319 $$ = $2; 320 } 321 | FOR LPAR alloc_macro opt_expression SEMICOLON 322 opt_relational_expression SEMICOLON 323 opt_expression RPAR opt_statement pop_nesting 324 { 325 ssize_t n; 326 327 if (st_has_continue) 328 n = node($10, cs("M"), $8, cs("s."), 329 $6, $3, END_NODE); 330 else 331 n = node($10, $8, cs("s."), $6, $3, 332 END_NODE); 333 334 emit_macro($3, n); 335 $$ = node($4, cs("s."), $6, $3, cs(" "), 336 END_NODE); 337 } 338 | IF LPAR alloc_macro pop_nesting relational_expression RPAR 339 opt_statement 340 { 341 emit_macro($3, $7); 342 $$ = node($5, $3, cs(" "), END_NODE); 343 } 344 | IF LPAR alloc_macro pop_nesting relational_expression RPAR 345 opt_statement ELSE alloc_macro pop_nesting opt_statement 346 { 347 emit_macro($3, $7); 348 emit_macro($9, $11); 349 $$ = node($5, $3, cs("e"), $9, cs(" "), 350 END_NODE); 351 } 352 | WHILE LPAR alloc_macro relational_expression RPAR 353 opt_statement pop_nesting 354 { 355 ssize_t n; 356 357 if (st_has_continue) 358 n = node($6, cs("M"), $4, $3, END_NODE); 359 else 360 n = node($6, $4, $3, END_NODE); 361 emit_macro($3, n); 362 $$ = node($4, $3, cs(" "), END_NODE); 363 } 364 | LBRACE statement_list RBRACE 365 { 366 $$ = $2; 367 } 368 | PRINT print_expression_list 369 { 370 $$ = $2; 371 } 372 ; 373 374 alloc_macro : /* empty */ 375 { 376 $$ = cs(str_table[macro_char]); 377 macro_char++; 378 /* Do not use [, \ and ] */ 379 if (macro_char == '[') 380 macro_char += 3; 381 /* skip letters */ 382 else if (macro_char == 'a') 383 macro_char = '{'; 384 else if (macro_char == ARRAY_CHAR) 385 macro_char += 26; 386 else if (macro_char == 255) 387 fatal("program too big"); 388 if (breaksp == BREAKSTACK_SZ) 389 fatal("nesting too deep"); 390 breakstack[breaksp++] = nesting++; 391 } 392 ; 393 394 pop_nesting : /* empty */ 395 { 396 breaksp--; 397 } 398 ; 399 400 function : function_header opt_parameter_list RPAR opt_newline 401 LBRACE NEWLINE opt_auto_define_list 402 statement_list RBRACE 403 { 404 int n = node(prologue, $8, epilogue, 405 cs("0"), numnode(nesting), 406 cs("Q"), END_NODE); 407 emit_macro($1, n); 408 reset_macro_char = macro_char; 409 nesting = 0; 410 breaksp = 0; 411 } 412 ; 413 414 function_header : DEFINE LETTER LPAR 415 { 416 $$ = function_node($2); 417 free($2); 418 prologue = cs(""); 419 epilogue = cs(""); 420 nesting = 1; 421 breaksp = 0; 422 breakstack[breaksp] = 0; 423 } 424 ; 425 426 opt_newline : /* empty */ 427 | NEWLINE 428 ; 429 430 opt_parameter_list 431 : /* empty */ 432 | parameter_list 433 ; 434 435 436 parameter_list : LETTER 437 { 438 add_par(letter_node($1)); 439 free($1); 440 } 441 | LETTER LBRACKET RBRACKET 442 { 443 add_par(array_node($1)); 444 free($1); 445 } 446 | parameter_list COMMA LETTER 447 { 448 add_par(letter_node($3)); 449 free($3); 450 } 451 | parameter_list COMMA LETTER LBRACKET RBRACKET 452 { 453 add_par(array_node($3)); 454 free($3); 455 } 456 ; 457 458 459 460 opt_auto_define_list 461 : /* empty */ 462 | AUTO define_list NEWLINE 463 | AUTO define_list SEMICOLON 464 ; 465 466 467 define_list : LETTER 468 { 469 add_local(letter_node($1)); 470 free($1); 471 } 472 | LETTER LBRACKET RBRACKET 473 { 474 add_local(array_node($1)); 475 free($1); 476 } 477 | define_list COMMA LETTER 478 { 479 add_local(letter_node($3)); 480 free($3); 481 } 482 | define_list COMMA LETTER LBRACKET RBRACKET 483 { 484 add_local(array_node($3)); 485 free($3); 486 } 487 ; 488 489 490 opt_argument_list 491 : /* empty */ 492 { 493 $$ = cs(""); 494 } 495 | argument_list 496 ; 497 498 499 argument_list : expression 500 | argument_list COMMA expression 501 { 502 $$ = node($1, $3, END_NODE); 503 } 504 | argument_list COMMA LETTER LBRACKET RBRACKET 505 { 506 $$ = node($1, cs("l"), array_node($3), 507 END_NODE); 508 free($3); 509 } 510 ; 511 512 opt_relational_expression 513 : /* empty */ 514 { 515 $$ = cs(" 0 0="); 516 } 517 | relational_expression 518 ; 519 520 relational_expression 521 : expression EQUALS expression 522 { 523 $$ = node($1, $3, cs("="), END_NODE); 524 } 525 | expression UNEQUALS expression 526 { 527 $$ = node($1, $3, cs("!="), END_NODE); 528 } 529 | expression LESS expression 530 { 531 $$ = node($1, $3, cs(">"), END_NODE); 532 } 533 | expression LESS_EQ expression 534 { 535 $$ = node($1, $3, cs("!<"), END_NODE); 536 } 537 | expression GREATER expression 538 { 539 $$ = node($1, $3, cs("<"), END_NODE); 540 } 541 | expression GREATER_EQ expression 542 { 543 $$ = node($1, $3, cs("!>"), END_NODE); 544 } 545 | expression 546 { 547 $$ = node($1, cs(" 0!="), END_NODE); 548 } 549 ; 550 551 552 return_expression 553 : /* empty */ 554 { 555 $$ = node(cs("0"), epilogue, 556 numnode(nesting), cs("Q"), END_NODE); 557 } 558 | expression 559 { 560 $$ = node($1, epilogue, 561 numnode(nesting), cs("Q"), END_NODE); 562 } 563 | LPAR RPAR 564 { 565 $$ = node(cs("0"), epilogue, 566 numnode(nesting), cs("Q"), END_NODE); 567 } 568 ; 569 570 571 opt_expression : /* empty */ 572 { 573 $$ = cs(" 0"); 574 } 575 | expression 576 ; 577 578 expression : named_expression 579 { 580 $$ = node($1.load, END_NODE); 581 } 582 | DOT { 583 $$ = node(cs("l."), END_NODE); 584 } 585 | NUMBER 586 { 587 $$ = node(cs(" "), as($1), END_NODE); 588 } 589 | LPAR expression RPAR 590 { 591 $$ = $2; 592 } 593 | LETTER LPAR opt_argument_list RPAR 594 { 595 $$ = node($3, cs("l"), 596 function_node($1), cs("x"), 597 END_NODE); 598 free($1); 599 } 600 | MINUS expression %prec UMINUS 601 { 602 $$ = node(cs(" 0"), $2, cs("-"), 603 END_NODE); 604 } 605 | expression PLUS expression 606 { 607 $$ = node($1, $3, cs("+"), END_NODE); 608 } 609 | expression MINUS expression 610 { 611 $$ = node($1, $3, cs("-"), END_NODE); 612 } 613 | expression MULTIPLY expression 614 { 615 $$ = node($1, $3, cs("*"), END_NODE); 616 } 617 | expression DIVIDE expression 618 { 619 $$ = node($1, $3, cs("/"), END_NODE); 620 } 621 | expression REMAINDER expression 622 { 623 $$ = node($1, $3, cs("%"), END_NODE); 624 } 625 | expression EXPONENT expression 626 { 627 $$ = node($1, $3, cs("^"), END_NODE); 628 } 629 | INCR named_expression 630 { 631 $$ = node($2.load, cs("1+d"), $2.store, 632 END_NODE); 633 } 634 | DECR named_expression 635 { 636 $$ = node($2.load, cs("1-d"), 637 $2.store, END_NODE); 638 } 639 | named_expression INCR 640 { 641 $$ = node($1.load, cs("d1+"), 642 $1.store, END_NODE); 643 } 644 | named_expression DECR 645 { 646 $$ = node($1.load, cs("d1-"), 647 $1.store, END_NODE); 648 } 649 | named_expression ASSIGN_OP expression 650 { 651 if ($2[0] == '\0') 652 $$ = node($3, cs($2), cs("d"), $1.store, 653 END_NODE); 654 else 655 $$ = node($1.load, $3, cs($2), cs("d"), 656 $1.store, END_NODE); 657 } 658 | LENGTH LPAR expression RPAR 659 { 660 $$ = node($3, cs("Z"), END_NODE); 661 } 662 | SQRT LPAR expression RPAR 663 { 664 $$ = node($3, cs("v"), END_NODE); 665 } 666 | SCALE LPAR expression RPAR 667 { 668 $$ = node($3, cs("X"), END_NODE); 669 } 670 | BOOL_NOT expression 671 { 672 $$ = node($2, cs("N"), END_NODE); 673 } 674 | expression BOOL_AND alloc_macro pop_nesting expression 675 { 676 ssize_t n = node(cs("R"), $5, END_NODE); 677 emit_macro($3, n); 678 $$ = node($1, cs("d0!="), $3, END_NODE); 679 } 680 | expression BOOL_OR alloc_macro pop_nesting expression 681 { 682 ssize_t n = node(cs("R"), $5, END_NODE); 683 emit_macro($3, n); 684 $$ = node($1, cs("d0="), $3, END_NODE); 685 } 686 | expression EQUALS expression 687 { 688 $$ = node($1, $3, cs("G"), END_NODE); 689 } 690 | expression UNEQUALS expression 691 { 692 $$ = node($1, $3, cs("GN"), END_NODE); 693 } 694 | expression LESS expression 695 { 696 $$ = node($3, $1, cs("("), END_NODE); 697 } 698 | expression LESS_EQ expression 699 { 700 $$ = node($3, $1, cs("{"), END_NODE); 701 } 702 | expression GREATER expression 703 { 704 $$ = node($1, $3, cs("("), END_NODE); 705 } 706 | expression GREATER_EQ expression 707 { 708 $$ = node($1, $3, cs("{"), END_NODE); 709 } 710 ; 711 712 named_expression 713 : LETTER 714 { 715 $$.load = node(cs("l"), letter_node($1), 716 END_NODE); 717 $$.store = node(cs("s"), letter_node($1), 718 END_NODE); 719 free($1); 720 } 721 | LETTER LBRACKET expression RBRACKET 722 { 723 $$.load = node($3, cs(";"), 724 array_node($1), END_NODE); 725 $$.store = node($3, cs(":"), 726 array_node($1), END_NODE); 727 free($1); 728 } 729 | SCALE 730 { 731 $$.load = cs("K"); 732 $$.store = cs("k"); 733 } 734 | IBASE 735 { 736 $$.load = cs("I"); 737 $$.store = cs("i"); 738 } 739 | OBASE 740 { 741 $$.load = cs("O"); 742 $$.store = cs("o"); 743 } 744 ; 745 746 print_expression_list 747 : print_expression 748 | print_expression_list COMMA print_expression 749 { 750 $$ = node($1, $3, END_NODE); 751 } 752 753 print_expression 754 : expression 755 { 756 $$ = node($1, cs("ds.n"), END_NODE); 757 } 758 | STRING 759 { 760 char *p = escape($1); 761 $$ = node(cs("["), as(p), cs("]n"), END_NODE); 762 free(p); 763 } 764 %% 765 766 767 static void 768 grow(void) 769 { 770 struct tree *p; 771 size_t newsize; 772 773 if (current == instr_sz) { 774 newsize = instr_sz * 2 + 1; 775 p = realloc(instructions, newsize * sizeof(*p)); 776 if (p == NULL) { 777 free(instructions); 778 err(1, NULL); 779 } 780 instructions = p; 781 instr_sz = newsize; 782 } 783 } 784 785 static ssize_t 786 cs(const char *str) 787 { 788 789 grow(); 790 instructions[current].index = CONST_STRING; 791 instructions[current].u.cstr = str; 792 return (current++); 793 } 794 795 static ssize_t 796 as(const char *str) 797 { 798 799 grow(); 800 instructions[current].index = ALLOC_STRING; 801 instructions[current].u.astr = strdup(str); 802 if (instructions[current].u.astr == NULL) 803 err(1, NULL); 804 return (current++); 805 } 806 807 static ssize_t 808 node(ssize_t arg, ...) 809 { 810 va_list ap; 811 ssize_t ret; 812 813 va_start(ap, arg); 814 815 ret = current; 816 grow(); 817 instructions[current++].index = arg; 818 819 do { 820 arg = va_arg(ap, ssize_t); 821 grow(); 822 instructions[current++].index = arg; 823 } while (arg != END_NODE); 824 825 va_end(ap); 826 return (ret); 827 } 828 829 static void 830 emit(ssize_t i) 831 { 832 833 if (instructions[i].index >= 0) 834 while (instructions[i].index != END_NODE) 835 emit(instructions[i++].index); 836 else 837 fputs(instructions[i].u.cstr, stdout); 838 } 839 840 static void 841 emit_macro(int nodeidx, ssize_t code) 842 { 843 844 putchar('['); 845 emit(code); 846 printf("]s%s\n", instructions[nodeidx].u.cstr); 847 nesting--; 848 } 849 850 static void 851 free_tree(void) 852 { 853 ssize_t i; 854 855 for (i = 0; i < current; i++) 856 if (instructions[i].index == ALLOC_STRING) 857 free(instructions[i].u.astr); 858 current = 0; 859 } 860 861 static ssize_t 862 numnode(int num) 863 { 864 const char *p; 865 866 if (num < 10) 867 p = str_table['0' + num]; 868 else if (num < 16) 869 p = str_table['A' - 10 + num]; 870 else 871 errx(1, "internal error: break num > 15"); 872 return (node(cs(" "), cs(p), END_NODE)); 873 } 874 875 876 static ssize_t 877 lookup(char * str, size_t len, char type) 878 { 879 ENTRY entry, *found; 880 u_char *p; 881 u_short num; 882 883 /* The scanner allocated an extra byte already */ 884 if (str[len-1] != type) { 885 str[len] = type; 886 str[len+1] = '\0'; 887 } 888 entry.key = str; 889 found = hsearch(entry, FIND); 890 if (found == NULL) { 891 if (var_count == MAX_VARIABLES) 892 errx(1, "too many variables"); 893 p = malloc(4); 894 if (p == NULL) 895 err(1, NULL); 896 num = var_count++; 897 p[0] = 255; 898 p[1] = ENCODE(num / VAR_BASE + 1); 899 p[2] = ENCODE(num % VAR_BASE + 1); 900 p[3] = '\0'; 901 902 entry.data = (char *)p; 903 entry.key = strdup(str); 904 if (entry.key == NULL) 905 err(1, NULL); 906 found = hsearch(entry, ENTER); 907 if (found == NULL) 908 err(1, NULL); 909 } 910 return (cs(found->data)); 911 } 912 913 static ssize_t 914 letter_node(char *str) 915 { 916 size_t len; 917 918 len = strlen(str); 919 if (len == 1 && str[0] != '_') 920 return (cs(str_table[(int)str[0]])); 921 else 922 return (lookup(str, len, 'L')); 923 } 924 925 static ssize_t 926 array_node(char *str) 927 { 928 size_t len; 929 930 len = strlen(str); 931 if (len == 1 && str[0] != '_') 932 return (cs(str_table[(int)str[0] - 'a' + ARRAY_CHAR])); 933 else 934 return (lookup(str, len, 'A')); 935 } 936 937 static ssize_t 938 function_node(char *str) 939 { 940 size_t len; 941 942 len = strlen(str); 943 if (len == 1 && str[0] != '_') 944 return (cs(str_table[(int)str[0] - 'a' + FUNC_CHAR])); 945 else 946 return (lookup(str, len, 'F')); 947 } 948 949 static void 950 add_par(ssize_t n) 951 { 952 953 prologue = node(cs("S"), n, prologue, END_NODE); 954 epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE); 955 } 956 957 static void 958 add_local(ssize_t n) 959 { 960 961 prologue = node(cs("0S"), n, prologue, END_NODE); 962 epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE); 963 } 964 965 void 966 yyerror(const char *s) 967 { 968 char *p, *str; 969 int n; 970 971 if (yyin != NULL && feof(yyin)) 972 n = asprintf(&str, "%s: %s:%d: %s: unexpected EOF", 973 __progname, filename, lineno, s); 974 else if (isspace(yytext[0]) || !isprint(yytext[0])) 975 n = asprintf(&str, 976 "%s: %s:%d: %s: ascii char 0x%02x unexpected", 977 __progname, filename, lineno, s, yytext[0]); 978 else 979 n = asprintf(&str, "%s: %s:%d: %s: %s unexpected", 980 __progname, filename, lineno, s, yytext); 981 if (n == -1) 982 err(1, NULL); 983 984 fputs("c[", stdout); 985 for (p = str; *p != '\0'; p++) { 986 if (*p == '[' || *p == ']' || *p =='\\') 987 putchar('\\'); 988 putchar(*p); 989 } 990 fputs("]pc\n", stdout); 991 free(str); 992 } 993 994 void 995 fatal(const char *s) 996 { 997 998 errx(1, "%s:%d: %s", filename, lineno, s); 999 } 1000 1001 static void 1002 warning(const char *s) 1003 { 1004 1005 warnx("%s:%d: %s", filename, lineno, s); 1006 } 1007 1008 static void 1009 init(void) 1010 { 1011 unsigned int i; 1012 1013 for (i = 0; i < UCHAR_MAX; i++) { 1014 str_table[i][0] = i; 1015 str_table[i][1] = '\0'; 1016 } 1017 if (hcreate(1 << 16) == 0) 1018 err(1, NULL); 1019 } 1020 1021 1022 static void 1023 usage(void) 1024 { 1025 1026 fprintf(stderr, "usage: %s [-chlqv] [-e expression] [file ...]\n", 1027 __progname); 1028 exit(1); 1029 } 1030 1031 static char * 1032 escape(const char *str) 1033 { 1034 char *p, *ret; 1035 1036 ret = malloc(strlen(str) + 1); 1037 if (ret == NULL) 1038 err(1, NULL); 1039 1040 p = ret; 1041 while (*str != '\0') { 1042 /* 1043 * We get _escaped_ strings here. Single backslashes are 1044 * already converted to double backslashes 1045 */ 1046 if (*str == '\\') { 1047 if (*++str == '\\') { 1048 switch (*++str) { 1049 case 'a': 1050 *p++ = '\a'; 1051 break; 1052 case 'b': 1053 *p++ = '\b'; 1054 break; 1055 case 'f': 1056 *p++ = '\f'; 1057 break; 1058 case 'n': 1059 *p++ = '\n'; 1060 break; 1061 case 'q': 1062 *p++ = '"'; 1063 break; 1064 case 'r': 1065 *p++ = '\r'; 1066 break; 1067 case 't': 1068 *p++ = '\t'; 1069 break; 1070 case '\\': 1071 *p++ = '\\'; 1072 break; 1073 } 1074 str++; 1075 } else { 1076 *p++ = '\\'; 1077 *p++ = *str++; 1078 } 1079 } else 1080 *p++ = *str++; 1081 } 1082 *p = '\0'; 1083 return (ret); 1084 } 1085 1086 /* ARGSUSED */ 1087 static void 1088 sigchld(int signo) 1089 { 1090 pid_t pid; 1091 int status; 1092 1093 switch (signo) { 1094 default: 1095 for (;;) { 1096 pid = waitpid(dc, &status, WUNTRACED); 1097 if (pid == -1) { 1098 if (errno == EINTR) 1099 continue; 1100 _exit(0); 1101 } 1102 if (WIFEXITED(status) || WIFSIGNALED(status)) 1103 _exit(0); 1104 else 1105 break; 1106 } 1107 } 1108 } 1109 1110 static const char * 1111 dummy_prompt(void) 1112 { 1113 1114 return (""); 1115 } 1116 1117 int 1118 main(int argc, char *argv[]) 1119 { 1120 char *q; 1121 int p[2]; 1122 int ch, i; 1123 1124 init(); 1125 setlinebuf(stdout); 1126 1127 sargv = malloc(argc * sizeof(char *)); 1128 if (sargv == NULL) 1129 err(1, NULL); 1130 1131 if ((cmdexpr = strdup("")) == NULL) 1132 err(1, NULL); 1133 /* The d debug option is 4.4 BSD bc(1) compatible */ 1134 while ((ch = getopt_long(argc, argv, "cde:hlqv", 1135 long_options, NULL)) != -1) { 1136 switch (ch) { 1137 case 'c': 1138 case 'd': 1139 do_fork = false; 1140 break; 1141 case 'e': 1142 q = cmdexpr; 1143 if (asprintf(&cmdexpr, "%s%s\n", cmdexpr, optarg) == -1) 1144 err(1, NULL); 1145 free(q); 1146 break; 1147 case 'h': 1148 usage(); 1149 break; 1150 case 'l': 1151 sargv[sargc++] = _PATH_LIBB; 1152 break; 1153 case 'q': 1154 /* compatibility option */ 1155 break; 1156 case 'v': 1157 fprintf(stderr, "%s (BSD bc) %s\n", __progname, BC_VER); 1158 exit(0); 1159 break; 1160 default: 1161 usage(); 1162 } 1163 } 1164 1165 argc -= optind; 1166 argv += optind; 1167 1168 interactive = isatty(STDIN_FILENO); 1169 for (i = 0; i < argc; i++) 1170 sargv[sargc++] = argv[i]; 1171 1172 if (do_fork) { 1173 if (pipe(p) == -1) 1174 err(1, "cannot create pipe"); 1175 dc = fork(); 1176 if (dc == -1) 1177 err(1, "cannot fork"); 1178 else if (dc != 0) { 1179 signal(SIGCHLD, sigchld); 1180 close(STDOUT_FILENO); 1181 dup(p[1]); 1182 close(p[0]); 1183 close(p[1]); 1184 } else { 1185 close(STDIN_FILENO); 1186 dup(p[0]); 1187 close(p[0]); 1188 close(p[1]); 1189 execl(_PATH_DC, "dc", "-x", (char *)NULL); 1190 err(1, "cannot find dc"); 1191 } 1192 } 1193 if (interactive) { 1194 el = el_init("bc", stdin, stderr, stderr); 1195 hist = history_init(); 1196 history(hist, &he, H_SETSIZE, 100); 1197 el_set(el, EL_HIST, history, hist); 1198 el_set(el, EL_EDITOR, "emacs"); 1199 el_set(el, EL_SIGNAL, 1); 1200 el_set(el, EL_PROMPT, dummy_prompt); 1201 el_source(el, NULL); 1202 } 1203 yywrap(); 1204 return (yyparse()); 1205 } 1206