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