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