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