bc.y revision 343491
1202719Sgabor%{ 2264573Sdelphij/* $OpenBSD: bc.y,v 1.44 2013/11/20 21:33:54 deraadt Exp $ */ 3202719Sgabor 4202719Sgabor/* 5202719Sgabor * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net> 6202719Sgabor * 7202719Sgabor * Permission to use, copy, modify, and distribute this software for any 8202719Sgabor * purpose with or without fee is hereby granted, provided that the above 9202719Sgabor * copyright notice and this permission notice appear in all copies. 10202719Sgabor * 11202719Sgabor * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12202719Sgabor * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13202719Sgabor * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14202719Sgabor * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15202719Sgabor * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16202719Sgabor * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17202719Sgabor * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18202719Sgabor */ 19202719Sgabor 20202719Sgabor/* 21202719Sgabor * This implementation of bc(1) uses concepts from the original 4.4 22202719Sgabor * BSD bc(1). The code itself is a complete rewrite, based on the 23202719Sgabor * Posix defined bc(1) grammar. Other differences include type safe 24202719Sgabor * usage of pointers to build the tree of emitted code, typed yacc 25202719Sgabor * rule values, dynamic allocation of all data structures and a 26202719Sgabor * completely rewritten lexical analyzer using lex(1). 27202719Sgabor * 28202719Sgabor * Some effort has been made to make sure that the generated code is 29202719Sgabor * the same as the code generated by the older version, to provide 30202719Sgabor * easy regression testing. 31202719Sgabor */ 32202719Sgabor 33202719Sgabor#include <sys/cdefs.h> 34202719Sgabor__FBSDID("$FreeBSD: stable/11/usr.bin/bc/bc.y 343491 2019-01-27 13:58:06Z nyan $"); 35202719Sgabor 36202719Sgabor#include <sys/types.h> 37202719Sgabor#include <sys/wait.h> 38202719Sgabor 39202719Sgabor#include <ctype.h> 40202719Sgabor#include <err.h> 41202719Sgabor#include <errno.h> 42202719Sgabor#include <getopt.h> 43203498Sdelphij#include <histedit.h> 44202719Sgabor#include <limits.h> 45202719Sgabor#include <search.h> 46202719Sgabor#include <signal.h> 47202719Sgabor#include <stdarg.h> 48202719Sgabor#include <string.h> 49202719Sgabor#include <unistd.h> 50232994Skevlo#include <stdlib.h> 51202719Sgabor 52202719Sgabor#include "extern.h" 53202719Sgabor#include "pathnames.h" 54202719Sgabor 55264573Sdelphij#define BC_VER "1.1-FreeBSD" 56202719Sgabor#define END_NODE ((ssize_t) -1) 57202719Sgabor#define CONST_STRING ((ssize_t) -2) 58202719Sgabor#define ALLOC_STRING ((ssize_t) -3) 59202719Sgabor 60202719Sgaborextern char *yytext; 61202719Sgaborextern FILE *yyin; 62202719Sgabor 63202719Sgaborstruct tree { 64202719Sgabor union { 65202719Sgabor char *astr; 66202719Sgabor const char *cstr; 67202719Sgabor } u; 68203443Sgabor ssize_t index; 69202719Sgabor}; 70202719Sgabor 71202719Sgaborint yywrap(void); 72202719Sgabor 73202719Sgaborint fileindex; 74202719Sgaborint sargc; 75202719Sgaborconst char **sargv; 76202719Sgaborconst char *filename; 77202719Sgaborchar *cmdexpr; 78202719Sgabor 79202719Sgaborstatic void grow(void); 80202719Sgaborstatic ssize_t cs(const char *); 81202719Sgaborstatic ssize_t as(const char *); 82202719Sgaborstatic ssize_t node(ssize_t, ...); 83291234Spfgstatic void emit(ssize_t, int); 84202719Sgaborstatic void emit_macro(int, ssize_t); 85202719Sgaborstatic void free_tree(void); 86202719Sgaborstatic ssize_t numnode(int); 87202719Sgaborstatic ssize_t lookup(char *, size_t, char); 88202719Sgaborstatic ssize_t letter_node(char *); 89202719Sgaborstatic ssize_t array_node(char *); 90202719Sgaborstatic ssize_t function_node(char *); 91202719Sgabor 92202719Sgaborstatic void add_par(ssize_t); 93202719Sgaborstatic void add_local(ssize_t); 94202719Sgaborstatic void warning(const char *); 95202719Sgaborstatic void init(void); 96202719Sgaborstatic void usage(void); 97202719Sgaborstatic char *escape(const char *); 98202719Sgabor 99202719Sgaborstatic ssize_t instr_sz = 0; 100202719Sgaborstatic struct tree *instructions = NULL; 101202719Sgaborstatic ssize_t current = 0; 102202719Sgaborstatic int macro_char = '0'; 103202719Sgaborstatic int reset_macro_char = '0'; 104202719Sgaborstatic int nesting = 0; 105202719Sgaborstatic int breakstack[16]; 106202719Sgaborstatic int breaksp = 0; 107202719Sgaborstatic ssize_t prologue; 108202719Sgaborstatic ssize_t epilogue; 109202719Sgaborstatic bool st_has_continue; 110202719Sgaborstatic char str_table[UCHAR_MAX][2]; 111202719Sgaborstatic bool do_fork = true; 112202719Sgaborstatic u_short var_count; 113202719Sgaborstatic pid_t dc; 114202719Sgabor 115202719Sgaborstatic void sigchld(int); 116202719Sgabor 117202719Sgaborextern char *__progname; 118202719Sgabor 119202719Sgabor#define BREAKSTACK_SZ (sizeof(breakstack)/sizeof(breakstack[0])) 120202719Sgabor 121202719Sgabor/* These values are 4.4BSD bc compatible */ 122202719Sgabor#define FUNC_CHAR 0x01 123202719Sgabor#define ARRAY_CHAR 0xa1 124202719Sgabor 125202719Sgabor/* Skip '\0', [, \ and ] */ 126202719Sgabor#define ENCODE(c) ((c) < '[' ? (c) : (c) + 3); 127202719Sgabor#define VAR_BASE (256-4) 128202719Sgabor#define MAX_VARIABLES (VAR_BASE * VAR_BASE) 129202719Sgabor 130202719Sgaborconst struct option long_options[] = 131202719Sgabor{ 132202719Sgabor {"expression", required_argument, NULL, 'e'}, 133202719Sgabor {"help", no_argument, NULL, 'h'}, 134202719Sgabor {"mathlib", no_argument, NULL, 'l'}, 135202719Sgabor /* compatibility option */ 136202719Sgabor {"quiet", no_argument, NULL, 'q'}, 137202719Sgabor {"version", no_argument, NULL, 'v'}, 138202719Sgabor {NULL, no_argument, NULL, 0} 139202719Sgabor}; 140202719Sgabor 141202719Sgabor%} 142202719Sgabor 143202719Sgabor%start program 144202719Sgabor 145202719Sgabor%union { 146202719Sgabor struct lvalue lvalue; 147202719Sgabor const char *str; 148202719Sgabor char *astr; 149203443Sgabor ssize_t node; 150202719Sgabor} 151202719Sgabor 152202719Sgabor%token COMMA SEMICOLON LPAR RPAR LBRACE RBRACE LBRACKET RBRACKET DOT 153202719Sgabor%token NEWLINE 154202719Sgabor%token <astr> LETTER 155202719Sgabor%token <str> NUMBER STRING 156202719Sgabor%token DEFINE BREAK QUIT LENGTH 157202719Sgabor%token RETURN FOR IF WHILE SQRT 158202719Sgabor%token SCALE IBASE OBASE AUTO 159202719Sgabor%token CONTINUE ELSE PRINT 160202719Sgabor 161202719Sgabor%left BOOL_OR 162202719Sgabor%left BOOL_AND 163202719Sgabor%nonassoc BOOL_NOT 164202719Sgabor%nonassoc EQUALS LESS_EQ GREATER_EQ UNEQUALS LESS GREATER 165202719Sgabor%right <str> ASSIGN_OP 166202719Sgabor%left PLUS MINUS 167202719Sgabor%left MULTIPLY DIVIDE REMAINDER 168202719Sgabor%right EXPONENT 169202719Sgabor%nonassoc UMINUS 170202719Sgabor%nonassoc INCR DECR 171202719Sgabor 172202719Sgabor%type <lvalue> named_expression 173202719Sgabor%type <node> argument_list 174202719Sgabor%type <node> alloc_macro 175202719Sgabor%type <node> expression 176202719Sgabor%type <node> function 177202719Sgabor%type <node> function_header 178202719Sgabor%type <node> input_item 179202719Sgabor%type <node> opt_argument_list 180202719Sgabor%type <node> opt_expression 181202719Sgabor%type <node> opt_relational_expression 182202719Sgabor%type <node> opt_statement 183202719Sgabor%type <node> print_expression 184202719Sgabor%type <node> print_expression_list 185202719Sgabor%type <node> relational_expression 186202719Sgabor%type <node> return_expression 187202719Sgabor%type <node> semicolon_list 188202719Sgabor%type <node> statement 189202719Sgabor%type <node> statement_list 190202719Sgabor 191202719Sgabor%% 192202719Sgabor 193202719Sgaborprogram : /* empty */ 194202719Sgabor | program input_item 195202719Sgabor ; 196202719Sgabor 197202719Sgaborinput_item : semicolon_list NEWLINE 198202719Sgabor { 199291234Spfg emit($1, 0); 200202719Sgabor macro_char = reset_macro_char; 201202719Sgabor putchar('\n'); 202202719Sgabor free_tree(); 203202719Sgabor st_has_continue = false; 204202719Sgabor } 205202719Sgabor | function 206202719Sgabor { 207202719Sgabor putchar('\n'); 208202719Sgabor free_tree(); 209202719Sgabor st_has_continue = false; 210202719Sgabor } 211202719Sgabor | error NEWLINE 212202719Sgabor { 213202719Sgabor yyerrok; 214202719Sgabor } 215202719Sgabor | error QUIT 216202719Sgabor { 217202719Sgabor yyerrok; 218202719Sgabor } 219202719Sgabor ; 220202719Sgabor 221202719Sgaborsemicolon_list : /* empty */ 222202719Sgabor { 223202719Sgabor $$ = cs(""); 224202719Sgabor } 225202719Sgabor | statement 226202719Sgabor | semicolon_list SEMICOLON statement 227202719Sgabor { 228202719Sgabor $$ = node($1, $3, END_NODE); 229202719Sgabor } 230202719Sgabor | semicolon_list SEMICOLON 231202719Sgabor ; 232202719Sgabor 233202719Sgaborstatement_list : /* empty */ 234202719Sgabor { 235202719Sgabor $$ = cs(""); 236202719Sgabor } 237202719Sgabor | statement 238202719Sgabor | statement_list NEWLINE 239202719Sgabor | statement_list NEWLINE statement 240202719Sgabor { 241202719Sgabor $$ = node($1, $3, END_NODE); 242202719Sgabor } 243202719Sgabor | statement_list SEMICOLON 244202719Sgabor | statement_list SEMICOLON statement 245202719Sgabor { 246202719Sgabor $$ = node($1, $3, END_NODE); 247202719Sgabor } 248202719Sgabor ; 249202719Sgabor 250202719Sgabor 251202719Sgaboropt_statement : /* empty */ 252202719Sgabor { 253202719Sgabor $$ = cs(""); 254202719Sgabor } 255202719Sgabor | statement 256202719Sgabor ; 257202719Sgabor 258202719Sgaborstatement : expression 259202719Sgabor { 260202719Sgabor $$ = node($1, cs("ps."), END_NODE); 261202719Sgabor } 262202719Sgabor | named_expression ASSIGN_OP expression 263202719Sgabor { 264202719Sgabor if ($2[0] == '\0') 265202719Sgabor $$ = node($3, cs($2), $1.store, 266202719Sgabor END_NODE); 267202719Sgabor else 268202719Sgabor $$ = node($1.load, $3, cs($2), $1.store, 269202719Sgabor END_NODE); 270202719Sgabor } 271202719Sgabor | STRING 272202719Sgabor { 273202719Sgabor $$ = node(cs("["), as($1), 274202719Sgabor cs("]P"), END_NODE); 275202719Sgabor } 276202719Sgabor | BREAK 277202719Sgabor { 278202719Sgabor if (breaksp == 0) { 279202719Sgabor warning("break not in for or while"); 280202719Sgabor YYERROR; 281202719Sgabor } else { 282202719Sgabor $$ = node( 283202719Sgabor numnode(nesting - 284202719Sgabor breakstack[breaksp-1]), 285202719Sgabor cs("Q"), END_NODE); 286202719Sgabor } 287202719Sgabor } 288202719Sgabor | CONTINUE 289202719Sgabor { 290202719Sgabor if (breaksp == 0) { 291202719Sgabor warning("continue not in for or while"); 292202719Sgabor YYERROR; 293202719Sgabor } else { 294202719Sgabor st_has_continue = true; 295202719Sgabor $$ = node(numnode(nesting - 296202719Sgabor breakstack[breaksp-1] - 1), 297202719Sgabor cs("J"), END_NODE); 298202719Sgabor } 299202719Sgabor } 300202719Sgabor | QUIT 301202719Sgabor { 302203443Sgabor sigset_t mask; 303202719Sgabor 304202719Sgabor putchar('q'); 305202719Sgabor fflush(stdout); 306202719Sgabor if (dc) { 307202719Sgabor sigprocmask(SIG_BLOCK, NULL, &mask); 308202719Sgabor sigsuspend(&mask); 309202719Sgabor } else 310202719Sgabor exit(0); 311202719Sgabor } 312202719Sgabor | RETURN return_expression 313202719Sgabor { 314202719Sgabor if (nesting == 0) { 315202719Sgabor warning("return must be in a function"); 316202719Sgabor YYERROR; 317202719Sgabor } 318202719Sgabor $$ = $2; 319202719Sgabor } 320202719Sgabor | FOR LPAR alloc_macro opt_expression SEMICOLON 321202719Sgabor opt_relational_expression SEMICOLON 322202719Sgabor opt_expression RPAR opt_statement pop_nesting 323202719Sgabor { 324203443Sgabor ssize_t n; 325202719Sgabor 326202719Sgabor if (st_has_continue) 327202719Sgabor n = node($10, cs("M"), $8, cs("s."), 328202719Sgabor $6, $3, END_NODE); 329202719Sgabor else 330202719Sgabor n = node($10, $8, cs("s."), $6, $3, 331202719Sgabor END_NODE); 332202719Sgabor 333202719Sgabor emit_macro($3, n); 334202719Sgabor $$ = node($4, cs("s."), $6, $3, cs(" "), 335202719Sgabor END_NODE); 336202719Sgabor } 337202719Sgabor | IF LPAR alloc_macro pop_nesting relational_expression RPAR 338202719Sgabor opt_statement 339202719Sgabor { 340202719Sgabor emit_macro($3, $7); 341202719Sgabor $$ = node($5, $3, cs(" "), END_NODE); 342202719Sgabor } 343202719Sgabor | IF LPAR alloc_macro pop_nesting relational_expression RPAR 344202719Sgabor opt_statement ELSE alloc_macro pop_nesting opt_statement 345202719Sgabor { 346202719Sgabor emit_macro($3, $7); 347202719Sgabor emit_macro($9, $11); 348202719Sgabor $$ = node($5, $3, cs("e"), $9, cs(" "), 349202719Sgabor END_NODE); 350202719Sgabor } 351202719Sgabor | WHILE LPAR alloc_macro relational_expression RPAR 352202719Sgabor opt_statement pop_nesting 353202719Sgabor { 354203443Sgabor ssize_t n; 355202719Sgabor 356202719Sgabor if (st_has_continue) 357202719Sgabor n = node($6, cs("M"), $4, $3, END_NODE); 358202719Sgabor else 359202719Sgabor n = node($6, $4, $3, END_NODE); 360202719Sgabor emit_macro($3, n); 361202719Sgabor $$ = node($4, $3, cs(" "), END_NODE); 362202719Sgabor } 363202719Sgabor | LBRACE statement_list RBRACE 364202719Sgabor { 365202719Sgabor $$ = $2; 366202719Sgabor } 367202719Sgabor | PRINT print_expression_list 368202719Sgabor { 369202719Sgabor $$ = $2; 370202719Sgabor } 371202719Sgabor ; 372202719Sgabor 373202719Sgaboralloc_macro : /* empty */ 374202719Sgabor { 375202719Sgabor $$ = cs(str_table[macro_char]); 376202719Sgabor macro_char++; 377202719Sgabor /* Do not use [, \ and ] */ 378202719Sgabor if (macro_char == '[') 379202719Sgabor macro_char += 3; 380202719Sgabor /* skip letters */ 381202719Sgabor else if (macro_char == 'a') 382202719Sgabor macro_char = '{'; 383202719Sgabor else if (macro_char == ARRAY_CHAR) 384202719Sgabor macro_char += 26; 385202719Sgabor else if (macro_char == 255) 386202719Sgabor fatal("program too big"); 387202719Sgabor if (breaksp == BREAKSTACK_SZ) 388202719Sgabor fatal("nesting too deep"); 389202719Sgabor breakstack[breaksp++] = nesting++; 390202719Sgabor } 391202719Sgabor ; 392202719Sgabor 393202719Sgaborpop_nesting : /* empty */ 394202719Sgabor { 395202719Sgabor breaksp--; 396202719Sgabor } 397202719Sgabor ; 398202719Sgabor 399202719Sgaborfunction : function_header opt_parameter_list RPAR opt_newline 400202719Sgabor LBRACE NEWLINE opt_auto_define_list 401202719Sgabor statement_list RBRACE 402202719Sgabor { 403202719Sgabor int n = node(prologue, $8, epilogue, 404202719Sgabor cs("0"), numnode(nesting), 405202719Sgabor cs("Q"), END_NODE); 406202719Sgabor emit_macro($1, n); 407202719Sgabor reset_macro_char = macro_char; 408202719Sgabor nesting = 0; 409202719Sgabor breaksp = 0; 410202719Sgabor } 411202719Sgabor ; 412202719Sgabor 413202719Sgaborfunction_header : DEFINE LETTER LPAR 414202719Sgabor { 415202719Sgabor $$ = function_node($2); 416202719Sgabor free($2); 417202719Sgabor prologue = cs(""); 418202719Sgabor epilogue = cs(""); 419202719Sgabor nesting = 1; 420202719Sgabor breaksp = 0; 421202719Sgabor breakstack[breaksp] = 0; 422202719Sgabor } 423202719Sgabor ; 424202719Sgabor 425202719Sgaboropt_newline : /* empty */ 426202719Sgabor | NEWLINE 427202719Sgabor ; 428202719Sgabor 429202719Sgaboropt_parameter_list 430202719Sgabor : /* empty */ 431202719Sgabor | parameter_list 432202719Sgabor ; 433202719Sgabor 434202719Sgabor 435202719Sgaborparameter_list : LETTER 436202719Sgabor { 437202719Sgabor add_par(letter_node($1)); 438202719Sgabor free($1); 439202719Sgabor } 440202719Sgabor | LETTER LBRACKET RBRACKET 441202719Sgabor { 442202719Sgabor add_par(array_node($1)); 443202719Sgabor free($1); 444202719Sgabor } 445202719Sgabor | parameter_list COMMA LETTER 446202719Sgabor { 447202719Sgabor add_par(letter_node($3)); 448202719Sgabor free($3); 449202719Sgabor } 450202719Sgabor | parameter_list COMMA LETTER LBRACKET RBRACKET 451202719Sgabor { 452202719Sgabor add_par(array_node($3)); 453202719Sgabor free($3); 454202719Sgabor } 455202719Sgabor ; 456202719Sgabor 457202719Sgabor 458202719Sgabor 459202719Sgaboropt_auto_define_list 460202719Sgabor : /* empty */ 461202719Sgabor | AUTO define_list NEWLINE 462202719Sgabor | AUTO define_list SEMICOLON 463202719Sgabor ; 464202719Sgabor 465202719Sgabor 466202719Sgabordefine_list : LETTER 467202719Sgabor { 468202719Sgabor add_local(letter_node($1)); 469202719Sgabor free($1); 470202719Sgabor } 471202719Sgabor | LETTER LBRACKET RBRACKET 472202719Sgabor { 473202719Sgabor add_local(array_node($1)); 474202719Sgabor free($1); 475202719Sgabor } 476202719Sgabor | define_list COMMA LETTER 477202719Sgabor { 478202719Sgabor add_local(letter_node($3)); 479202719Sgabor free($3); 480202719Sgabor } 481202719Sgabor | define_list COMMA LETTER LBRACKET RBRACKET 482202719Sgabor { 483202719Sgabor add_local(array_node($3)); 484202719Sgabor free($3); 485202719Sgabor } 486202719Sgabor ; 487202719Sgabor 488202719Sgabor 489202719Sgaboropt_argument_list 490202719Sgabor : /* empty */ 491202719Sgabor { 492202719Sgabor $$ = cs(""); 493202719Sgabor } 494202719Sgabor | argument_list 495202719Sgabor ; 496202719Sgabor 497202719Sgabor 498202719Sgaborargument_list : expression 499202719Sgabor | argument_list COMMA expression 500202719Sgabor { 501202719Sgabor $$ = node($1, $3, END_NODE); 502202719Sgabor } 503202719Sgabor | argument_list COMMA LETTER LBRACKET RBRACKET 504202719Sgabor { 505202719Sgabor $$ = node($1, cs("l"), array_node($3), 506202719Sgabor END_NODE); 507202719Sgabor free($3); 508202719Sgabor } 509202719Sgabor ; 510202719Sgabor 511202719Sgaboropt_relational_expression 512202719Sgabor : /* empty */ 513202719Sgabor { 514202719Sgabor $$ = cs(" 0 0="); 515202719Sgabor } 516202719Sgabor | relational_expression 517202719Sgabor ; 518202719Sgabor 519202719Sgaborrelational_expression 520202719Sgabor : expression EQUALS expression 521202719Sgabor { 522202719Sgabor $$ = node($1, $3, cs("="), END_NODE); 523202719Sgabor } 524202719Sgabor | expression UNEQUALS expression 525202719Sgabor { 526202719Sgabor $$ = node($1, $3, cs("!="), END_NODE); 527202719Sgabor } 528202719Sgabor | expression LESS expression 529202719Sgabor { 530202719Sgabor $$ = node($1, $3, cs(">"), END_NODE); 531202719Sgabor } 532202719Sgabor | expression LESS_EQ expression 533202719Sgabor { 534202719Sgabor $$ = node($1, $3, cs("!<"), END_NODE); 535202719Sgabor } 536202719Sgabor | expression GREATER expression 537202719Sgabor { 538202719Sgabor $$ = node($1, $3, cs("<"), END_NODE); 539202719Sgabor } 540202719Sgabor | expression GREATER_EQ expression 541202719Sgabor { 542202719Sgabor $$ = node($1, $3, cs("!>"), END_NODE); 543202719Sgabor } 544202719Sgabor | expression 545202719Sgabor { 546202719Sgabor $$ = node($1, cs(" 0!="), END_NODE); 547202719Sgabor } 548202719Sgabor ; 549202719Sgabor 550202719Sgabor 551202719Sgaborreturn_expression 552202719Sgabor : /* empty */ 553202719Sgabor { 554202719Sgabor $$ = node(cs("0"), epilogue, 555202719Sgabor numnode(nesting), cs("Q"), END_NODE); 556202719Sgabor } 557202719Sgabor | expression 558202719Sgabor { 559202719Sgabor $$ = node($1, epilogue, 560202719Sgabor numnode(nesting), cs("Q"), END_NODE); 561202719Sgabor } 562202719Sgabor | LPAR RPAR 563202719Sgabor { 564202719Sgabor $$ = node(cs("0"), epilogue, 565202719Sgabor numnode(nesting), cs("Q"), END_NODE); 566202719Sgabor } 567202719Sgabor ; 568202719Sgabor 569202719Sgabor 570202719Sgaboropt_expression : /* empty */ 571202719Sgabor { 572202719Sgabor $$ = cs(" 0"); 573202719Sgabor } 574202719Sgabor | expression 575202719Sgabor ; 576202719Sgabor 577202719Sgaborexpression : named_expression 578202719Sgabor { 579202719Sgabor $$ = node($1.load, END_NODE); 580202719Sgabor } 581202719Sgabor | DOT { 582202719Sgabor $$ = node(cs("l."), END_NODE); 583202719Sgabor } 584202719Sgabor | NUMBER 585202719Sgabor { 586202719Sgabor $$ = node(cs(" "), as($1), END_NODE); 587202719Sgabor } 588202719Sgabor | LPAR expression RPAR 589202719Sgabor { 590202719Sgabor $$ = $2; 591202719Sgabor } 592202719Sgabor | LETTER LPAR opt_argument_list RPAR 593202719Sgabor { 594202719Sgabor $$ = node($3, cs("l"), 595202719Sgabor function_node($1), cs("x"), 596202719Sgabor END_NODE); 597202719Sgabor free($1); 598202719Sgabor } 599202719Sgabor | MINUS expression %prec UMINUS 600202719Sgabor { 601202719Sgabor $$ = node(cs(" 0"), $2, cs("-"), 602202719Sgabor END_NODE); 603202719Sgabor } 604202719Sgabor | expression PLUS expression 605202719Sgabor { 606202719Sgabor $$ = node($1, $3, cs("+"), END_NODE); 607202719Sgabor } 608202719Sgabor | expression MINUS expression 609202719Sgabor { 610202719Sgabor $$ = node($1, $3, cs("-"), END_NODE); 611202719Sgabor } 612202719Sgabor | expression MULTIPLY expression 613202719Sgabor { 614202719Sgabor $$ = node($1, $3, cs("*"), END_NODE); 615202719Sgabor } 616202719Sgabor | expression DIVIDE expression 617202719Sgabor { 618202719Sgabor $$ = node($1, $3, cs("/"), END_NODE); 619202719Sgabor } 620202719Sgabor | expression REMAINDER expression 621202719Sgabor { 622202719Sgabor $$ = node($1, $3, cs("%"), END_NODE); 623202719Sgabor } 624202719Sgabor | expression EXPONENT expression 625202719Sgabor { 626202719Sgabor $$ = node($1, $3, cs("^"), END_NODE); 627202719Sgabor } 628202719Sgabor | INCR named_expression 629202719Sgabor { 630202719Sgabor $$ = node($2.load, cs("1+d"), $2.store, 631202719Sgabor END_NODE); 632202719Sgabor } 633202719Sgabor | DECR named_expression 634202719Sgabor { 635202719Sgabor $$ = node($2.load, cs("1-d"), 636202719Sgabor $2.store, END_NODE); 637202719Sgabor } 638202719Sgabor | named_expression INCR 639202719Sgabor { 640202719Sgabor $$ = node($1.load, cs("d1+"), 641202719Sgabor $1.store, END_NODE); 642202719Sgabor } 643202719Sgabor | named_expression DECR 644202719Sgabor { 645202719Sgabor $$ = node($1.load, cs("d1-"), 646202719Sgabor $1.store, END_NODE); 647202719Sgabor } 648202719Sgabor | named_expression ASSIGN_OP expression 649202719Sgabor { 650202719Sgabor if ($2[0] == '\0') 651202719Sgabor $$ = node($3, cs($2), cs("d"), $1.store, 652202719Sgabor END_NODE); 653202719Sgabor else 654202719Sgabor $$ = node($1.load, $3, cs($2), cs("d"), 655202719Sgabor $1.store, END_NODE); 656202719Sgabor } 657202719Sgabor | LENGTH LPAR expression RPAR 658202719Sgabor { 659202719Sgabor $$ = node($3, cs("Z"), END_NODE); 660202719Sgabor } 661202719Sgabor | SQRT LPAR expression RPAR 662202719Sgabor { 663202719Sgabor $$ = node($3, cs("v"), END_NODE); 664202719Sgabor } 665202719Sgabor | SCALE LPAR expression RPAR 666202719Sgabor { 667202719Sgabor $$ = node($3, cs("X"), END_NODE); 668202719Sgabor } 669202719Sgabor | BOOL_NOT expression 670202719Sgabor { 671202719Sgabor $$ = node($2, cs("N"), END_NODE); 672202719Sgabor } 673202719Sgabor | expression BOOL_AND alloc_macro pop_nesting expression 674202719Sgabor { 675202719Sgabor ssize_t n = node(cs("R"), $5, END_NODE); 676202719Sgabor emit_macro($3, n); 677202719Sgabor $$ = node($1, cs("d0!="), $3, END_NODE); 678202719Sgabor } 679202719Sgabor | expression BOOL_OR alloc_macro pop_nesting expression 680202719Sgabor { 681202719Sgabor ssize_t n = node(cs("R"), $5, END_NODE); 682202719Sgabor emit_macro($3, n); 683202719Sgabor $$ = node($1, cs("d0="), $3, END_NODE); 684202719Sgabor } 685202719Sgabor | expression EQUALS expression 686202719Sgabor { 687202719Sgabor $$ = node($1, $3, cs("G"), END_NODE); 688202719Sgabor } 689202719Sgabor | expression UNEQUALS expression 690202719Sgabor { 691202719Sgabor $$ = node($1, $3, cs("GN"), END_NODE); 692202719Sgabor } 693202719Sgabor | expression LESS expression 694202719Sgabor { 695202719Sgabor $$ = node($3, $1, cs("("), END_NODE); 696202719Sgabor } 697202719Sgabor | expression LESS_EQ expression 698202719Sgabor { 699202719Sgabor $$ = node($3, $1, cs("{"), END_NODE); 700202719Sgabor } 701202719Sgabor | expression GREATER expression 702202719Sgabor { 703202719Sgabor $$ = node($1, $3, cs("("), END_NODE); 704202719Sgabor } 705202719Sgabor | expression GREATER_EQ expression 706202719Sgabor { 707202719Sgabor $$ = node($1, $3, cs("{"), END_NODE); 708202719Sgabor } 709202719Sgabor ; 710202719Sgabor 711202719Sgabornamed_expression 712202719Sgabor : LETTER 713202719Sgabor { 714202719Sgabor $$.load = node(cs("l"), letter_node($1), 715202719Sgabor END_NODE); 716202719Sgabor $$.store = node(cs("s"), letter_node($1), 717202719Sgabor END_NODE); 718202719Sgabor free($1); 719202719Sgabor } 720202719Sgabor | LETTER LBRACKET expression RBRACKET 721202719Sgabor { 722202719Sgabor $$.load = node($3, cs(";"), 723202719Sgabor array_node($1), END_NODE); 724202719Sgabor $$.store = node($3, cs(":"), 725202719Sgabor array_node($1), END_NODE); 726202719Sgabor free($1); 727202719Sgabor } 728202719Sgabor | SCALE 729202719Sgabor { 730202719Sgabor $$.load = cs("K"); 731202719Sgabor $$.store = cs("k"); 732202719Sgabor } 733202719Sgabor | IBASE 734202719Sgabor { 735202719Sgabor $$.load = cs("I"); 736202719Sgabor $$.store = cs("i"); 737202719Sgabor } 738202719Sgabor | OBASE 739202719Sgabor { 740202719Sgabor $$.load = cs("O"); 741202719Sgabor $$.store = cs("o"); 742202719Sgabor } 743202719Sgabor ; 744202719Sgabor 745202719Sgaborprint_expression_list 746202719Sgabor : print_expression 747202719Sgabor | print_expression_list COMMA print_expression 748202719Sgabor { 749202719Sgabor $$ = node($1, $3, END_NODE); 750202719Sgabor } 751202719Sgabor 752202719Sgaborprint_expression 753202719Sgabor : expression 754202719Sgabor { 755202719Sgabor $$ = node($1, cs("ds.n"), END_NODE); 756202719Sgabor } 757202719Sgabor | STRING 758202719Sgabor { 759202719Sgabor char *p = escape($1); 760202719Sgabor $$ = node(cs("["), as(p), cs("]n"), END_NODE); 761202719Sgabor free(p); 762202719Sgabor } 763202719Sgabor%% 764202719Sgabor 765202719Sgabor 766202719Sgaborstatic void 767202719Sgaborgrow(void) 768202719Sgabor{ 769203443Sgabor struct tree *p; 770203443Sgabor size_t newsize; 771202719Sgabor 772202719Sgabor if (current == instr_sz) { 773202719Sgabor newsize = instr_sz * 2 + 1; 774202719Sgabor p = realloc(instructions, newsize * sizeof(*p)); 775202719Sgabor if (p == NULL) { 776202719Sgabor free(instructions); 777202719Sgabor err(1, NULL); 778202719Sgabor } 779202719Sgabor instructions = p; 780202719Sgabor instr_sz = newsize; 781202719Sgabor } 782202719Sgabor} 783202719Sgabor 784202719Sgaborstatic ssize_t 785202719Sgaborcs(const char *str) 786202719Sgabor{ 787203443Sgabor 788202719Sgabor grow(); 789202719Sgabor instructions[current].index = CONST_STRING; 790202719Sgabor instructions[current].u.cstr = str; 791202719Sgabor return (current++); 792202719Sgabor} 793202719Sgabor 794202719Sgaborstatic ssize_t 795202719Sgaboras(const char *str) 796202719Sgabor{ 797203443Sgabor 798202719Sgabor grow(); 799202719Sgabor instructions[current].index = ALLOC_STRING; 800202719Sgabor instructions[current].u.astr = strdup(str); 801202719Sgabor if (instructions[current].u.astr == NULL) 802202719Sgabor err(1, NULL); 803202719Sgabor return (current++); 804202719Sgabor} 805202719Sgabor 806202719Sgaborstatic ssize_t 807202719Sgabornode(ssize_t arg, ...) 808202719Sgabor{ 809203443Sgabor va_list ap; 810203443Sgabor ssize_t ret; 811202719Sgabor 812202719Sgabor va_start(ap, arg); 813202719Sgabor 814202719Sgabor ret = current; 815202719Sgabor grow(); 816202719Sgabor instructions[current++].index = arg; 817202719Sgabor 818202719Sgabor do { 819202719Sgabor arg = va_arg(ap, ssize_t); 820202719Sgabor grow(); 821202719Sgabor instructions[current++].index = arg; 822202719Sgabor } while (arg != END_NODE); 823202719Sgabor 824202719Sgabor va_end(ap); 825202719Sgabor return (ret); 826202719Sgabor} 827202719Sgabor 828202719Sgaborstatic void 829291234Spfgemit(ssize_t i, int level) 830202719Sgabor{ 831203443Sgabor 832291234Spfg if (level > 1000) 833291234Spfg errx(1, "internal error: tree level > 1000"); 834291234Spfg if (instructions[i].index >= 0) { 835291234Spfg while (instructions[i].index != END_NODE && 836291234Spfg instructions[i].index != i) { 837291234Spfg emit(instructions[i].index, level + 1); 838291234Spfg i++; 839291234Spfg } 840291234Spfg } else if (instructions[i].index != END_NODE) 841202719Sgabor fputs(instructions[i].u.cstr, stdout); 842202719Sgabor} 843202719Sgabor 844202719Sgaborstatic void 845202719Sgaboremit_macro(int nodeidx, ssize_t code) 846202719Sgabor{ 847203443Sgabor 848202719Sgabor putchar('['); 849291234Spfg emit(code, 0); 850202719Sgabor printf("]s%s\n", instructions[nodeidx].u.cstr); 851202719Sgabor nesting--; 852202719Sgabor} 853202719Sgabor 854202719Sgaborstatic void 855202719Sgaborfree_tree(void) 856202719Sgabor{ 857203443Sgabor ssize_t i; 858202719Sgabor 859202719Sgabor for (i = 0; i < current; i++) 860202719Sgabor if (instructions[i].index == ALLOC_STRING) 861202719Sgabor free(instructions[i].u.astr); 862202719Sgabor current = 0; 863202719Sgabor} 864202719Sgabor 865202719Sgaborstatic ssize_t 866202719Sgabornumnode(int num) 867202719Sgabor{ 868203443Sgabor const char *p; 869202719Sgabor 870202719Sgabor if (num < 10) 871202719Sgabor p = str_table['0' + num]; 872202719Sgabor else if (num < 16) 873202719Sgabor p = str_table['A' - 10 + num]; 874202719Sgabor else 875202719Sgabor errx(1, "internal error: break num > 15"); 876202719Sgabor return (node(cs(" "), cs(p), END_NODE)); 877202719Sgabor} 878202719Sgabor 879202719Sgabor 880202719Sgaborstatic ssize_t 881202719Sgaborlookup(char * str, size_t len, char type) 882202719Sgabor{ 883203443Sgabor ENTRY entry, *found; 884203443Sgabor u_char *p; 885203443Sgabor u_short num; 886202719Sgabor 887202719Sgabor /* The scanner allocated an extra byte already */ 888202719Sgabor if (str[len-1] != type) { 889202719Sgabor str[len] = type; 890202719Sgabor str[len+1] = '\0'; 891202719Sgabor } 892202719Sgabor entry.key = str; 893202719Sgabor found = hsearch(entry, FIND); 894202719Sgabor if (found == NULL) { 895202719Sgabor if (var_count == MAX_VARIABLES) 896202719Sgabor errx(1, "too many variables"); 897202719Sgabor p = malloc(4); 898202719Sgabor if (p == NULL) 899202719Sgabor err(1, NULL); 900202719Sgabor num = var_count++; 901202719Sgabor p[0] = 255; 902202719Sgabor p[1] = ENCODE(num / VAR_BASE + 1); 903202719Sgabor p[2] = ENCODE(num % VAR_BASE + 1); 904202719Sgabor p[3] = '\0'; 905202719Sgabor 906202719Sgabor entry.data = (char *)p; 907202719Sgabor entry.key = strdup(str); 908202719Sgabor if (entry.key == NULL) 909202719Sgabor err(1, NULL); 910202719Sgabor found = hsearch(entry, ENTER); 911202719Sgabor if (found == NULL) 912202719Sgabor err(1, NULL); 913202719Sgabor } 914202719Sgabor return (cs(found->data)); 915202719Sgabor} 916202719Sgabor 917202719Sgaborstatic ssize_t 918202719Sgaborletter_node(char *str) 919202719Sgabor{ 920203443Sgabor size_t len; 921202719Sgabor 922202719Sgabor len = strlen(str); 923202719Sgabor if (len == 1 && str[0] != '_') 924202719Sgabor return (cs(str_table[(int)str[0]])); 925202719Sgabor else 926202719Sgabor return (lookup(str, len, 'L')); 927202719Sgabor} 928202719Sgabor 929202719Sgaborstatic ssize_t 930202719Sgaborarray_node(char *str) 931202719Sgabor{ 932203443Sgabor size_t len; 933202719Sgabor 934202719Sgabor len = strlen(str); 935202719Sgabor if (len == 1 && str[0] != '_') 936202719Sgabor return (cs(str_table[(int)str[0] - 'a' + ARRAY_CHAR])); 937202719Sgabor else 938202719Sgabor return (lookup(str, len, 'A')); 939202719Sgabor} 940202719Sgabor 941202719Sgaborstatic ssize_t 942202719Sgaborfunction_node(char *str) 943202719Sgabor{ 944203443Sgabor size_t len; 945202719Sgabor 946202719Sgabor len = strlen(str); 947202719Sgabor if (len == 1 && str[0] != '_') 948202719Sgabor return (cs(str_table[(int)str[0] - 'a' + FUNC_CHAR])); 949202719Sgabor else 950202719Sgabor return (lookup(str, len, 'F')); 951202719Sgabor} 952202719Sgabor 953202719Sgaborstatic void 954202719Sgaboradd_par(ssize_t n) 955202719Sgabor{ 956203443Sgabor 957202719Sgabor prologue = node(cs("S"), n, prologue, END_NODE); 958202719Sgabor epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE); 959202719Sgabor} 960202719Sgabor 961202719Sgaborstatic void 962202719Sgaboradd_local(ssize_t n) 963202719Sgabor{ 964203443Sgabor 965202719Sgabor prologue = node(cs("0S"), n, prologue, END_NODE); 966202719Sgabor epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE); 967202719Sgabor} 968202719Sgabor 969202719Sgaborvoid 970202719Sgaboryyerror(const char *s) 971202719Sgabor{ 972203443Sgabor char *p, *str; 973203443Sgabor int n; 974202719Sgabor 975202719Sgabor if (yyin != NULL && feof(yyin)) 976202719Sgabor n = asprintf(&str, "%s: %s:%d: %s: unexpected EOF", 977202719Sgabor __progname, filename, lineno, s); 978264573Sdelphij else if (yytext[0] == '\n') 979202719Sgabor n = asprintf(&str, 980264573Sdelphij "%s: %s:%d: %s: newline unexpected", 981264573Sdelphij __progname, filename, lineno, s); 982264573Sdelphij else if (isspace((unsigned char)yytext[0]) || 983264573Sdelphij !isprint((unsigned char)yytext[0])) 984264573Sdelphij n = asprintf(&str, 985202719Sgabor "%s: %s:%d: %s: ascii char 0x%02x unexpected", 986291234Spfg __progname, filename, lineno, s, yytext[0] & 0xff); 987202719Sgabor else 988202719Sgabor n = asprintf(&str, "%s: %s:%d: %s: %s unexpected", 989202719Sgabor __progname, filename, lineno, s, yytext); 990202719Sgabor if (n == -1) 991202719Sgabor err(1, NULL); 992202719Sgabor 993202719Sgabor fputs("c[", stdout); 994202719Sgabor for (p = str; *p != '\0'; p++) { 995202719Sgabor if (*p == '[' || *p == ']' || *p =='\\') 996202719Sgabor putchar('\\'); 997202719Sgabor putchar(*p); 998202719Sgabor } 999343491Snyan fputs("]ec\n", stdout); 1000202719Sgabor free(str); 1001202719Sgabor} 1002202719Sgabor 1003202719Sgaborvoid 1004202719Sgaborfatal(const char *s) 1005202719Sgabor{ 1006203443Sgabor 1007202719Sgabor errx(1, "%s:%d: %s", filename, lineno, s); 1008202719Sgabor} 1009202719Sgabor 1010202719Sgaborstatic void 1011202719Sgaborwarning(const char *s) 1012202719Sgabor{ 1013203443Sgabor 1014202719Sgabor warnx("%s:%d: %s", filename, lineno, s); 1015202719Sgabor} 1016202719Sgabor 1017202719Sgaborstatic void 1018202719Sgaborinit(void) 1019202719Sgabor{ 1020203443Sgabor unsigned int i; 1021202719Sgabor 1022202719Sgabor for (i = 0; i < UCHAR_MAX; i++) { 1023202719Sgabor str_table[i][0] = i; 1024202719Sgabor str_table[i][1] = '\0'; 1025202719Sgabor } 1026202719Sgabor if (hcreate(1 << 16) == 0) 1027202719Sgabor err(1, NULL); 1028202719Sgabor} 1029202719Sgabor 1030202719Sgabor 1031202719Sgaborstatic void 1032202719Sgaborusage(void) 1033202719Sgabor{ 1034203443Sgabor 1035259058Sdelphij fprintf(stderr, "usage: %s [-chlv] [-e expression] [file ...]\n", 1036202719Sgabor __progname); 1037202719Sgabor exit(1); 1038202719Sgabor} 1039202719Sgabor 1040202719Sgaborstatic char * 1041202719Sgaborescape(const char *str) 1042202719Sgabor{ 1043203443Sgabor char *p, *ret; 1044202719Sgabor 1045202719Sgabor ret = malloc(strlen(str) + 1); 1046202719Sgabor if (ret == NULL) 1047202719Sgabor err(1, NULL); 1048202719Sgabor 1049202719Sgabor p = ret; 1050202719Sgabor while (*str != '\0') { 1051202719Sgabor /* 1052202719Sgabor * We get _escaped_ strings here. Single backslashes are 1053202719Sgabor * already converted to double backslashes 1054202719Sgabor */ 1055202719Sgabor if (*str == '\\') { 1056202719Sgabor if (*++str == '\\') { 1057202719Sgabor switch (*++str) { 1058202719Sgabor case 'a': 1059202719Sgabor *p++ = '\a'; 1060202719Sgabor break; 1061202719Sgabor case 'b': 1062202719Sgabor *p++ = '\b'; 1063202719Sgabor break; 1064202719Sgabor case 'f': 1065202719Sgabor *p++ = '\f'; 1066202719Sgabor break; 1067202719Sgabor case 'n': 1068202719Sgabor *p++ = '\n'; 1069202719Sgabor break; 1070202719Sgabor case 'q': 1071202719Sgabor *p++ = '"'; 1072202719Sgabor break; 1073202719Sgabor case 'r': 1074202719Sgabor *p++ = '\r'; 1075202719Sgabor break; 1076202719Sgabor case 't': 1077202719Sgabor *p++ = '\t'; 1078202719Sgabor break; 1079202719Sgabor case '\\': 1080202719Sgabor *p++ = '\\'; 1081202719Sgabor break; 1082202719Sgabor } 1083202719Sgabor str++; 1084202719Sgabor } else { 1085202719Sgabor *p++ = '\\'; 1086202719Sgabor *p++ = *str++; 1087202719Sgabor } 1088202719Sgabor } else 1089202719Sgabor *p++ = *str++; 1090202719Sgabor } 1091202719Sgabor *p = '\0'; 1092202719Sgabor return (ret); 1093202719Sgabor} 1094202719Sgabor 1095202719Sgabor/* ARGSUSED */ 1096243075Seadlerstatic void 1097264573Sdelphijsigchld(int signo __unused) 1098202719Sgabor{ 1099203443Sgabor pid_t pid; 1100264573Sdelphij int status, save_errno = errno; 1101202719Sgabor 1102264573Sdelphij for (;;) { 1103264573Sdelphij pid = waitpid(dc, &status, WCONTINUED | WNOHANG); 1104264573Sdelphij if (pid == -1) { 1105264573Sdelphij if (errno == EINTR) 1106264573Sdelphij continue; 1107264573Sdelphij _exit(0); 1108264573Sdelphij } else if (pid == 0) 1109264573Sdelphij break; 1110264573Sdelphij if (WIFEXITED(status) || WIFSIGNALED(status)) 1111264573Sdelphij _exit(0); 1112264573Sdelphij else 1113264573Sdelphij break; 1114202719Sgabor } 1115264573Sdelphij errno = save_errno; 1116202719Sgabor} 1117202719Sgabor 1118203498Sdelphijstatic const char * 1119203498Sdelphijdummy_prompt(void) 1120203498Sdelphij{ 1121203498Sdelphij 1122203498Sdelphij return (""); 1123203498Sdelphij} 1124203498Sdelphij 1125202719Sgaborint 1126202719Sgabormain(int argc, char *argv[]) 1127202719Sgabor{ 1128203443Sgabor char *q; 1129203443Sgabor int p[2]; 1130203443Sgabor int ch, i; 1131202719Sgabor 1132202719Sgabor init(); 1133291155Spfg setvbuf(stdout, NULL, _IOLBF, 0); 1134202719Sgabor 1135202719Sgabor sargv = malloc(argc * sizeof(char *)); 1136202719Sgabor if (sargv == NULL) 1137202719Sgabor err(1, NULL); 1138202719Sgabor 1139202719Sgabor if ((cmdexpr = strdup("")) == NULL) 1140202719Sgabor err(1, NULL); 1141202719Sgabor /* The d debug option is 4.4 BSD bc(1) compatible */ 1142202719Sgabor while ((ch = getopt_long(argc, argv, "cde:hlqv", 1143202719Sgabor long_options, NULL)) != -1) { 1144202719Sgabor switch (ch) { 1145202719Sgabor case 'c': 1146202719Sgabor case 'd': 1147202719Sgabor do_fork = false; 1148202719Sgabor break; 1149202719Sgabor case 'e': 1150202719Sgabor q = cmdexpr; 1151202719Sgabor if (asprintf(&cmdexpr, "%s%s\n", cmdexpr, optarg) == -1) 1152202719Sgabor err(1, NULL); 1153202719Sgabor free(q); 1154202719Sgabor break; 1155202719Sgabor case 'h': 1156202719Sgabor usage(); 1157202719Sgabor break; 1158202719Sgabor case 'l': 1159202719Sgabor sargv[sargc++] = _PATH_LIBB; 1160202719Sgabor break; 1161202719Sgabor case 'q': 1162202719Sgabor /* compatibility option */ 1163202719Sgabor break; 1164202719Sgabor case 'v': 1165202719Sgabor fprintf(stderr, "%s (BSD bc) %s\n", __progname, BC_VER); 1166202719Sgabor exit(0); 1167202719Sgabor break; 1168202719Sgabor default: 1169202719Sgabor usage(); 1170202719Sgabor } 1171202719Sgabor } 1172202719Sgabor 1173202719Sgabor argc -= optind; 1174202719Sgabor argv += optind; 1175202719Sgabor 1176343491Snyan interactive = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) && 1177343491Snyan isatty(STDERR_FILENO); 1178202719Sgabor for (i = 0; i < argc; i++) 1179202719Sgabor sargv[sargc++] = argv[i]; 1180202719Sgabor 1181202719Sgabor if (do_fork) { 1182202719Sgabor if (pipe(p) == -1) 1183202719Sgabor err(1, "cannot create pipe"); 1184202719Sgabor dc = fork(); 1185202719Sgabor if (dc == -1) 1186202719Sgabor err(1, "cannot fork"); 1187202719Sgabor else if (dc != 0) { 1188202719Sgabor signal(SIGCHLD, sigchld); 1189202719Sgabor close(STDOUT_FILENO); 1190202719Sgabor dup(p[1]); 1191202719Sgabor close(p[0]); 1192202719Sgabor close(p[1]); 1193202719Sgabor } else { 1194202719Sgabor close(STDIN_FILENO); 1195202719Sgabor dup(p[0]); 1196202719Sgabor close(p[0]); 1197202719Sgabor close(p[1]); 1198202719Sgabor execl(_PATH_DC, "dc", "-x", (char *)NULL); 1199202719Sgabor err(1, "cannot find dc"); 1200202719Sgabor } 1201202719Sgabor } 1202232994Skevlo if (interactive) { 1203264573Sdelphij gettty(&ttysaved); 1204232994Skevlo el = el_init("bc", stdin, stderr, stderr); 1205232994Skevlo hist = history_init(); 1206232994Skevlo history(hist, &he, H_SETSIZE, 100); 1207232994Skevlo el_set(el, EL_HIST, history, hist); 1208232994Skevlo el_set(el, EL_EDITOR, "emacs"); 1209232994Skevlo el_set(el, EL_SIGNAL, 1); 1210232994Skevlo el_set(el, EL_PROMPT, dummy_prompt); 1211264573Sdelphij el_set(el, EL_ADDFN, "bc_eof", "", bc_eof); 1212264573Sdelphij el_set(el, EL_BIND, "^D", "bc_eof", NULL); 1213232994Skevlo el_source(el, NULL); 1214232994Skevlo } 1215202719Sgabor yywrap(); 1216202719Sgabor return (yyparse()); 1217202719Sgabor} 1218