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