bc.y revision 243075
1202719Sgabor%{ 2202719Sgabor/* $OpenBSD: bc.y,v 1.33 2009/10/27 23:59:36 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: head/usr.bin/bc/bc.y 243075 2012-11-15 15:06:00Z eadler $"); 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 <stdbool.h> 49202719Sgabor#include <string.h> 50202719Sgabor#include <unistd.h> 51232994Skevlo#include <stdlib.h> 52202719Sgabor 53202719Sgabor#include "extern.h" 54202719Sgabor#include "pathnames.h" 55202719Sgabor 56202719Sgabor#define BC_VER "1.0-FreeBSD" 57202719Sgabor#define END_NODE ((ssize_t) -1) 58202719Sgabor#define CONST_STRING ((ssize_t) -2) 59202719Sgabor#define ALLOC_STRING ((ssize_t) -3) 60202719Sgabor 61202719Sgaborextern char *yytext; 62202719Sgaborextern FILE *yyin; 63202719Sgabor 64202719Sgaborstruct tree { 65202719Sgabor union { 66202719Sgabor char *astr; 67202719Sgabor const char *cstr; 68202719Sgabor } u; 69203443Sgabor ssize_t index; 70202719Sgabor}; 71202719Sgabor 72202719Sgaborint yywrap(void); 73202719Sgabor 74202719Sgaborint fileindex; 75202719Sgaborint sargc; 76202719Sgaborconst char **sargv; 77202719Sgaborconst char *filename; 78202719Sgaborchar *cmdexpr; 79202719Sgabor 80202719Sgaborstatic void grow(void); 81202719Sgaborstatic ssize_t cs(const char *); 82202719Sgaborstatic ssize_t as(const char *); 83202719Sgaborstatic ssize_t node(ssize_t, ...); 84202719Sgaborstatic void emit(ssize_t); 85202719Sgaborstatic void emit_macro(int, ssize_t); 86202719Sgaborstatic void free_tree(void); 87202719Sgaborstatic ssize_t numnode(int); 88202719Sgaborstatic ssize_t lookup(char *, size_t, char); 89202719Sgaborstatic ssize_t letter_node(char *); 90202719Sgaborstatic ssize_t array_node(char *); 91202719Sgaborstatic ssize_t function_node(char *); 92202719Sgabor 93202719Sgaborstatic void add_par(ssize_t); 94202719Sgaborstatic void add_local(ssize_t); 95202719Sgaborstatic void warning(const char *); 96202719Sgaborstatic void init(void); 97202719Sgaborstatic void usage(void); 98202719Sgaborstatic char *escape(const char *); 99202719Sgabor 100202719Sgaborstatic ssize_t instr_sz = 0; 101202719Sgaborstatic struct tree *instructions = NULL; 102202719Sgaborstatic ssize_t current = 0; 103202719Sgaborstatic int macro_char = '0'; 104202719Sgaborstatic int reset_macro_char = '0'; 105202719Sgaborstatic int nesting = 0; 106202719Sgaborstatic int breakstack[16]; 107202719Sgaborstatic int breaksp = 0; 108202719Sgaborstatic ssize_t prologue; 109202719Sgaborstatic ssize_t epilogue; 110202719Sgaborstatic bool st_has_continue; 111202719Sgaborstatic char str_table[UCHAR_MAX][2]; 112202719Sgaborstatic bool do_fork = true; 113202719Sgaborstatic u_short var_count; 114202719Sgaborstatic pid_t dc; 115202719Sgabor 116202719Sgaborstatic void sigchld(int); 117202719Sgabor 118202719Sgaborextern char *__progname; 119202719Sgabor 120202719Sgabor#define BREAKSTACK_SZ (sizeof(breakstack)/sizeof(breakstack[0])) 121202719Sgabor 122202719Sgabor/* These values are 4.4BSD bc compatible */ 123202719Sgabor#define FUNC_CHAR 0x01 124202719Sgabor#define ARRAY_CHAR 0xa1 125202719Sgabor 126202719Sgabor/* Skip '\0', [, \ and ] */ 127202719Sgabor#define ENCODE(c) ((c) < '[' ? (c) : (c) + 3); 128202719Sgabor#define VAR_BASE (256-4) 129202719Sgabor#define MAX_VARIABLES (VAR_BASE * VAR_BASE) 130202719Sgabor 131202719Sgaborconst struct option long_options[] = 132202719Sgabor{ 133202719Sgabor {"expression", required_argument, NULL, 'e'}, 134202719Sgabor {"help", no_argument, NULL, 'h'}, 135202719Sgabor {"mathlib", no_argument, NULL, 'l'}, 136202719Sgabor /* compatibility option */ 137202719Sgabor {"quiet", no_argument, NULL, 'q'}, 138202719Sgabor {"version", no_argument, NULL, 'v'}, 139202719Sgabor {NULL, no_argument, NULL, 0} 140202719Sgabor}; 141202719Sgabor 142202719Sgabor%} 143202719Sgabor 144202719Sgabor%start program 145202719Sgabor 146202719Sgabor%union { 147202719Sgabor struct lvalue lvalue; 148202719Sgabor const char *str; 149202719Sgabor char *astr; 150203443Sgabor ssize_t node; 151202719Sgabor} 152202719Sgabor 153202719Sgabor%token COMMA SEMICOLON LPAR RPAR LBRACE RBRACE LBRACKET RBRACKET DOT 154202719Sgabor%token NEWLINE 155202719Sgabor%token <astr> LETTER 156202719Sgabor%token <str> NUMBER STRING 157202719Sgabor%token DEFINE BREAK QUIT LENGTH 158202719Sgabor%token RETURN FOR IF WHILE SQRT 159202719Sgabor%token SCALE IBASE OBASE AUTO 160202719Sgabor%token CONTINUE ELSE PRINT 161202719Sgabor 162202719Sgabor%left BOOL_OR 163202719Sgabor%left BOOL_AND 164202719Sgabor%nonassoc BOOL_NOT 165202719Sgabor%nonassoc EQUALS LESS_EQ GREATER_EQ UNEQUALS LESS GREATER 166202719Sgabor%right <str> ASSIGN_OP 167202719Sgabor%left PLUS MINUS 168202719Sgabor%left MULTIPLY DIVIDE REMAINDER 169202719Sgabor%right EXPONENT 170202719Sgabor%nonassoc UMINUS 171202719Sgabor%nonassoc INCR DECR 172202719Sgabor 173202719Sgabor%type <lvalue> named_expression 174202719Sgabor%type <node> argument_list 175202719Sgabor%type <node> alloc_macro 176202719Sgabor%type <node> expression 177202719Sgabor%type <node> function 178202719Sgabor%type <node> function_header 179202719Sgabor%type <node> input_item 180202719Sgabor%type <node> opt_argument_list 181202719Sgabor%type <node> opt_expression 182202719Sgabor%type <node> opt_relational_expression 183202719Sgabor%type <node> opt_statement 184202719Sgabor%type <node> print_expression 185202719Sgabor%type <node> print_expression_list 186202719Sgabor%type <node> relational_expression 187202719Sgabor%type <node> return_expression 188202719Sgabor%type <node> semicolon_list 189202719Sgabor%type <node> statement 190202719Sgabor%type <node> statement_list 191202719Sgabor 192202719Sgabor%% 193202719Sgabor 194202719Sgaborprogram : /* empty */ 195202719Sgabor | program input_item 196202719Sgabor ; 197202719Sgabor 198202719Sgaborinput_item : semicolon_list NEWLINE 199202719Sgabor { 200202719Sgabor emit($1); 201202719Sgabor macro_char = reset_macro_char; 202202719Sgabor putchar('\n'); 203202719Sgabor free_tree(); 204202719Sgabor st_has_continue = false; 205202719Sgabor } 206202719Sgabor | function 207202719Sgabor { 208202719Sgabor putchar('\n'); 209202719Sgabor free_tree(); 210202719Sgabor st_has_continue = false; 211202719Sgabor } 212202719Sgabor | error NEWLINE 213202719Sgabor { 214202719Sgabor yyerrok; 215202719Sgabor } 216202719Sgabor | error QUIT 217202719Sgabor { 218202719Sgabor yyerrok; 219202719Sgabor } 220202719Sgabor ; 221202719Sgabor 222202719Sgaborsemicolon_list : /* empty */ 223202719Sgabor { 224202719Sgabor $$ = cs(""); 225202719Sgabor } 226202719Sgabor | statement 227202719Sgabor | semicolon_list SEMICOLON statement 228202719Sgabor { 229202719Sgabor $$ = node($1, $3, END_NODE); 230202719Sgabor } 231202719Sgabor | semicolon_list SEMICOLON 232202719Sgabor ; 233202719Sgabor 234202719Sgaborstatement_list : /* empty */ 235202719Sgabor { 236202719Sgabor $$ = cs(""); 237202719Sgabor } 238202719Sgabor | statement 239202719Sgabor | statement_list NEWLINE 240202719Sgabor | statement_list NEWLINE statement 241202719Sgabor { 242202719Sgabor $$ = node($1, $3, END_NODE); 243202719Sgabor } 244202719Sgabor | statement_list SEMICOLON 245202719Sgabor | statement_list SEMICOLON statement 246202719Sgabor { 247202719Sgabor $$ = node($1, $3, END_NODE); 248202719Sgabor } 249202719Sgabor ; 250202719Sgabor 251202719Sgabor 252202719Sgaboropt_statement : /* empty */ 253202719Sgabor { 254202719Sgabor $$ = cs(""); 255202719Sgabor } 256202719Sgabor | statement 257202719Sgabor ; 258202719Sgabor 259202719Sgaborstatement : expression 260202719Sgabor { 261202719Sgabor $$ = node($1, cs("ps."), END_NODE); 262202719Sgabor } 263202719Sgabor | named_expression ASSIGN_OP expression 264202719Sgabor { 265202719Sgabor if ($2[0] == '\0') 266202719Sgabor $$ = node($3, cs($2), $1.store, 267202719Sgabor END_NODE); 268202719Sgabor else 269202719Sgabor $$ = node($1.load, $3, cs($2), $1.store, 270202719Sgabor END_NODE); 271202719Sgabor } 272202719Sgabor | STRING 273202719Sgabor { 274202719Sgabor $$ = node(cs("["), as($1), 275202719Sgabor cs("]P"), END_NODE); 276202719Sgabor } 277202719Sgabor | BREAK 278202719Sgabor { 279202719Sgabor if (breaksp == 0) { 280202719Sgabor warning("break not in for or while"); 281202719Sgabor YYERROR; 282202719Sgabor } else { 283202719Sgabor $$ = node( 284202719Sgabor numnode(nesting - 285202719Sgabor breakstack[breaksp-1]), 286202719Sgabor cs("Q"), END_NODE); 287202719Sgabor } 288202719Sgabor } 289202719Sgabor | CONTINUE 290202719Sgabor { 291202719Sgabor if (breaksp == 0) { 292202719Sgabor warning("continue not in for or while"); 293202719Sgabor YYERROR; 294202719Sgabor } else { 295202719Sgabor st_has_continue = true; 296202719Sgabor $$ = node(numnode(nesting - 297202719Sgabor breakstack[breaksp-1] - 1), 298202719Sgabor cs("J"), END_NODE); 299202719Sgabor } 300202719Sgabor } 301202719Sgabor | QUIT 302202719Sgabor { 303203443Sgabor sigset_t mask; 304202719Sgabor 305202719Sgabor putchar('q'); 306202719Sgabor fflush(stdout); 307202719Sgabor if (dc) { 308202719Sgabor sigprocmask(SIG_BLOCK, NULL, &mask); 309202719Sgabor sigsuspend(&mask); 310202719Sgabor } else 311202719Sgabor exit(0); 312202719Sgabor } 313202719Sgabor | RETURN return_expression 314202719Sgabor { 315202719Sgabor if (nesting == 0) { 316202719Sgabor warning("return must be in a function"); 317202719Sgabor YYERROR; 318202719Sgabor } 319202719Sgabor $$ = $2; 320202719Sgabor } 321202719Sgabor | FOR LPAR alloc_macro opt_expression SEMICOLON 322202719Sgabor opt_relational_expression SEMICOLON 323202719Sgabor opt_expression RPAR opt_statement pop_nesting 324202719Sgabor { 325203443Sgabor ssize_t n; 326202719Sgabor 327202719Sgabor if (st_has_continue) 328202719Sgabor n = node($10, cs("M"), $8, cs("s."), 329202719Sgabor $6, $3, END_NODE); 330202719Sgabor else 331202719Sgabor n = node($10, $8, cs("s."), $6, $3, 332202719Sgabor END_NODE); 333202719Sgabor 334202719Sgabor emit_macro($3, n); 335202719Sgabor $$ = node($4, cs("s."), $6, $3, cs(" "), 336202719Sgabor END_NODE); 337202719Sgabor } 338202719Sgabor | IF LPAR alloc_macro pop_nesting relational_expression RPAR 339202719Sgabor opt_statement 340202719Sgabor { 341202719Sgabor emit_macro($3, $7); 342202719Sgabor $$ = node($5, $3, cs(" "), END_NODE); 343202719Sgabor } 344202719Sgabor | IF LPAR alloc_macro pop_nesting relational_expression RPAR 345202719Sgabor opt_statement ELSE alloc_macro pop_nesting opt_statement 346202719Sgabor { 347202719Sgabor emit_macro($3, $7); 348202719Sgabor emit_macro($9, $11); 349202719Sgabor $$ = node($5, $3, cs("e"), $9, cs(" "), 350202719Sgabor END_NODE); 351202719Sgabor } 352202719Sgabor | WHILE LPAR alloc_macro relational_expression RPAR 353202719Sgabor opt_statement pop_nesting 354202719Sgabor { 355203443Sgabor ssize_t n; 356202719Sgabor 357202719Sgabor if (st_has_continue) 358202719Sgabor n = node($6, cs("M"), $4, $3, END_NODE); 359202719Sgabor else 360202719Sgabor n = node($6, $4, $3, END_NODE); 361202719Sgabor emit_macro($3, n); 362202719Sgabor $$ = node($4, $3, cs(" "), END_NODE); 363202719Sgabor } 364202719Sgabor | LBRACE statement_list RBRACE 365202719Sgabor { 366202719Sgabor $$ = $2; 367202719Sgabor } 368202719Sgabor | PRINT print_expression_list 369202719Sgabor { 370202719Sgabor $$ = $2; 371202719Sgabor } 372202719Sgabor ; 373202719Sgabor 374202719Sgaboralloc_macro : /* empty */ 375202719Sgabor { 376202719Sgabor $$ = cs(str_table[macro_char]); 377202719Sgabor macro_char++; 378202719Sgabor /* Do not use [, \ and ] */ 379202719Sgabor if (macro_char == '[') 380202719Sgabor macro_char += 3; 381202719Sgabor /* skip letters */ 382202719Sgabor else if (macro_char == 'a') 383202719Sgabor macro_char = '{'; 384202719Sgabor else if (macro_char == ARRAY_CHAR) 385202719Sgabor macro_char += 26; 386202719Sgabor else if (macro_char == 255) 387202719Sgabor fatal("program too big"); 388202719Sgabor if (breaksp == BREAKSTACK_SZ) 389202719Sgabor fatal("nesting too deep"); 390202719Sgabor breakstack[breaksp++] = nesting++; 391202719Sgabor } 392202719Sgabor ; 393202719Sgabor 394202719Sgaborpop_nesting : /* empty */ 395202719Sgabor { 396202719Sgabor breaksp--; 397202719Sgabor } 398202719Sgabor ; 399202719Sgabor 400202719Sgaborfunction : function_header opt_parameter_list RPAR opt_newline 401202719Sgabor LBRACE NEWLINE opt_auto_define_list 402202719Sgabor statement_list RBRACE 403202719Sgabor { 404202719Sgabor int n = node(prologue, $8, epilogue, 405202719Sgabor cs("0"), numnode(nesting), 406202719Sgabor cs("Q"), END_NODE); 407202719Sgabor emit_macro($1, n); 408202719Sgabor reset_macro_char = macro_char; 409202719Sgabor nesting = 0; 410202719Sgabor breaksp = 0; 411202719Sgabor } 412202719Sgabor ; 413202719Sgabor 414202719Sgaborfunction_header : DEFINE LETTER LPAR 415202719Sgabor { 416202719Sgabor $$ = function_node($2); 417202719Sgabor free($2); 418202719Sgabor prologue = cs(""); 419202719Sgabor epilogue = cs(""); 420202719Sgabor nesting = 1; 421202719Sgabor breaksp = 0; 422202719Sgabor breakstack[breaksp] = 0; 423202719Sgabor } 424202719Sgabor ; 425202719Sgabor 426202719Sgaboropt_newline : /* empty */ 427202719Sgabor | NEWLINE 428202719Sgabor ; 429202719Sgabor 430202719Sgaboropt_parameter_list 431202719Sgabor : /* empty */ 432202719Sgabor | parameter_list 433202719Sgabor ; 434202719Sgabor 435202719Sgabor 436202719Sgaborparameter_list : LETTER 437202719Sgabor { 438202719Sgabor add_par(letter_node($1)); 439202719Sgabor free($1); 440202719Sgabor } 441202719Sgabor | LETTER LBRACKET RBRACKET 442202719Sgabor { 443202719Sgabor add_par(array_node($1)); 444202719Sgabor free($1); 445202719Sgabor } 446202719Sgabor | parameter_list COMMA LETTER 447202719Sgabor { 448202719Sgabor add_par(letter_node($3)); 449202719Sgabor free($3); 450202719Sgabor } 451202719Sgabor | parameter_list COMMA LETTER LBRACKET RBRACKET 452202719Sgabor { 453202719Sgabor add_par(array_node($3)); 454202719Sgabor free($3); 455202719Sgabor } 456202719Sgabor ; 457202719Sgabor 458202719Sgabor 459202719Sgabor 460202719Sgaboropt_auto_define_list 461202719Sgabor : /* empty */ 462202719Sgabor | AUTO define_list NEWLINE 463202719Sgabor | AUTO define_list SEMICOLON 464202719Sgabor ; 465202719Sgabor 466202719Sgabor 467202719Sgabordefine_list : LETTER 468202719Sgabor { 469202719Sgabor add_local(letter_node($1)); 470202719Sgabor free($1); 471202719Sgabor } 472202719Sgabor | LETTER LBRACKET RBRACKET 473202719Sgabor { 474202719Sgabor add_local(array_node($1)); 475202719Sgabor free($1); 476202719Sgabor } 477202719Sgabor | define_list COMMA LETTER 478202719Sgabor { 479202719Sgabor add_local(letter_node($3)); 480202719Sgabor free($3); 481202719Sgabor } 482202719Sgabor | define_list COMMA LETTER LBRACKET RBRACKET 483202719Sgabor { 484202719Sgabor add_local(array_node($3)); 485202719Sgabor free($3); 486202719Sgabor } 487202719Sgabor ; 488202719Sgabor 489202719Sgabor 490202719Sgaboropt_argument_list 491202719Sgabor : /* empty */ 492202719Sgabor { 493202719Sgabor $$ = cs(""); 494202719Sgabor } 495202719Sgabor | argument_list 496202719Sgabor ; 497202719Sgabor 498202719Sgabor 499202719Sgaborargument_list : expression 500202719Sgabor | argument_list COMMA expression 501202719Sgabor { 502202719Sgabor $$ = node($1, $3, END_NODE); 503202719Sgabor } 504202719Sgabor | argument_list COMMA LETTER LBRACKET RBRACKET 505202719Sgabor { 506202719Sgabor $$ = node($1, cs("l"), array_node($3), 507202719Sgabor END_NODE); 508202719Sgabor free($3); 509202719Sgabor } 510202719Sgabor ; 511202719Sgabor 512202719Sgaboropt_relational_expression 513202719Sgabor : /* empty */ 514202719Sgabor { 515202719Sgabor $$ = cs(" 0 0="); 516202719Sgabor } 517202719Sgabor | relational_expression 518202719Sgabor ; 519202719Sgabor 520202719Sgaborrelational_expression 521202719Sgabor : expression EQUALS expression 522202719Sgabor { 523202719Sgabor $$ = node($1, $3, cs("="), END_NODE); 524202719Sgabor } 525202719Sgabor | expression UNEQUALS expression 526202719Sgabor { 527202719Sgabor $$ = node($1, $3, cs("!="), END_NODE); 528202719Sgabor } 529202719Sgabor | expression LESS expression 530202719Sgabor { 531202719Sgabor $$ = node($1, $3, cs(">"), END_NODE); 532202719Sgabor } 533202719Sgabor | expression LESS_EQ expression 534202719Sgabor { 535202719Sgabor $$ = node($1, $3, cs("!<"), END_NODE); 536202719Sgabor } 537202719Sgabor | expression GREATER expression 538202719Sgabor { 539202719Sgabor $$ = node($1, $3, cs("<"), END_NODE); 540202719Sgabor } 541202719Sgabor | expression GREATER_EQ expression 542202719Sgabor { 543202719Sgabor $$ = node($1, $3, cs("!>"), END_NODE); 544202719Sgabor } 545202719Sgabor | expression 546202719Sgabor { 547202719Sgabor $$ = node($1, cs(" 0!="), END_NODE); 548202719Sgabor } 549202719Sgabor ; 550202719Sgabor 551202719Sgabor 552202719Sgaborreturn_expression 553202719Sgabor : /* empty */ 554202719Sgabor { 555202719Sgabor $$ = node(cs("0"), epilogue, 556202719Sgabor numnode(nesting), cs("Q"), END_NODE); 557202719Sgabor } 558202719Sgabor | expression 559202719Sgabor { 560202719Sgabor $$ = node($1, epilogue, 561202719Sgabor numnode(nesting), cs("Q"), END_NODE); 562202719Sgabor } 563202719Sgabor | LPAR RPAR 564202719Sgabor { 565202719Sgabor $$ = node(cs("0"), epilogue, 566202719Sgabor numnode(nesting), cs("Q"), END_NODE); 567202719Sgabor } 568202719Sgabor ; 569202719Sgabor 570202719Sgabor 571202719Sgaboropt_expression : /* empty */ 572202719Sgabor { 573202719Sgabor $$ = cs(" 0"); 574202719Sgabor } 575202719Sgabor | expression 576202719Sgabor ; 577202719Sgabor 578202719Sgaborexpression : named_expression 579202719Sgabor { 580202719Sgabor $$ = node($1.load, END_NODE); 581202719Sgabor } 582202719Sgabor | DOT { 583202719Sgabor $$ = node(cs("l."), END_NODE); 584202719Sgabor } 585202719Sgabor | NUMBER 586202719Sgabor { 587202719Sgabor $$ = node(cs(" "), as($1), END_NODE); 588202719Sgabor } 589202719Sgabor | LPAR expression RPAR 590202719Sgabor { 591202719Sgabor $$ = $2; 592202719Sgabor } 593202719Sgabor | LETTER LPAR opt_argument_list RPAR 594202719Sgabor { 595202719Sgabor $$ = node($3, cs("l"), 596202719Sgabor function_node($1), cs("x"), 597202719Sgabor END_NODE); 598202719Sgabor free($1); 599202719Sgabor } 600202719Sgabor | MINUS expression %prec UMINUS 601202719Sgabor { 602202719Sgabor $$ = node(cs(" 0"), $2, cs("-"), 603202719Sgabor END_NODE); 604202719Sgabor } 605202719Sgabor | expression PLUS expression 606202719Sgabor { 607202719Sgabor $$ = node($1, $3, cs("+"), END_NODE); 608202719Sgabor } 609202719Sgabor | expression MINUS expression 610202719Sgabor { 611202719Sgabor $$ = node($1, $3, cs("-"), END_NODE); 612202719Sgabor } 613202719Sgabor | expression MULTIPLY expression 614202719Sgabor { 615202719Sgabor $$ = node($1, $3, cs("*"), END_NODE); 616202719Sgabor } 617202719Sgabor | expression DIVIDE expression 618202719Sgabor { 619202719Sgabor $$ = node($1, $3, cs("/"), END_NODE); 620202719Sgabor } 621202719Sgabor | expression REMAINDER expression 622202719Sgabor { 623202719Sgabor $$ = node($1, $3, cs("%"), END_NODE); 624202719Sgabor } 625202719Sgabor | expression EXPONENT expression 626202719Sgabor { 627202719Sgabor $$ = node($1, $3, cs("^"), END_NODE); 628202719Sgabor } 629202719Sgabor | INCR named_expression 630202719Sgabor { 631202719Sgabor $$ = node($2.load, cs("1+d"), $2.store, 632202719Sgabor END_NODE); 633202719Sgabor } 634202719Sgabor | DECR named_expression 635202719Sgabor { 636202719Sgabor $$ = node($2.load, cs("1-d"), 637202719Sgabor $2.store, END_NODE); 638202719Sgabor } 639202719Sgabor | named_expression INCR 640202719Sgabor { 641202719Sgabor $$ = node($1.load, cs("d1+"), 642202719Sgabor $1.store, END_NODE); 643202719Sgabor } 644202719Sgabor | named_expression DECR 645202719Sgabor { 646202719Sgabor $$ = node($1.load, cs("d1-"), 647202719Sgabor $1.store, END_NODE); 648202719Sgabor } 649202719Sgabor | named_expression ASSIGN_OP expression 650202719Sgabor { 651202719Sgabor if ($2[0] == '\0') 652202719Sgabor $$ = node($3, cs($2), cs("d"), $1.store, 653202719Sgabor END_NODE); 654202719Sgabor else 655202719Sgabor $$ = node($1.load, $3, cs($2), cs("d"), 656202719Sgabor $1.store, END_NODE); 657202719Sgabor } 658202719Sgabor | LENGTH LPAR expression RPAR 659202719Sgabor { 660202719Sgabor $$ = node($3, cs("Z"), END_NODE); 661202719Sgabor } 662202719Sgabor | SQRT LPAR expression RPAR 663202719Sgabor { 664202719Sgabor $$ = node($3, cs("v"), END_NODE); 665202719Sgabor } 666202719Sgabor | SCALE LPAR expression RPAR 667202719Sgabor { 668202719Sgabor $$ = node($3, cs("X"), END_NODE); 669202719Sgabor } 670202719Sgabor | BOOL_NOT expression 671202719Sgabor { 672202719Sgabor $$ = node($2, cs("N"), END_NODE); 673202719Sgabor } 674202719Sgabor | expression BOOL_AND alloc_macro pop_nesting expression 675202719Sgabor { 676202719Sgabor ssize_t n = node(cs("R"), $5, END_NODE); 677202719Sgabor emit_macro($3, n); 678202719Sgabor $$ = node($1, cs("d0!="), $3, END_NODE); 679202719Sgabor } 680202719Sgabor | expression BOOL_OR alloc_macro pop_nesting expression 681202719Sgabor { 682202719Sgabor ssize_t n = node(cs("R"), $5, END_NODE); 683202719Sgabor emit_macro($3, n); 684202719Sgabor $$ = node($1, cs("d0="), $3, END_NODE); 685202719Sgabor } 686202719Sgabor | expression EQUALS expression 687202719Sgabor { 688202719Sgabor $$ = node($1, $3, cs("G"), END_NODE); 689202719Sgabor } 690202719Sgabor | expression UNEQUALS expression 691202719Sgabor { 692202719Sgabor $$ = node($1, $3, cs("GN"), END_NODE); 693202719Sgabor } 694202719Sgabor | expression LESS expression 695202719Sgabor { 696202719Sgabor $$ = node($3, $1, cs("("), END_NODE); 697202719Sgabor } 698202719Sgabor | expression LESS_EQ expression 699202719Sgabor { 700202719Sgabor $$ = node($3, $1, cs("{"), END_NODE); 701202719Sgabor } 702202719Sgabor | expression GREATER expression 703202719Sgabor { 704202719Sgabor $$ = node($1, $3, cs("("), END_NODE); 705202719Sgabor } 706202719Sgabor | expression GREATER_EQ expression 707202719Sgabor { 708202719Sgabor $$ = node($1, $3, cs("{"), END_NODE); 709202719Sgabor } 710202719Sgabor ; 711202719Sgabor 712202719Sgabornamed_expression 713202719Sgabor : LETTER 714202719Sgabor { 715202719Sgabor $$.load = node(cs("l"), letter_node($1), 716202719Sgabor END_NODE); 717202719Sgabor $$.store = node(cs("s"), letter_node($1), 718202719Sgabor END_NODE); 719202719Sgabor free($1); 720202719Sgabor } 721202719Sgabor | LETTER LBRACKET expression RBRACKET 722202719Sgabor { 723202719Sgabor $$.load = node($3, cs(";"), 724202719Sgabor array_node($1), END_NODE); 725202719Sgabor $$.store = node($3, cs(":"), 726202719Sgabor array_node($1), END_NODE); 727202719Sgabor free($1); 728202719Sgabor } 729202719Sgabor | SCALE 730202719Sgabor { 731202719Sgabor $$.load = cs("K"); 732202719Sgabor $$.store = cs("k"); 733202719Sgabor } 734202719Sgabor | IBASE 735202719Sgabor { 736202719Sgabor $$.load = cs("I"); 737202719Sgabor $$.store = cs("i"); 738202719Sgabor } 739202719Sgabor | OBASE 740202719Sgabor { 741202719Sgabor $$.load = cs("O"); 742202719Sgabor $$.store = cs("o"); 743202719Sgabor } 744202719Sgabor ; 745202719Sgabor 746202719Sgaborprint_expression_list 747202719Sgabor : print_expression 748202719Sgabor | print_expression_list COMMA print_expression 749202719Sgabor { 750202719Sgabor $$ = node($1, $3, END_NODE); 751202719Sgabor } 752202719Sgabor 753202719Sgaborprint_expression 754202719Sgabor : expression 755202719Sgabor { 756202719Sgabor $$ = node($1, cs("ds.n"), END_NODE); 757202719Sgabor } 758202719Sgabor | STRING 759202719Sgabor { 760202719Sgabor char *p = escape($1); 761202719Sgabor $$ = node(cs("["), as(p), cs("]n"), END_NODE); 762202719Sgabor free(p); 763202719Sgabor } 764202719Sgabor%% 765202719Sgabor 766202719Sgabor 767202719Sgaborstatic void 768202719Sgaborgrow(void) 769202719Sgabor{ 770203443Sgabor struct tree *p; 771203443Sgabor size_t newsize; 772202719Sgabor 773202719Sgabor if (current == instr_sz) { 774202719Sgabor newsize = instr_sz * 2 + 1; 775202719Sgabor p = realloc(instructions, newsize * sizeof(*p)); 776202719Sgabor if (p == NULL) { 777202719Sgabor free(instructions); 778202719Sgabor err(1, NULL); 779202719Sgabor } 780202719Sgabor instructions = p; 781202719Sgabor instr_sz = newsize; 782202719Sgabor } 783202719Sgabor} 784202719Sgabor 785202719Sgaborstatic ssize_t 786202719Sgaborcs(const char *str) 787202719Sgabor{ 788203443Sgabor 789202719Sgabor grow(); 790202719Sgabor instructions[current].index = CONST_STRING; 791202719Sgabor instructions[current].u.cstr = str; 792202719Sgabor return (current++); 793202719Sgabor} 794202719Sgabor 795202719Sgaborstatic ssize_t 796202719Sgaboras(const char *str) 797202719Sgabor{ 798203443Sgabor 799202719Sgabor grow(); 800202719Sgabor instructions[current].index = ALLOC_STRING; 801202719Sgabor instructions[current].u.astr = strdup(str); 802202719Sgabor if (instructions[current].u.astr == NULL) 803202719Sgabor err(1, NULL); 804202719Sgabor return (current++); 805202719Sgabor} 806202719Sgabor 807202719Sgaborstatic ssize_t 808202719Sgabornode(ssize_t arg, ...) 809202719Sgabor{ 810203443Sgabor va_list ap; 811203443Sgabor ssize_t ret; 812202719Sgabor 813202719Sgabor va_start(ap, arg); 814202719Sgabor 815202719Sgabor ret = current; 816202719Sgabor grow(); 817202719Sgabor instructions[current++].index = arg; 818202719Sgabor 819202719Sgabor do { 820202719Sgabor arg = va_arg(ap, ssize_t); 821202719Sgabor grow(); 822202719Sgabor instructions[current++].index = arg; 823202719Sgabor } while (arg != END_NODE); 824202719Sgabor 825202719Sgabor va_end(ap); 826202719Sgabor return (ret); 827202719Sgabor} 828202719Sgabor 829202719Sgaborstatic void 830202719Sgaboremit(ssize_t i) 831202719Sgabor{ 832203443Sgabor 833202719Sgabor if (instructions[i].index >= 0) 834202719Sgabor while (instructions[i].index != END_NODE) 835202719Sgabor emit(instructions[i++].index); 836202719Sgabor else 837202719Sgabor fputs(instructions[i].u.cstr, stdout); 838202719Sgabor} 839202719Sgabor 840202719Sgaborstatic void 841202719Sgaboremit_macro(int nodeidx, ssize_t code) 842202719Sgabor{ 843203443Sgabor 844202719Sgabor putchar('['); 845202719Sgabor emit(code); 846202719Sgabor printf("]s%s\n", instructions[nodeidx].u.cstr); 847202719Sgabor nesting--; 848202719Sgabor} 849202719Sgabor 850202719Sgaborstatic void 851202719Sgaborfree_tree(void) 852202719Sgabor{ 853203443Sgabor ssize_t i; 854202719Sgabor 855202719Sgabor for (i = 0; i < current; i++) 856202719Sgabor if (instructions[i].index == ALLOC_STRING) 857202719Sgabor free(instructions[i].u.astr); 858202719Sgabor current = 0; 859202719Sgabor} 860202719Sgabor 861202719Sgaborstatic ssize_t 862202719Sgabornumnode(int num) 863202719Sgabor{ 864203443Sgabor const char *p; 865202719Sgabor 866202719Sgabor if (num < 10) 867202719Sgabor p = str_table['0' + num]; 868202719Sgabor else if (num < 16) 869202719Sgabor p = str_table['A' - 10 + num]; 870202719Sgabor else 871202719Sgabor errx(1, "internal error: break num > 15"); 872202719Sgabor return (node(cs(" "), cs(p), END_NODE)); 873202719Sgabor} 874202719Sgabor 875202719Sgabor 876202719Sgaborstatic ssize_t 877202719Sgaborlookup(char * str, size_t len, char type) 878202719Sgabor{ 879203443Sgabor ENTRY entry, *found; 880203443Sgabor u_char *p; 881203443Sgabor u_short num; 882202719Sgabor 883202719Sgabor /* The scanner allocated an extra byte already */ 884202719Sgabor if (str[len-1] != type) { 885202719Sgabor str[len] = type; 886202719Sgabor str[len+1] = '\0'; 887202719Sgabor } 888202719Sgabor entry.key = str; 889202719Sgabor found = hsearch(entry, FIND); 890202719Sgabor if (found == NULL) { 891202719Sgabor if (var_count == MAX_VARIABLES) 892202719Sgabor errx(1, "too many variables"); 893202719Sgabor p = malloc(4); 894202719Sgabor if (p == NULL) 895202719Sgabor err(1, NULL); 896202719Sgabor num = var_count++; 897202719Sgabor p[0] = 255; 898202719Sgabor p[1] = ENCODE(num / VAR_BASE + 1); 899202719Sgabor p[2] = ENCODE(num % VAR_BASE + 1); 900202719Sgabor p[3] = '\0'; 901202719Sgabor 902202719Sgabor entry.data = (char *)p; 903202719Sgabor entry.key = strdup(str); 904202719Sgabor if (entry.key == NULL) 905202719Sgabor err(1, NULL); 906202719Sgabor found = hsearch(entry, ENTER); 907202719Sgabor if (found == NULL) 908202719Sgabor err(1, NULL); 909202719Sgabor } 910202719Sgabor return (cs(found->data)); 911202719Sgabor} 912202719Sgabor 913202719Sgaborstatic ssize_t 914202719Sgaborletter_node(char *str) 915202719Sgabor{ 916203443Sgabor size_t len; 917202719Sgabor 918202719Sgabor len = strlen(str); 919202719Sgabor if (len == 1 && str[0] != '_') 920202719Sgabor return (cs(str_table[(int)str[0]])); 921202719Sgabor else 922202719Sgabor return (lookup(str, len, 'L')); 923202719Sgabor} 924202719Sgabor 925202719Sgaborstatic ssize_t 926202719Sgaborarray_node(char *str) 927202719Sgabor{ 928203443Sgabor size_t len; 929202719Sgabor 930202719Sgabor len = strlen(str); 931202719Sgabor if (len == 1 && str[0] != '_') 932202719Sgabor return (cs(str_table[(int)str[0] - 'a' + ARRAY_CHAR])); 933202719Sgabor else 934202719Sgabor return (lookup(str, len, 'A')); 935202719Sgabor} 936202719Sgabor 937202719Sgaborstatic ssize_t 938202719Sgaborfunction_node(char *str) 939202719Sgabor{ 940203443Sgabor size_t len; 941202719Sgabor 942202719Sgabor len = strlen(str); 943202719Sgabor if (len == 1 && str[0] != '_') 944202719Sgabor return (cs(str_table[(int)str[0] - 'a' + FUNC_CHAR])); 945202719Sgabor else 946202719Sgabor return (lookup(str, len, 'F')); 947202719Sgabor} 948202719Sgabor 949202719Sgaborstatic void 950202719Sgaboradd_par(ssize_t n) 951202719Sgabor{ 952203443Sgabor 953202719Sgabor prologue = node(cs("S"), n, prologue, END_NODE); 954202719Sgabor epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE); 955202719Sgabor} 956202719Sgabor 957202719Sgaborstatic void 958202719Sgaboradd_local(ssize_t n) 959202719Sgabor{ 960203443Sgabor 961202719Sgabor prologue = node(cs("0S"), n, prologue, END_NODE); 962202719Sgabor epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE); 963202719Sgabor} 964202719Sgabor 965202719Sgaborvoid 966202719Sgaboryyerror(const char *s) 967202719Sgabor{ 968203443Sgabor char *p, *str; 969203443Sgabor int n; 970202719Sgabor 971202719Sgabor if (yyin != NULL && feof(yyin)) 972202719Sgabor n = asprintf(&str, "%s: %s:%d: %s: unexpected EOF", 973202719Sgabor __progname, filename, lineno, s); 974202719Sgabor else if (isspace(yytext[0]) || !isprint(yytext[0])) 975202719Sgabor n = asprintf(&str, 976202719Sgabor "%s: %s:%d: %s: ascii char 0x%02x unexpected", 977202719Sgabor __progname, filename, lineno, s, yytext[0]); 978202719Sgabor else 979202719Sgabor n = asprintf(&str, "%s: %s:%d: %s: %s unexpected", 980202719Sgabor __progname, filename, lineno, s, yytext); 981202719Sgabor if (n == -1) 982202719Sgabor err(1, NULL); 983202719Sgabor 984202719Sgabor fputs("c[", stdout); 985202719Sgabor for (p = str; *p != '\0'; p++) { 986202719Sgabor if (*p == '[' || *p == ']' || *p =='\\') 987202719Sgabor putchar('\\'); 988202719Sgabor putchar(*p); 989202719Sgabor } 990202719Sgabor fputs("]pc\n", stdout); 991202719Sgabor free(str); 992202719Sgabor} 993202719Sgabor 994202719Sgaborvoid 995202719Sgaborfatal(const char *s) 996202719Sgabor{ 997203443Sgabor 998202719Sgabor errx(1, "%s:%d: %s", filename, lineno, s); 999202719Sgabor} 1000202719Sgabor 1001202719Sgaborstatic void 1002202719Sgaborwarning(const char *s) 1003202719Sgabor{ 1004203443Sgabor 1005202719Sgabor warnx("%s:%d: %s", filename, lineno, s); 1006202719Sgabor} 1007202719Sgabor 1008202719Sgaborstatic void 1009202719Sgaborinit(void) 1010202719Sgabor{ 1011203443Sgabor unsigned int i; 1012202719Sgabor 1013202719Sgabor for (i = 0; i < UCHAR_MAX; i++) { 1014202719Sgabor str_table[i][0] = i; 1015202719Sgabor str_table[i][1] = '\0'; 1016202719Sgabor } 1017202719Sgabor if (hcreate(1 << 16) == 0) 1018202719Sgabor err(1, NULL); 1019202719Sgabor} 1020202719Sgabor 1021202719Sgabor 1022202719Sgaborstatic void 1023202719Sgaborusage(void) 1024202719Sgabor{ 1025203443Sgabor 1026202845Sdelphij fprintf(stderr, "usage: %s [-chlqv] [-e expression] [file ...]\n", 1027202719Sgabor __progname); 1028202719Sgabor exit(1); 1029202719Sgabor} 1030202719Sgabor 1031202719Sgaborstatic char * 1032202719Sgaborescape(const char *str) 1033202719Sgabor{ 1034203443Sgabor char *p, *ret; 1035202719Sgabor 1036202719Sgabor ret = malloc(strlen(str) + 1); 1037202719Sgabor if (ret == NULL) 1038202719Sgabor err(1, NULL); 1039202719Sgabor 1040202719Sgabor p = ret; 1041202719Sgabor while (*str != '\0') { 1042202719Sgabor /* 1043202719Sgabor * We get _escaped_ strings here. Single backslashes are 1044202719Sgabor * already converted to double backslashes 1045202719Sgabor */ 1046202719Sgabor if (*str == '\\') { 1047202719Sgabor if (*++str == '\\') { 1048202719Sgabor switch (*++str) { 1049202719Sgabor case 'a': 1050202719Sgabor *p++ = '\a'; 1051202719Sgabor break; 1052202719Sgabor case 'b': 1053202719Sgabor *p++ = '\b'; 1054202719Sgabor break; 1055202719Sgabor case 'f': 1056202719Sgabor *p++ = '\f'; 1057202719Sgabor break; 1058202719Sgabor case 'n': 1059202719Sgabor *p++ = '\n'; 1060202719Sgabor break; 1061202719Sgabor case 'q': 1062202719Sgabor *p++ = '"'; 1063202719Sgabor break; 1064202719Sgabor case 'r': 1065202719Sgabor *p++ = '\r'; 1066202719Sgabor break; 1067202719Sgabor case 't': 1068202719Sgabor *p++ = '\t'; 1069202719Sgabor break; 1070202719Sgabor case '\\': 1071202719Sgabor *p++ = '\\'; 1072202719Sgabor break; 1073202719Sgabor } 1074202719Sgabor str++; 1075202719Sgabor } else { 1076202719Sgabor *p++ = '\\'; 1077202719Sgabor *p++ = *str++; 1078202719Sgabor } 1079202719Sgabor } else 1080202719Sgabor *p++ = *str++; 1081202719Sgabor } 1082202719Sgabor *p = '\0'; 1083202719Sgabor return (ret); 1084202719Sgabor} 1085202719Sgabor 1086202719Sgabor/* ARGSUSED */ 1087243075Seadlerstatic void 1088202719Sgaborsigchld(int signo) 1089202719Sgabor{ 1090203443Sgabor pid_t pid; 1091203443Sgabor int status; 1092202719Sgabor 1093202719Sgabor switch (signo) { 1094202719Sgabor default: 1095202719Sgabor for (;;) { 1096232994Skevlo pid = waitpid(dc, &status, WUNTRACED); 1097202719Sgabor if (pid == -1) { 1098202719Sgabor if (errno == EINTR) 1099202719Sgabor continue; 1100202719Sgabor _exit(0); 1101202719Sgabor } 1102202719Sgabor if (WIFEXITED(status) || WIFSIGNALED(status)) 1103202719Sgabor _exit(0); 1104202719Sgabor else 1105202719Sgabor break; 1106202719Sgabor } 1107202719Sgabor } 1108202719Sgabor} 1109202719Sgabor 1110203498Sdelphijstatic const char * 1111203498Sdelphijdummy_prompt(void) 1112203498Sdelphij{ 1113203498Sdelphij 1114203498Sdelphij return (""); 1115203498Sdelphij} 1116203498Sdelphij 1117202719Sgaborint 1118202719Sgabormain(int argc, char *argv[]) 1119202719Sgabor{ 1120203443Sgabor char *q; 1121203443Sgabor int p[2]; 1122203443Sgabor int ch, i; 1123202719Sgabor 1124202719Sgabor init(); 1125202719Sgabor setlinebuf(stdout); 1126202719Sgabor 1127202719Sgabor sargv = malloc(argc * sizeof(char *)); 1128202719Sgabor if (sargv == NULL) 1129202719Sgabor err(1, NULL); 1130202719Sgabor 1131202719Sgabor if ((cmdexpr = strdup("")) == NULL) 1132202719Sgabor err(1, NULL); 1133202719Sgabor /* The d debug option is 4.4 BSD bc(1) compatible */ 1134202719Sgabor while ((ch = getopt_long(argc, argv, "cde:hlqv", 1135202719Sgabor long_options, NULL)) != -1) { 1136202719Sgabor switch (ch) { 1137202719Sgabor case 'c': 1138202719Sgabor case 'd': 1139202719Sgabor do_fork = false; 1140202719Sgabor break; 1141202719Sgabor case 'e': 1142202719Sgabor q = cmdexpr; 1143202719Sgabor if (asprintf(&cmdexpr, "%s%s\n", cmdexpr, optarg) == -1) 1144202719Sgabor err(1, NULL); 1145202719Sgabor free(q); 1146202719Sgabor break; 1147202719Sgabor case 'h': 1148202719Sgabor usage(); 1149202719Sgabor break; 1150202719Sgabor case 'l': 1151202719Sgabor sargv[sargc++] = _PATH_LIBB; 1152202719Sgabor break; 1153202719Sgabor case 'q': 1154202719Sgabor /* compatibility option */ 1155202719Sgabor break; 1156202719Sgabor case 'v': 1157202719Sgabor fprintf(stderr, "%s (BSD bc) %s\n", __progname, BC_VER); 1158202719Sgabor exit(0); 1159202719Sgabor break; 1160202719Sgabor default: 1161202719Sgabor usage(); 1162202719Sgabor } 1163202719Sgabor } 1164202719Sgabor 1165202719Sgabor argc -= optind; 1166202719Sgabor argv += optind; 1167202719Sgabor 1168202719Sgabor interactive = isatty(STDIN_FILENO); 1169202719Sgabor for (i = 0; i < argc; i++) 1170202719Sgabor sargv[sargc++] = argv[i]; 1171202719Sgabor 1172202719Sgabor if (do_fork) { 1173202719Sgabor if (pipe(p) == -1) 1174202719Sgabor err(1, "cannot create pipe"); 1175202719Sgabor dc = fork(); 1176202719Sgabor if (dc == -1) 1177202719Sgabor err(1, "cannot fork"); 1178202719Sgabor else if (dc != 0) { 1179202719Sgabor signal(SIGCHLD, sigchld); 1180202719Sgabor close(STDOUT_FILENO); 1181202719Sgabor dup(p[1]); 1182202719Sgabor close(p[0]); 1183202719Sgabor close(p[1]); 1184202719Sgabor } else { 1185202719Sgabor close(STDIN_FILENO); 1186202719Sgabor dup(p[0]); 1187202719Sgabor close(p[0]); 1188202719Sgabor close(p[1]); 1189202719Sgabor execl(_PATH_DC, "dc", "-x", (char *)NULL); 1190202719Sgabor err(1, "cannot find dc"); 1191202719Sgabor } 1192202719Sgabor } 1193232994Skevlo if (interactive) { 1194232994Skevlo el = el_init("bc", stdin, stderr, stderr); 1195232994Skevlo hist = history_init(); 1196232994Skevlo history(hist, &he, H_SETSIZE, 100); 1197232994Skevlo el_set(el, EL_HIST, history, hist); 1198232994Skevlo el_set(el, EL_EDITOR, "emacs"); 1199232994Skevlo el_set(el, EL_SIGNAL, 1); 1200232994Skevlo el_set(el, EL_PROMPT, dummy_prompt); 1201232994Skevlo el_source(el, NULL); 1202232994Skevlo } 1203202719Sgabor yywrap(); 1204202719Sgabor return (yyparse()); 1205202719Sgabor} 1206