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