Switched back to using pthread_create versus lwp_create.
[dragonfly/vkernel-mp.git] / usr.bin / bc / bc.y
blob2a3ac240c89f95dc1fba2fa2860065fe44fc9b44
1 %{
2 /*
3 * $OpenBSD: bc.y,v 1.25 2005/03/17 16:59:31 otto Exp $
4 * $DragonFly: src/usr.bin/bc/bc.y,v 1.2 2005/04/21 20:50:22 swildner Exp $
5 */
7 /*
8 * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
14 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
20 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 * This implementation of bc(1) uses concepts from the original 4.4
25 * BSD bc(1). The code itself is a complete rewrite, based on the
26 * Posix defined bc(1) grammar. Other differences include type safe
27 * usage of pointers to build the tree of emitted code, typed yacc
28 * rule values, dynamic allocation of all data structures and a
29 * completely rewritten lexical analyzer using lex(1).
31 * Some effort has been made to make sure that the generated code is
32 * the same as the code generated by the older version, to provide
33 * easy regression testing.
36 #include <ctype.h>
37 #include <err.h>
38 #include <limits.h>
39 #include <search.h>
40 #include <signal.h>
41 #include <stdarg.h>
42 #include <stdbool.h>
43 #include <string.h>
44 #include <unistd.h>
46 #include "extern.h"
47 #include "pathnames.h"
49 #define END_NODE ((ssize_t) -1)
50 #define CONST_STRING ((ssize_t) -2)
51 #define ALLOC_STRING ((ssize_t) -3)
53 struct tree {
54 ssize_t index;
55 union {
56 char *astr;
57 const char *cstr;
58 } u;
61 int yyparse(void);
62 int yywrap(void);
64 int fileindex;
65 int sargc;
66 char **sargv;
67 char *filename;
68 char *cmdexpr;
70 static void grow(void);
71 static ssize_t cs(const char *);
72 static ssize_t as(const char *);
73 static ssize_t node(ssize_t, ...);
74 static void emit(ssize_t);
75 static void emit_macro(int, ssize_t);
76 static void free_tree(void);
77 static ssize_t numnode(int);
78 static ssize_t lookup(char *, size_t, char);
79 static ssize_t letter_node(char *);
80 static ssize_t array_node(char *);
81 static ssize_t function_node(char *);
83 static void add_par(ssize_t);
84 static void add_local(ssize_t);
85 static void warning(const char *);
86 static void init(void);
87 static __dead2 void usage(void);
88 static char *escape(const char *);
90 static size_t instr_sz = 0;
91 static struct tree *instructions = NULL;
92 static ssize_t current = 0;
93 static int macro_char = '0';
94 static int reset_macro_char = '0';
95 static int nesting = 0;
96 static int breakstack[16];
97 static int breaksp = 0;
98 static ssize_t prologue;
99 static ssize_t epilogue;
100 static bool st_has_continue;
101 static char str_table[UCHAR_MAX][2];
102 static bool do_fork = true;
103 static u_short var_count;
105 extern char *__progname;
107 #define BREAKSTACK_SZ (sizeof(breakstack)/sizeof(breakstack[0]))
109 /* These values are 4.4BSD bc compatible */
110 #define FUNC_CHAR 0x01
111 #define ARRAY_CHAR 0xa1
113 /* Skip '\0', [, \ and ] */
114 #define ENCODE(c) ((c) < '[' ? (c) : (c) + 3);
115 #define VAR_BASE (256-4)
116 #define MAX_VARIABLES (VAR_BASE * VAR_BASE)
120 %start program
122 %union {
123 ssize_t node;
124 struct lvalue lvalue;
125 const char *str;
126 char *astr;
129 %token COMMA SEMICOLON LPAR RPAR LBRACE RBRACE LBRACKET RBRACKET DOT
130 %token NEWLINE
131 %token <astr> LETTER
132 %token <str> NUMBER STRING
133 %token DEFINE BREAK QUIT LENGTH
134 %token RETURN FOR IF WHILE SQRT
135 %token SCALE IBASE OBASE AUTO
136 %token CONTINUE ELSE PRINT
138 %left BOOL_OR
139 %left BOOL_AND
140 %nonassoc BOOL_NOT
141 %nonassoc EQUALS LESS_EQ GREATER_EQ UNEQUALS LESS GREATER
142 %right <str> ASSIGN_OP
143 %left PLUS MINUS
144 %left MULTIPLY DIVIDE REMAINDER
145 %right EXPONENT
146 %nonassoc UMINUS
147 %nonassoc INCR DECR
149 %type <lvalue> named_expression
150 %type <node> argument_list
151 %type <node> alloc_macro
152 %type <node> expression
153 %type <node> function
154 %type <node> function_header
155 %type <node> input_item
156 %type <node> opt_argument_list
157 %type <node> opt_expression
158 %type <node> opt_relational_expression
159 %type <node> opt_statement
160 %type <node> print_expression
161 %type <node> print_expression_list
162 %type <node> relational_expression
163 %type <node> return_expression
164 %type <node> semicolon_list
165 %type <node> statement
166 %type <node> statement_list
170 program : /* empty */
171 | program input_item
174 input_item : semicolon_list NEWLINE
176 emit($1);
177 macro_char = reset_macro_char;
178 putchar('\n');
179 free_tree();
180 st_has_continue = false;
182 | function
184 putchar('\n');
185 free_tree();
186 st_has_continue = false;
188 | error NEWLINE
190 yyerrok;
192 | error QUIT
194 yyerrok;
198 semicolon_list : /* empty */
200 $$ = cs("");
202 | statement
203 | semicolon_list SEMICOLON statement
205 $$ = node($1, $3, END_NODE);
207 | semicolon_list SEMICOLON
210 statement_list : /* empty */
212 $$ = cs("");
214 | statement
215 | statement_list NEWLINE
216 | statement_list NEWLINE statement
218 $$ = node($1, $3, END_NODE);
220 | statement_list SEMICOLON
221 | statement_list SEMICOLON statement
223 $$ = node($1, $3, END_NODE);
228 opt_statement : /* empty */
230 $$ = cs("");
232 | statement
235 statement : expression
237 $$ = node($1, cs("ps."), END_NODE);
239 | named_expression ASSIGN_OP expression
241 if ($2[0] == '\0')
242 $$ = node($3, cs($2), $1.store,
243 END_NODE);
244 else
245 $$ = node($1.load, $3, cs($2), $1.store,
246 END_NODE);
248 | STRING
250 $$ = node(cs("["), as($1),
251 cs("]P"), END_NODE);
253 | BREAK
255 if (breaksp == 0) {
256 warning("break not in for or while");
257 YYERROR;
258 } else {
259 $$ = node(
260 numnode(nesting -
261 breakstack[breaksp-1]),
262 cs("Q"), END_NODE);
265 | CONTINUE
267 if (breaksp == 0) {
268 warning("continue not in for or while");
269 YYERROR;
270 } else {
271 st_has_continue = true;
272 $$ = node(numnode(nesting -
273 breakstack[breaksp-1] - 1),
274 cs("J"), END_NODE);
277 | QUIT
279 putchar('q');
280 fflush(stdout);
281 exit(0);
283 | RETURN return_expression
285 if (nesting == 0) {
286 warning("return must be in a function");
287 YYERROR;
289 $$ = $2;
291 | FOR LPAR alloc_macro opt_expression SEMICOLON
292 opt_relational_expression SEMICOLON
293 opt_expression RPAR opt_statement pop_nesting
295 ssize_t n;
297 if (st_has_continue)
298 n = node($10, cs("M"), $8, cs("s."),
299 $6, $3, END_NODE);
300 else
301 n = node($10, $8, cs("s."), $6, $3,
302 END_NODE);
304 emit_macro($3, n);
305 $$ = node($4, cs("s."), $6, $3, cs(" "),
306 END_NODE);
308 | IF LPAR alloc_macro pop_nesting relational_expression RPAR
309 opt_statement
311 emit_macro($3, $7);
312 $$ = node($5, $3, cs(" "), END_NODE);
314 | IF LPAR alloc_macro pop_nesting relational_expression RPAR
315 opt_statement ELSE alloc_macro pop_nesting opt_statement
317 emit_macro($3, $7);
318 emit_macro($9, $11);
319 $$ = node($5, $3, cs("e"), $9, cs(" "),
320 END_NODE);
322 | WHILE LPAR alloc_macro relational_expression RPAR
323 opt_statement pop_nesting
325 ssize_t n;
327 if (st_has_continue)
328 n = node($6, cs("M"), $4, $3, END_NODE);
329 else
330 n = node($6, $4, $3, END_NODE);
331 emit_macro($3, n);
332 $$ = node($4, $3, cs(" "), END_NODE);
334 | LBRACE statement_list RBRACE
336 $$ = $2;
338 | PRINT print_expression_list
340 $$ = $2;
344 alloc_macro : /* empty */
346 $$ = cs(str_table[macro_char]);
347 macro_char++;
348 /* Do not use [, \ and ] */
349 if (macro_char == '[')
350 macro_char += 3;
351 /* skip letters */
352 else if (macro_char == 'a')
353 macro_char = '{';
354 else if (macro_char == ARRAY_CHAR)
355 macro_char += 26;
356 else if (macro_char == 255)
357 fatal("program too big");
358 if (breaksp == BREAKSTACK_SZ)
359 fatal("nesting too deep");
360 breakstack[breaksp++] = nesting++;
364 pop_nesting : /* empty */
366 breaksp--;
370 function : function_header opt_parameter_list RPAR opt_newline
371 LBRACE NEWLINE opt_auto_define_list
372 statement_list RBRACE
374 int n = node(prologue, $8, epilogue,
375 cs("0"), numnode(nesting),
376 cs("Q"), END_NODE);
377 emit_macro($1, n);
378 reset_macro_char = macro_char;
379 nesting = 0;
380 breaksp = 0;
384 function_header : DEFINE LETTER LPAR
386 $$ = function_node($2);
387 free($2);
388 prologue = cs("");
389 epilogue = cs("");
390 nesting = 1;
391 breaksp = 0;
392 breakstack[breaksp] = 0;
396 opt_newline : /* empty */
397 | NEWLINE
400 opt_parameter_list
401 : /* empty */
402 | parameter_list
406 parameter_list : LETTER
408 add_par(letter_node($1));
409 free($1);
411 | LETTER LBRACKET RBRACKET
413 add_par(array_node($1));
414 free($1);
416 | parameter_list COMMA LETTER
418 add_par(letter_node($3));
419 free($3);
421 | parameter_list COMMA LETTER LBRACKET RBRACKET
423 add_par(array_node($3));
424 free($3);
430 opt_auto_define_list
431 : /* empty */
432 | AUTO define_list NEWLINE
433 | AUTO define_list SEMICOLON
437 define_list : LETTER
439 add_local(letter_node($1));
440 free($1);
442 | LETTER LBRACKET RBRACKET
444 add_local(array_node($1));
445 free($1);
447 | define_list COMMA LETTER
449 add_local(letter_node($3));
450 free($3);
452 | define_list COMMA LETTER LBRACKET RBRACKET
454 add_local(array_node($3));
455 free($3);
460 opt_argument_list
461 : /* empty */
463 $$ = cs("");
465 | argument_list
469 argument_list : expression
470 | argument_list COMMA expression
472 $$ = node($1, $3, END_NODE);
474 | argument_list COMMA LETTER LBRACKET RBRACKET
476 $$ = node($1, cs("l"), array_node($3),
477 END_NODE);
478 free($3);
482 opt_relational_expression
483 : /* empty */
485 $$ = cs(" 0 0=");
487 | relational_expression
490 relational_expression
491 : expression EQUALS expression
493 $$ = node($1, $3, cs("="), END_NODE);
495 | expression UNEQUALS expression
497 $$ = node($1, $3, cs("!="), END_NODE);
499 | expression LESS expression
501 $$ = node($1, $3, cs(">"), END_NODE);
503 | expression LESS_EQ expression
505 $$ = node($1, $3, cs("!<"), END_NODE);
507 | expression GREATER expression
509 $$ = node($1, $3, cs("<"), END_NODE);
511 | expression GREATER_EQ expression
513 $$ = node($1, $3, cs("!>"), END_NODE);
515 | expression
517 $$ = node($1, cs(" 0!="), END_NODE);
522 return_expression
523 : /* empty */
525 $$ = node(cs("0"), epilogue,
526 numnode(nesting), cs("Q"), END_NODE);
528 | expression
530 $$ = node($1, epilogue,
531 numnode(nesting), cs("Q"), END_NODE);
533 | LPAR RPAR
535 $$ = node(cs("0"), epilogue,
536 numnode(nesting), cs("Q"), END_NODE);
541 opt_expression : /* empty */
543 $$ = cs(" 0");
545 | expression
548 expression : named_expression
550 $$ = node($1.load, END_NODE);
552 | DOT {
553 $$ = node(cs("l."), END_NODE);
555 | NUMBER
557 $$ = node(cs(" "), as($1), END_NODE);
559 | LPAR expression RPAR
561 $$ = $2;
563 | LETTER LPAR opt_argument_list RPAR
565 $$ = node($3, cs("l"),
566 function_node($1), cs("x"),
567 END_NODE);
568 free($1);
570 | MINUS expression %prec UMINUS
572 $$ = node(cs(" 0"), $2, cs("-"),
573 END_NODE);
575 | expression PLUS expression
577 $$ = node($1, $3, cs("+"), END_NODE);
579 | expression MINUS expression
581 $$ = node($1, $3, cs("-"), END_NODE);
583 | expression MULTIPLY expression
585 $$ = node($1, $3, cs("*"), END_NODE);
587 | expression DIVIDE expression
589 $$ = node($1, $3, cs("/"), END_NODE);
591 | expression REMAINDER expression
593 $$ = node($1, $3, cs("%"), END_NODE);
595 | expression EXPONENT expression
597 $$ = node($1, $3, cs("^"), END_NODE);
599 | INCR named_expression
601 $$ = node($2.load, cs("1+d"), $2.store,
602 END_NODE);
604 | DECR named_expression
606 $$ = node($2.load, cs("1-d"),
607 $2.store, END_NODE);
609 | named_expression INCR
611 $$ = node($1.load, cs("d1+"),
612 $1.store, END_NODE);
614 | named_expression DECR
616 $$ = node($1.load, cs("d1-"),
617 $1.store, END_NODE);
619 | named_expression ASSIGN_OP expression
621 if ($2[0] == '\0')
622 $$ = node($3, cs($2), cs("d"), $1.store,
623 END_NODE);
624 else
625 $$ = node($1.load, $3, cs($2), cs("d"),
626 $1.store, END_NODE);
628 | LENGTH LPAR expression RPAR
630 $$ = node($3, cs("Z"), END_NODE);
632 | SQRT LPAR expression RPAR
634 $$ = node($3, cs("v"), END_NODE);
636 | SCALE LPAR expression RPAR
638 $$ = node($3, cs("X"), END_NODE);
640 | BOOL_NOT expression
642 $$ = node($2, cs("N"), END_NODE);
644 | expression BOOL_AND alloc_macro pop_nesting expression
646 ssize_t n = node(cs("R"), $5, END_NODE);
647 emit_macro($3, n);
648 $$ = node($1, cs("d0!="), $3, END_NODE);
650 | expression BOOL_OR alloc_macro pop_nesting expression
652 ssize_t n = node(cs("R"), $5, END_NODE);
653 emit_macro($3, n);
654 $$ = node($1, cs("d0="), $3, END_NODE);
656 | expression EQUALS expression
658 $$ = node($1, $3, cs("G"), END_NODE);
660 | expression UNEQUALS expression
662 $$ = node($1, $3, cs("GN"), END_NODE);
664 | expression LESS expression
666 $$ = node($3, $1, cs("("), END_NODE);
668 | expression LESS_EQ expression
670 $$ = node($3, $1, cs("{"), END_NODE);
672 | expression GREATER expression
674 $$ = node($1, $3, cs("("), END_NODE);
676 | expression GREATER_EQ expression
678 $$ = node($1, $3, cs("{"), END_NODE);
682 named_expression
683 : LETTER
685 $$.load = node(cs("l"), letter_node($1),
686 END_NODE);
687 $$.store = node(cs("s"), letter_node($1),
688 END_NODE);
689 free($1);
691 | LETTER LBRACKET expression RBRACKET
693 $$.load = node($3, cs(";"),
694 array_node($1), END_NODE);
695 $$.store = node($3, cs(":"),
696 array_node($1), END_NODE);
697 free($1);
699 | SCALE
701 $$.load = cs("K");
702 $$.store = cs("k");
704 | IBASE
706 $$.load = cs("I");
707 $$.store = cs("i");
709 | OBASE
711 $$.load = cs("O");
712 $$.store = cs("o");
716 print_expression_list
717 : print_expression
718 | print_expression_list COMMA print_expression
720 $$ = node($1, $3, END_NODE);
723 print_expression
724 : expression
726 $$ = node($1, cs("ds.n"), END_NODE);
728 | STRING
730 char *p = escape($1);
731 $$ = node(cs("["), as(p), cs("]n"), END_NODE);
732 free(p);
737 static void
738 grow(void)
740 struct tree *p;
741 int newsize;
743 if (current == instr_sz) {
744 newsize = instr_sz * 2 + 1;
745 p = realloc(instructions, newsize * sizeof(*p));
746 if (p == NULL) {
747 free(instructions);
748 err(1, NULL);
750 instructions = p;
751 instr_sz = newsize;
755 static ssize_t
756 cs(const char *str)
758 grow();
759 instructions[current].index = CONST_STRING;
760 instructions[current].u.cstr = str;
761 return current++;
764 static ssize_t
765 as(const char *str)
767 grow();
768 instructions[current].index = ALLOC_STRING;
769 instructions[current].u.astr = strdup(str);
770 if (instructions[current].u.astr == NULL)
771 err(1, NULL);
772 return current++;
775 static ssize_t
776 node(ssize_t arg, ...)
778 va_list ap;
779 ssize_t ret;
781 va_start(ap, arg);
783 ret = current;
784 grow();
785 instructions[current++].index = arg;
787 do {
788 arg = va_arg(ap, ssize_t);
789 grow();
790 instructions[current++].index = arg;
791 } while (arg != END_NODE);
793 va_end(ap);
794 return ret;
797 static void
798 emit(ssize_t i)
800 if (instructions[i].index >= 0)
801 while (instructions[i].index != END_NODE)
802 emit(instructions[i++].index);
803 else
804 fputs(instructions[i].u.cstr, stdout);
807 static void
808 emit_macro(int node, ssize_t code)
810 putchar('[');
811 emit(code);
812 printf("]s%s\n", instructions[node].u.cstr);
813 nesting--;
816 static void
817 free_tree(void)
819 size_t i;
821 for (i = 0; i < current; i++)
822 if (instructions[i].index == ALLOC_STRING)
823 free(instructions[i].u.astr);
824 current = 0;
827 static ssize_t
828 numnode(int num)
830 const char *p;
832 if (num < 10)
833 p = str_table['0' + num];
834 else if (num < 16)
835 p = str_table['A' - 10 + num];
836 else
837 errx(1, "internal error: break num > 15");
838 return node(cs(" "), cs(p), END_NODE);
842 static ssize_t
843 lookup(char * str, size_t len, char type)
845 ENTRY entry, *found;
846 u_short num;
847 u_char *p;
849 /* The scanner allocated an extra byte already */
850 if (str[len-1] != type) {
851 str[len] = type;
852 str[len+1] = '\0';
854 entry.key = str;
855 found = hsearch(entry, FIND);
856 if (found == NULL) {
857 if (var_count == MAX_VARIABLES)
858 errx(1, "too many variables");
859 p = malloc(4);
860 if (p == NULL)
861 err(1, NULL);
862 num = var_count++;
863 p[0] = 255;
864 p[1] = ENCODE(num / VAR_BASE + 1);
865 p[2] = ENCODE(num % VAR_BASE + 1);
866 p[3] = '\0';
868 entry.data = (char *)p;
869 entry.key = strdup(str);
870 if (entry.key == NULL)
871 err(1, NULL);
872 found = hsearch(entry, ENTER);
873 if (found == NULL)
874 err(1, NULL);
876 return cs(found->data);
879 static ssize_t
880 letter_node(char *str)
882 size_t len;
884 len = strlen(str);
885 if (len == 1 && str[0] != '_')
886 return cs(str_table[(int)str[0]]);
887 else
888 return lookup(str, len, 'L');
891 static ssize_t
892 array_node(char *str)
894 size_t len;
896 len = strlen(str);
897 if (len == 1 && str[0] != '_')
898 return cs(str_table[(int)str[0] - 'a' + ARRAY_CHAR]);
899 else
900 return lookup(str, len, 'A');
903 static ssize_t
904 function_node(char *str)
906 size_t len;
908 len = strlen(str);
909 if (len == 1 && str[0] != '_')
910 return cs(str_table[(int)str[0] - 'a' + FUNC_CHAR]);
911 else
912 return lookup(str, len, 'F');
915 static void
916 add_par(ssize_t n)
918 prologue = node(cs("S"), n, prologue, END_NODE);
919 epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE);
922 static void
923 add_local(ssize_t n)
925 prologue = node(cs("0S"), n, prologue, END_NODE);
926 epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE);
929 void
930 yyerror(char *s)
932 char *str, *p;
934 if (feof(yyin))
935 asprintf(&str, "%s: %s:%d: %s: unexpected EOF",
936 __progname, filename, lineno, s);
937 else if (isspace(yytext[0]) || !isprint(yytext[0]))
938 asprintf(&str, "%s: %s:%d: %s: ascii char 0x%02x unexpected",
939 __progname, filename, lineno, s, yytext[0]);
940 else
941 asprintf(&str, "%s: %s:%d: %s: %s unexpected",
942 __progname, filename, lineno, s, yytext);
943 if (str == NULL)
944 err(1, NULL);
946 fputs("c[", stdout);
947 for (p = str; *p != '\0'; p++) {
948 if (*p == '[' || *p == ']' || *p =='\\')
949 putchar('\\');
950 putchar(*p);
952 fputs("]pc\n", stdout);
953 free(str);
956 void
957 fatal(const char *s)
959 errx(1, "%s:%d: %s", filename, lineno, s);
962 static void
963 warning(const char *s)
965 warnx("%s:%d: %s", filename, lineno, s);
968 static void
969 init(void)
971 int i;
973 for (i = 0; i < UCHAR_MAX; i++) {
974 str_table[i][0] = i;
975 str_table[i][1] = '\0';
977 if (hcreate(1 << 16) == 0)
978 err(1, NULL);
982 static __dead2 void
983 usage(void)
985 fprintf(stderr, "%s: usage: [-cl] [-e expression] [file ...]\n",
986 __progname);
987 exit(1);
990 static char *
991 escape(const char *str)
993 char *ret, *p;
995 ret = malloc(strlen(str) + 1);
996 if (ret == NULL)
997 err(1, NULL);
999 p = ret;
1000 while (*str != '\0') {
1002 * We get _escaped_ strings here. Single backslashes are
1003 * already converted to double backslashes
1005 if (*str == '\\') {
1006 if (*++str == '\\') {
1007 switch (*++str) {
1008 case 'a':
1009 *p++ = '\a';
1010 break;
1011 case 'b':
1012 *p++ = '\b';
1013 break;
1014 case 'f':
1015 *p++ = '\f';
1016 break;
1017 case 'n':
1018 *p++ = '\n';
1019 break;
1020 case 'q':
1021 *p++ = '"';
1022 break;
1023 case 'r':
1024 *p++ = '\r';
1025 break;
1026 case 't':
1027 *p++ = '\t';
1028 break;
1029 case '\\':
1030 *p++ = '\\';
1031 break;
1033 str++;
1034 } else {
1035 *p++ = '\\';
1036 *p++ = *str++;
1038 } else
1039 *p++ = *str++;
1041 *p = '\0';
1042 return ret;
1046 main(int argc, char *argv[])
1048 int i, ch, ret;
1049 int p[2];
1050 char *q;
1052 init();
1053 setlinebuf(stdout);
1055 sargv = malloc(argc * sizeof(char *));
1056 if (sargv == NULL)
1057 err(1, NULL);
1059 if ((cmdexpr = strdup("")) == NULL)
1060 err(1, NULL);
1061 /* The d debug option is 4.4 BSD bc(1) compatible */
1062 while ((ch = getopt(argc, argv, "cde:l")) != -1) {
1063 switch (ch) {
1064 case 'c':
1065 case 'd':
1066 do_fork = false;
1067 break;
1068 case 'e':
1069 q = cmdexpr;
1070 if (asprintf(&cmdexpr, "%s%s\n", cmdexpr, optarg) == -1)
1071 err(1, NULL);
1072 free(q);
1073 break;
1074 case 'l':
1075 sargv[sargc++] = _PATH_LIBB;
1076 break;
1077 default:
1078 usage();
1082 argc -= optind;
1083 argv += optind;
1085 for (i = 0; i < argc; i++)
1086 sargv[sargc++] = argv[i];
1088 if (do_fork) {
1089 if (pipe(p) == -1)
1090 err(1, "cannot create pipe");
1091 ret = fork();
1092 if (ret == -1)
1093 err(1, "cannot fork");
1094 else if (ret == 0) {
1095 close(STDOUT_FILENO);
1096 dup(p[1]);
1097 close(p[0]);
1098 close(p[1]);
1099 } else {
1100 close(STDIN_FILENO);
1101 dup(p[0]);
1102 close(p[0]);
1103 close(p[1]);
1104 execl(_PATH_DC, "dc", "-x", (char *)NULL);
1105 err(1, "cannot find dc");
1108 signal(SIGINT, abort_line);
1109 yywrap();
1110 return yyparse();