bc.y revision 202719
1%{ 2/* $OpenBSD: bc.y,v 1.33 2009/10/27 23:59:36 deraadt Exp $ */ 3 4/* 5 * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20/* 21 * This implementation of bc(1) uses concepts from the original 4.4 22 * BSD bc(1). The code itself is a complete rewrite, based on the 23 * Posix defined bc(1) grammar. Other differences include type safe 24 * usage of pointers to build the tree of emitted code, typed yacc 25 * rule values, dynamic allocation of all data structures and a 26 * completely rewritten lexical analyzer using lex(1). 27 * 28 * Some effort has been made to make sure that the generated code is 29 * the same as the code generated by the older version, to provide 30 * easy regression testing. 31 */ 32 33#include <sys/cdefs.h> 34__FBSDID("$FreeBSD: head/usr.bin/bc/bc.y 202719 2010-01-20 21:30:52Z gabor $"); 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 <limits.h> 44#include <search.h> 45#include <signal.h> 46#include <stdarg.h> 47#include <stdbool.h> 48#include <string.h> 49#include <unistd.h> 50 51#include "extern.h" 52#include "pathnames.h" 53 54#define BC_VER "1.0-FreeBSD" 55#define END_NODE ((ssize_t) -1) 56#define CONST_STRING ((ssize_t) -2) 57#define ALLOC_STRING ((ssize_t) -3) 58 59extern char *yytext; 60extern FILE *yyin; 61 62struct tree { 63 ssize_t index; 64 union { 65 char *astr; 66 const char *cstr; 67 } u; 68}; 69 70int yyparse(void); 71int yywrap(void); 72 73int fileindex; 74int sargc; 75const char **sargv; 76const char *filename; 77char *cmdexpr; 78 79static void grow(void); 80static ssize_t cs(const char *); 81static ssize_t as(const char *); 82static ssize_t node(ssize_t, ...); 83static void emit(ssize_t); 84static void emit_macro(int, ssize_t); 85static void free_tree(void); 86static ssize_t numnode(int); 87static ssize_t lookup(char *, size_t, char); 88static ssize_t letter_node(char *); 89static ssize_t array_node(char *); 90static ssize_t function_node(char *); 91 92static void add_par(ssize_t); 93static void add_local(ssize_t); 94static void warning(const char *); 95static void init(void); 96static void usage(void); 97static char *escape(const char *); 98 99static ssize_t instr_sz = 0; 100static struct tree *instructions = NULL; 101static ssize_t current = 0; 102static int macro_char = '0'; 103static int reset_macro_char = '0'; 104static int nesting = 0; 105static int breakstack[16]; 106static int breaksp = 0; 107static ssize_t prologue; 108static ssize_t epilogue; 109static bool st_has_continue; 110static char str_table[UCHAR_MAX][2]; 111static bool do_fork = true; 112static u_short var_count; 113static pid_t dc; 114 115static void sigchld(int); 116 117extern 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 130const struct option long_options[] = 131{ 132 {"debug", no_argument, NULL, 'd'}, 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 ssize_t node; 148 struct lvalue lvalue; 149 const char *str; 150 char *astr; 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 grow(); 789 instructions[current].index = CONST_STRING; 790 instructions[current].u.cstr = str; 791 return (current++); 792} 793 794static ssize_t 795as(const char *str) 796{ 797 grow(); 798 instructions[current].index = ALLOC_STRING; 799 instructions[current].u.astr = strdup(str); 800 if (instructions[current].u.astr == NULL) 801 err(1, NULL); 802 return (current++); 803} 804 805static ssize_t 806node(ssize_t arg, ...) 807{ 808 va_list ap; 809 ssize_t ret; 810 811 va_start(ap, arg); 812 813 ret = current; 814 grow(); 815 instructions[current++].index = arg; 816 817 do { 818 arg = va_arg(ap, ssize_t); 819 grow(); 820 instructions[current++].index = arg; 821 } while (arg != END_NODE); 822 823 va_end(ap); 824 return (ret); 825} 826 827static void 828emit(ssize_t i) 829{ 830 if (instructions[i].index >= 0) 831 while (instructions[i].index != END_NODE) 832 emit(instructions[i++].index); 833 else 834 fputs(instructions[i].u.cstr, stdout); 835} 836 837static void 838emit_macro(int nodeidx, ssize_t code) 839{ 840 putchar('['); 841 emit(code); 842 printf("]s%s\n", instructions[nodeidx].u.cstr); 843 nesting--; 844} 845 846static void 847free_tree(void) 848{ 849 ssize_t i; 850 851 for (i = 0; i < current; i++) 852 if (instructions[i].index == ALLOC_STRING) 853 free(instructions[i].u.astr); 854 current = 0; 855} 856 857static ssize_t 858numnode(int num) 859{ 860 const char *p; 861 862 if (num < 10) 863 p = str_table['0' + num]; 864 else if (num < 16) 865 p = str_table['A' - 10 + num]; 866 else 867 errx(1, "internal error: break num > 15"); 868 return (node(cs(" "), cs(p), END_NODE)); 869} 870 871 872static ssize_t 873lookup(char * str, size_t len, char type) 874{ 875 ENTRY entry, *found; 876 u_short num; 877 u_char *p; 878 879 /* The scanner allocated an extra byte already */ 880 if (str[len-1] != type) { 881 str[len] = type; 882 str[len+1] = '\0'; 883 } 884 entry.key = str; 885 found = hsearch(entry, FIND); 886 if (found == NULL) { 887 if (var_count == MAX_VARIABLES) 888 errx(1, "too many variables"); 889 p = malloc(4); 890 if (p == NULL) 891 err(1, NULL); 892 num = var_count++; 893 p[0] = 255; 894 p[1] = ENCODE(num / VAR_BASE + 1); 895 p[2] = ENCODE(num % VAR_BASE + 1); 896 p[3] = '\0'; 897 898 entry.data = (char *)p; 899 entry.key = strdup(str); 900 if (entry.key == NULL) 901 err(1, NULL); 902 found = hsearch(entry, ENTER); 903 if (found == NULL) 904 err(1, NULL); 905 } 906 return (cs(found->data)); 907} 908 909static ssize_t 910letter_node(char *str) 911{ 912 size_t len; 913 914 len = strlen(str); 915 if (len == 1 && str[0] != '_') 916 return (cs(str_table[(int)str[0]])); 917 else 918 return (lookup(str, len, 'L')); 919} 920 921static ssize_t 922array_node(char *str) 923{ 924 size_t len; 925 926 len = strlen(str); 927 if (len == 1 && str[0] != '_') 928 return (cs(str_table[(int)str[0] - 'a' + ARRAY_CHAR])); 929 else 930 return (lookup(str, len, 'A')); 931} 932 933static ssize_t 934function_node(char *str) 935{ 936 size_t len; 937 938 len = strlen(str); 939 if (len == 1 && str[0] != '_') 940 return (cs(str_table[(int)str[0] - 'a' + FUNC_CHAR])); 941 else 942 return (lookup(str, len, 'F')); 943} 944 945static void 946add_par(ssize_t n) 947{ 948 prologue = node(cs("S"), n, prologue, END_NODE); 949 epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE); 950} 951 952static void 953add_local(ssize_t n) 954{ 955 prologue = node(cs("0S"), n, prologue, END_NODE); 956 epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE); 957} 958 959void 960yyerror(const char *s) 961{ 962 char *str, *p; 963 int n; 964 965 if (yyin != NULL && feof(yyin)) 966 n = asprintf(&str, "%s: %s:%d: %s: unexpected EOF", 967 __progname, filename, lineno, s); 968 else if (isspace(yytext[0]) || !isprint(yytext[0])) 969 n = asprintf(&str, 970 "%s: %s:%d: %s: ascii char 0x%02x unexpected", 971 __progname, filename, lineno, s, yytext[0]); 972 else 973 n = asprintf(&str, "%s: %s:%d: %s: %s unexpected", 974 __progname, filename, lineno, s, yytext); 975 if (n == -1) 976 err(1, NULL); 977 978 fputs("c[", stdout); 979 for (p = str; *p != '\0'; p++) { 980 if (*p == '[' || *p == ']' || *p =='\\') 981 putchar('\\'); 982 putchar(*p); 983 } 984 fputs("]pc\n", stdout); 985 free(str); 986} 987 988void 989fatal(const char *s) 990{ 991 errx(1, "%s:%d: %s", filename, lineno, s); 992} 993 994static void 995warning(const char *s) 996{ 997 warnx("%s:%d: %s", filename, lineno, s); 998} 999 1000static void 1001init(void) 1002{ 1003 unsigned int i; 1004 1005 for (i = 0; i < UCHAR_MAX; i++) { 1006 str_table[i][0] = i; 1007 str_table[i][1] = '\0'; 1008 } 1009 if (hcreate(1 << 16) == 0) 1010 err(1, NULL); 1011} 1012 1013 1014static void 1015usage(void) 1016{ 1017 fprintf(stderr, "usage: %s [-cdhlqv] [-e expression] [file ...]\n", 1018 __progname); 1019 exit(1); 1020} 1021 1022static char * 1023escape(const char *str) 1024{ 1025 char *ret, *p; 1026 1027 ret = malloc(strlen(str) + 1); 1028 if (ret == NULL) 1029 err(1, NULL); 1030 1031 p = ret; 1032 while (*str != '\0') { 1033 /* 1034 * We get _escaped_ strings here. Single backslashes are 1035 * already converted to double backslashes 1036 */ 1037 if (*str == '\\') { 1038 if (*++str == '\\') { 1039 switch (*++str) { 1040 case 'a': 1041 *p++ = '\a'; 1042 break; 1043 case 'b': 1044 *p++ = '\b'; 1045 break; 1046 case 'f': 1047 *p++ = '\f'; 1048 break; 1049 case 'n': 1050 *p++ = '\n'; 1051 break; 1052 case 'q': 1053 *p++ = '"'; 1054 break; 1055 case 'r': 1056 *p++ = '\r'; 1057 break; 1058 case 't': 1059 *p++ = '\t'; 1060 break; 1061 case '\\': 1062 *p++ = '\\'; 1063 break; 1064 } 1065 str++; 1066 } else { 1067 *p++ = '\\'; 1068 *p++ = *str++; 1069 } 1070 } else 1071 *p++ = *str++; 1072 } 1073 *p = '\0'; 1074 return (ret); 1075} 1076 1077/* ARGSUSED */ 1078void 1079sigchld(int signo) 1080{ 1081 pid_t pid; 1082 int status; 1083 1084 switch (signo) { 1085 default: 1086 for (;;) { 1087 pid = waitpid(dc, &status, WCONTINUED); 1088 if (pid == -1) { 1089 if (errno == EINTR) 1090 continue; 1091 _exit(0); 1092 } 1093 if (WIFEXITED(status) || WIFSIGNALED(status)) 1094 _exit(0); 1095 else 1096 break; 1097 } 1098 } 1099} 1100 1101int 1102main(int argc, char *argv[]) 1103{ 1104 int i, ch; 1105 int p[2]; 1106 char *q; 1107 1108 init(); 1109 setlinebuf(stdout); 1110 1111 sargv = malloc(argc * sizeof(char *)); 1112 if (sargv == NULL) 1113 err(1, NULL); 1114 1115 if ((cmdexpr = strdup("")) == NULL) 1116 err(1, NULL); 1117 /* The d debug option is 4.4 BSD bc(1) compatible */ 1118 while ((ch = getopt_long(argc, argv, "cde:hlqv", 1119 long_options, NULL)) != -1) { 1120 switch (ch) { 1121 case 'c': 1122 case 'd': 1123 do_fork = false; 1124 break; 1125 case 'e': 1126 q = cmdexpr; 1127 if (asprintf(&cmdexpr, "%s%s\n", cmdexpr, optarg) == -1) 1128 err(1, NULL); 1129 free(q); 1130 break; 1131 case 'h': 1132 usage(); 1133 break; 1134 case 'l': 1135 sargv[sargc++] = _PATH_LIBB; 1136 break; 1137 case 'q': 1138 /* compatibility option */ 1139 break; 1140 case 'v': 1141 fprintf(stderr, "%s (BSD bc) %s\n", __progname, BC_VER); 1142 exit(0); 1143 break; 1144 default: 1145 usage(); 1146 } 1147 } 1148 1149 argc -= optind; 1150 argv += optind; 1151 1152 interactive = isatty(STDIN_FILENO); 1153 for (i = 0; i < argc; i++) 1154 sargv[sargc++] = argv[i]; 1155 1156 if (do_fork) { 1157 if (pipe(p) == -1) 1158 err(1, "cannot create pipe"); 1159 dc = fork(); 1160 if (dc == -1) 1161 err(1, "cannot fork"); 1162 else if (dc != 0) { 1163 signal(SIGCHLD, sigchld); 1164 close(STDOUT_FILENO); 1165 dup(p[1]); 1166 close(p[0]); 1167 close(p[1]); 1168 } else { 1169 close(STDIN_FILENO); 1170 dup(p[0]); 1171 close(p[0]); 1172 close(p[1]); 1173 execl(_PATH_DC, "dc", "-x", (char *)NULL); 1174 err(1, "cannot find dc"); 1175 } 1176 } 1177 yywrap(); 1178 return (yyparse()); 1179} 1180