Annotation of src/usr.bin/bc/bc.y, Revision 1.13
1.1 otto 1: %{
1.13 ! otto 2: /* $OpenBSD: bc.y,v 1.12 2003/10/18 20:35:36 otto Exp $ */
1.1 otto 3:
4: /*
5: * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
6: *
7: * Permission to use, copy, modify, and distribute this software for any
8: * purpose with or without fee is hereby granted, provided that the above
9: * copyright notice and this permission notice appear in all copies.
10: *
11: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18: */
19:
20: /*
21: * This implementation of bc(1) uses concepts from the original 4.4
22: * BSD bc(1). The code itself is a complete rewrite, based on the
23: * Posix defined bc(1) grammar. Other differences include type safe
24: * usage of pointers to build the tree of emitted code, typed yacc
25: * rule values, dynamic allocation of all data structures and a
26: * completely rewritten lexical analyzer using lex(1).
27: *
28: * Some effort has been made to make sure that the generated code is
29: * the same as the code generated by the older version, to provide
30: * easy regression testing.
31: */
32:
33: #ifndef lint
1.13 ! otto 34: static const char rcsid[] = "$OpenBSD: bc.y,v 1.12 2003/10/18 20:35:36 otto Exp $";
1.1 otto 35: #endif /* not lint */
36:
37: #include <ctype.h>
38: #include <err.h>
39: #include <limits.h>
40: #include <signal.h>
41: #include <stdarg.h>
42: #include <stdbool.h>
43: #include <string.h>
44: #include <unistd.h>
45:
46: #include "extern.h"
47: #include "pathnames.h"
48:
49: #define END_NODE ((ssize_t) -1)
50: #define CONST_STRING ((ssize_t) -2)
51: #define ALLOC_STRING ((ssize_t) -3)
52:
53: struct tree {
54: ssize_t index;
55: union {
56: char *astr;
57: const char *cstr;
58: } u;
59: };
60:
61: int yyparse(void);
62: int yywrap(void);
63:
64: static void grow(void);
65: static ssize_t cs(const char *);
66: static ssize_t as(const char *);
67: static ssize_t node(ssize_t, ...);
68: static void emit(ssize_t);
69: static void emit_macro(int, ssize_t);
70: static void free_tree(void);
71: static ssize_t numnode(int);
72: static void add_par(ssize_t);
73: static void add_local(ssize_t);
74: static void warning(const char *);
75: static void init(void);
76: static __dead void usage(void);
77:
78: static size_t instr_sz = 0;
79: static struct tree *instructions = NULL;
1.7 otto 80: static ssize_t current = 0;
1.1 otto 81: static int macro_char = '0';
82: static int reset_macro_char = '0';
83: static int nesting = 0;
84: static int breakstack[16];
85: static int breaksp = 0;
86: static ssize_t prologue;
87: static ssize_t epilogue;
1.11 otto 88: static bool st_has_continue;
1.1 otto 89: static char str_table[UCHAR_MAX][2];
90: static int sargc;
91: static char **sargv;
92: static char *filename;
93: static bool do_fork = true;
94:
95: extern char *__progname;
96:
97: #define BREAKSTACK_SZ (sizeof(breakstack)/sizeof(breakstack[0]))
98:
99: /* These values are 4.4BSD dc compatible */
100: #define FUNC_CHAR 0x01
101: #define ARRAY_CHAR 0xa1
102:
103: #define LETTER_NODE(str) (cs(str_table[(int)str[0]]))
104: #define ARRAY_NODE(str) (cs(str_table[(int)str[0] - 'a' + ARRAY_CHAR]))
105: #define FUNCTION_NODE(str) (cs(str_table[(int)str[0] - 'a' + FUNC_CHAR]))
106:
107: %}
108:
109: %start program
110:
111: %union {
112: ssize_t node;
113: struct lvalue lvalue;
114: const char *str;
115: }
116:
1.9 otto 117: %token COMMA SEMICOLON LPAR RPAR LBRACE RBRACE LBRACKET RBRACKET DOT
118: %token NEWLINE
1.1 otto 119: %token <str> LETTER NUMBER STRING
120: %token DEFINE BREAK QUIT LENGTH
121: %token RETURN FOR IF WHILE SQRT
122: %token SCALE IBASE OBASE AUTO
1.11 otto 123: %token CONTINUE ELSE
1.1 otto 124:
125: %nonassoc EQUALS LESS_EQ GREATER_EQ UNEQUALS LESS GREATER
126: %right <str> ASSIGN_OP
127: %left PLUS MINUS
128: %left MULTIPLY DIVIDE REMAINDER
129: %left EXPONENT
130: %nonassoc UMINUS
131: %nonassoc INCR DECR
132:
133: %type <lvalue> named_expression
134: %type <node> argument_list
135: %type <node> alloc_macro
136: %type <node> expression
137: %type <node> function
138: %type <node> function_header
139: %type <node> input_item
140: %type <node> opt_argument_list
1.13 ! otto 141: %type <node> opt_expression
! 142: %type <node> opt_relational_expression
1.1 otto 143: %type <node> opt_statement
144: %type <node> relational_expression
145: %type <node> return_expression
146: %type <node> semicolon_list
147: %type <node> statement
148: %type <node> statement_list
149:
150: %%
151:
152: program : /* empty */
153: {
154: putchar('q');
155: fflush(stdout);
156: exit(0);
157: }
158: | input_item program
159: ;
160:
161: input_item : semicolon_list NEWLINE
162: {
163: emit($1);
164: macro_char = reset_macro_char;
165: putchar('\n');
166: free_tree();
1.11 otto 167: st_has_continue = false;
1.1 otto 168: }
169: | function
170: {
171: putchar('\n');
172: free_tree();
1.11 otto 173: st_has_continue = false;
1.1 otto 174: }
1.8 otto 175: | error NEWLINE
1.1 otto 176: {
1.8 otto 177: yyerrok;
1.1 otto 178: }
179: ;
180:
181: semicolon_list : /* empty */
182: {
183: $$ = cs("");
184: }
185: | statement
186: | semicolon_list SEMICOLON statement
187: {
188: $$ = node($1, $3, END_NODE);
189: }
190: | semicolon_list SEMICOLON
191: ;
192:
193: statement_list : /* empty */
194: {
195: $$ = cs("");
196: }
197: | statement
198: | statement_list NEWLINE
199: | statement_list NEWLINE statement
200: {
201: $$ = node($1, $3, END_NODE);
202: }
203: | statement_list SEMICOLON
204: | statement_list SEMICOLON statement
205: {
206: $$ = node($1, $3, END_NODE);
207: }
208: ;
209:
210:
211: opt_statement : /* empty */
212: {
213: $$ = cs("");
214: }
215: | statement
216: ;
217:
218: statement : expression
219: {
220: $$ = node($1, cs("ps."), END_NODE);
221: }
222: | named_expression ASSIGN_OP expression
223: {
1.11 otto 224: if ($2[0] == '\0')
225: $$ = node($3, cs($2), $1.store,
226: END_NODE);
227: else
228: $$ = node($1.load, $3, cs($2), $1.store,
229: END_NODE);
1.1 otto 230: }
231: | STRING
232: {
233: $$ = node(cs("["), as($1),
234: cs("]P"), END_NODE);
235: }
236: | BREAK
237: {
238: if (breaksp == 0) {
239: warning("break not in for or while");
240: YYERROR;
241: } else {
242: $$ = node(
243: numnode(nesting -
244: breakstack[breaksp-1]),
245: cs("Q"), END_NODE);
246: }
247: }
1.11 otto 248: | CONTINUE
249: {
250: if (breaksp == 0) {
251: warning("continue not in for or while");
252: YYERROR;
253: } else {
254: st_has_continue = true;
255: $$ = node(numnode(nesting -
256: breakstack[breaksp-1] - 1),
257: cs("J"), END_NODE);
258: }
259: }
1.1 otto 260: | QUIT
261: {
262: putchar('q');
263: fflush(stdout);
264: exit(0);
265: }
266: | RETURN
267: {
268: if (nesting == 0) {
1.8 otto 269: warning("return must be in a function");
1.1 otto 270: YYERROR;
271: }
272: $$ = node(cs("0"), epilogue,
273: numnode(nesting), cs("Q"), END_NODE);
274: }
275: | RETURN LPAR return_expression RPAR
276: {
277: if (nesting == 0) {
1.8 otto 278: warning("return must be in a function");
1.1 otto 279: YYERROR;
280: }
281: $$ = $3;
282: }
1.13 ! otto 283: | FOR LPAR alloc_macro opt_expression SEMICOLON
! 284: opt_relational_expression SEMICOLON
! 285: opt_expression RPAR opt_statement pop_nesting
1.1 otto 286: {
1.11 otto 287: ssize_t n;
288:
289: if (st_has_continue)
290: n = node($10, cs("M"), $8, cs("s."),
291: $6, $3, END_NODE);
292: else
293: n = node($10, $8, cs("s."), $6, $3,
294: END_NODE);
295:
1.1 otto 296: emit_macro($3, n);
297: $$ = node($4, cs("s."), $6, $3, cs(" "),
298: END_NODE);
299: }
300: | IF LPAR alloc_macro pop_nesting relational_expression RPAR
301: opt_statement
302: {
303: emit_macro($3, $7);
304: $$ = node($5, $3, cs(" "), END_NODE);
305: }
306: | WHILE LPAR alloc_macro relational_expression RPAR
307: opt_statement pop_nesting
308: {
1.11 otto 309: ssize_t n;
310:
311: if (st_has_continue)
312: n = node($6, cs("M"), $4, $3, END_NODE);
313: else
314: n = node($6, $4, $3, END_NODE);
1.1 otto 315: emit_macro($3, n);
316: $$ = node($4, $3, cs(" "), END_NODE);
317: }
318: | LBRACE statement_list RBRACE
319: {
320: $$ = $2;
321: }
322: ;
323:
324: alloc_macro : /* empty */
325: {
326: $$ = cs(str_table[macro_char]);
327: macro_char++;
328: /* Do not use [, \ and ] */
329: if (macro_char == '[')
330: macro_char += 3;
331: /* skip letters */
332: else if (macro_char == 'a')
333: macro_char = '{';
334: else if (macro_char == ARRAY_CHAR)
335: macro_char += 26;
336: else if (macro_char == 256)
337: fatal("program too big");
338: if (breaksp == BREAKSTACK_SZ)
339: fatal("nesting too deep");
340: breakstack[breaksp++] = nesting++;
341: }
1.11 otto 342: ;
343:
1.1 otto 344: pop_nesting : /* empty */
345: {
346: breaksp--;
347: }
1.11 otto 348: ;
1.1 otto 349:
350: function : function_header opt_parameter_list RPAR
351: LBRACE NEWLINE opt_auto_define_list
352: statement_list RBRACE
353: {
354: int n = node(prologue, $7, epilogue,
355: cs("0"), numnode(nesting),
356: cs("Q"), END_NODE);
357: emit_macro($1, n);
358: reset_macro_char = macro_char;
359: nesting = 0;
360: breaksp = 0;
361: }
362: ;
363:
364: function_header : DEFINE LETTER LPAR
365: {
366: $$ = FUNCTION_NODE($2);
367: prologue = cs("");
368: epilogue = cs("");
369: nesting = 1;
370: breaksp = 0;
371: breakstack[breaksp] = 0;
372: }
1.11 otto 373: ;
1.1 otto 374:
375: opt_parameter_list
376: : /* empty */
377: | parameter_list
378: ;
379:
380:
381: parameter_list : LETTER
382: {
383: add_par(LETTER_NODE($1));
384: }
385: | LETTER LBRACKET RBRACKET
386: {
387: add_par(ARRAY_NODE($1));
388: }
389: | parameter_list COMMA LETTER
390: {
391: add_par(LETTER_NODE($3));
392: }
393: | parameter_list COMMA LETTER LBRACKET RBRACKET
394: {
395: add_par(ARRAY_NODE($3));
396: }
397: ;
398:
399:
400:
401: opt_auto_define_list
402: : /* empty */
403: | AUTO define_list NEWLINE
404: | AUTO define_list SEMICOLON
405: ;
406:
407:
408: define_list : LETTER
409: {
410: add_local(LETTER_NODE($1));
411: }
412: | LETTER LBRACKET RBRACKET
413: {
414: add_local(ARRAY_NODE($1));
415: }
416: | define_list COMMA LETTER
417: {
418: add_local(LETTER_NODE($3));
419: }
420: | define_list COMMA LETTER LBRACKET RBRACKET
421: {
422: add_local(ARRAY_NODE($3));
423: }
424: ;
425:
426:
427: opt_argument_list
428: : /* empty */
429: {
430: $$ = cs("");
431: }
432: | argument_list
433: ;
434:
435:
436: argument_list : expression
437: | argument_list COMMA expression
438: {
439: $$ = node($1, $3, END_NODE);
440: }
441: | argument_list COMMA LETTER LBRACKET RBRACKET
442: {
443: $$ = node($1, cs("l"), ARRAY_NODE($3),
1.3 deraadt 444: END_NODE);
1.1 otto 445: }
446: ;
447:
1.13 ! otto 448: opt_relational_expression
! 449: : /* empty */
! 450: {
! 451: $$ = cs(" 0 0=");
! 452: }
! 453: | relational_expression
! 454: ;
1.1 otto 455:
456: relational_expression
457: : expression
458: {
459: $$ = node($1, cs(" 0!="), END_NODE);
460: }
461: | expression EQUALS expression
462: {
463: $$ = node($1, $3, cs("="), END_NODE);
464: }
465: | expression UNEQUALS expression
466: {
467: $$ = node($1, $3, cs("!="), END_NODE);
468: }
469: | expression LESS expression
470: {
471: $$ = node($1, $3, cs(">"), END_NODE);
472: }
473: | expression LESS_EQ expression
474: {
475: $$ = node($1, $3, cs("!<"), END_NODE);
476: }
477: | expression GREATER expression
478: {
479: $$ = node($1, $3, cs("<"), END_NODE);
480: }
481: | expression GREATER_EQ expression
482: {
483: $$ = node($1, $3, cs("!>"), END_NODE);
484: }
485: ;
486:
487:
488: return_expression
489: : /* empty */
490: {
491: $$ = node(cs("0"), epilogue,
492: numnode(nesting), cs("Q"), END_NODE);
493: }
494: | expression
495: {
496: $$ = node($1, epilogue,
497: numnode(nesting), cs("Q"), END_NODE);
498: }
499: ;
500:
1.13 ! otto 501:
! 502: opt_expression : /* empty */
! 503: {
! 504: $$ = cs(" 0");
! 505: }
! 506: | expression
! 507: ;
1.1 otto 508:
509: expression : named_expression
510: {
511: $$ = node($1.load, END_NODE);
1.9 otto 512: }
513: | DOT {
514: $$ = node(cs("l."), END_NODE);
1.1 otto 515: }
516: | NUMBER
517: {
518: $$ = node(cs(" "), as($1), END_NODE);
519: }
520: | LPAR expression RPAR
521: {
522: $$ = $2;
523: }
524: | LETTER LPAR opt_argument_list RPAR
525: {
526: $$ = node($3, cs("l"),
527: FUNCTION_NODE($1), cs("x"),
528: END_NODE);
529: }
530: | MINUS expression %prec UMINUS
531: {
532: $$ = node(cs(" 0"), $2, cs("-"),
533: END_NODE);
534: }
535: | expression PLUS expression
536: {
537: $$ = node($1, $3, cs("+"), END_NODE);
538: }
539: | expression MINUS expression
540: {
541: $$ = node($1, $3, cs("-"), END_NODE);
542: }
543: | expression MULTIPLY expression
544: {
545: $$ = node($1, $3, cs("*"), END_NODE);
546: }
547: | expression DIVIDE expression
548: {
549: $$ = node($1, $3, cs("/"), END_NODE);
550: }
551: | expression REMAINDER expression
552: {
553: $$ = node($1, $3, cs("%"), END_NODE);
554: }
555: | expression EXPONENT expression
556: {
557: $$ = node($1, $3, cs("^"), END_NODE);
558: }
559: | INCR named_expression
560: {
561: $$ = node($2.load, cs("1+d"), $2.store,
562: END_NODE);
563: }
564: | DECR named_expression
565: {
566: $$ = node($2.load, cs("1-d"),
567: $2.store, END_NODE);
568: }
569: | named_expression INCR
570: {
571: $$ = node($1.load, cs("d1+"),
572: $1.store, END_NODE);
573: }
574: | named_expression DECR
575: {
576: $$ = node($1.load, cs("d1-"),
577: $1.store, END_NODE);
578: }
579: | named_expression ASSIGN_OP expression
580: {
1.11 otto 581: if ($2[0] == '\0')
582: $$ = node($3, cs($2), cs("d"), $1.store,
583: END_NODE);
584: else
585: $$ = node($1.load, $3, cs($2), cs("d"),
586: $1.store, END_NODE);
1.1 otto 587: }
588: | LENGTH LPAR expression RPAR
589: {
590: $$ = node($3, cs("Z"), END_NODE);
591: }
592: | SQRT LPAR expression RPAR
593: {
594: $$ = node($3, cs("v"), END_NODE);
595: }
596: | SCALE LPAR expression RPAR
597: {
598: $$ = node($3, cs("X"), END_NODE);
599: }
600: ;
601:
602: named_expression
603: : LETTER
604: {
605: $$.load = node(cs("l"), LETTER_NODE($1),
606: END_NODE);
607: $$.store = node(cs("s"), LETTER_NODE($1),
608: END_NODE);
609: }
610: | LETTER LBRACKET expression RBRACKET
611: {
612: $$.load = node($3, cs(";"),
613: ARRAY_NODE($1), END_NODE);
614: $$.store = node($3, cs(":"),
615: ARRAY_NODE($1), END_NODE);
616: }
617: | SCALE
618: {
619: $$.load = cs("K");
620: $$.store = cs("k");
621: }
622: | IBASE
623: {
624: $$.load = cs("I");
625: $$.store = cs("i");
626: }
627: | OBASE
628: {
629: $$.load = cs("O");
630: $$.store = cs("o");
631: }
632: ;
633: %%
634:
635:
636: static void
637: grow(void)
638: {
639: struct tree *p;
640: int newsize;
641:
642: if (current == instr_sz) {
643: newsize = instr_sz * 2 + 1;
644: p = realloc(instructions, newsize * sizeof(*p));
645: if (p == NULL) {
646: free(instructions);
1.12 otto 647: err(1, NULL);
1.1 otto 648: }
649: instructions = p;
650: instr_sz = newsize;
651: }
652: }
653:
1.7 otto 654: static ssize_t
1.1 otto 655: cs(const char *str)
656: {
657: grow();
658: instructions[current].index = CONST_STRING;
659: instructions[current].u.cstr = str;
660: return current++;
661: }
662:
1.7 otto 663: static ssize_t
1.1 otto 664: as(const char *str)
665: {
666: grow();
667: instructions[current].index = ALLOC_STRING;
668: instructions[current].u.astr = strdup(str);
1.2 otto 669: if (instructions[current].u.astr == NULL)
1.12 otto 670: err(1, NULL);
1.1 otto 671: return current++;
672: }
673:
674: static ssize_t
675: node(ssize_t arg, ...)
676: {
677: va_list ap;
678: ssize_t ret;
679:
680: va_start(ap, arg);
681:
682: ret = current;
683: grow();
684: instructions[current++].index = arg;
685:
686: do {
687: arg = va_arg(ap, ssize_t);
688: grow();
689: instructions[current++].index = arg;
690: } while (arg != END_NODE);
691:
692: va_end(ap);
693: return ret;
694: }
695:
696: static void
697: emit(ssize_t i)
698: {
699: if (instructions[i].index >= 0)
700: while (instructions[i].index != END_NODE)
701: emit(instructions[i++].index);
702: else
703: fputs(instructions[i].u.cstr, stdout);
704: }
705:
706: static void
707: emit_macro(int node, ssize_t code)
708: {
709: putchar('[');
710: emit(code);
711: printf("]s%s\n", instructions[node].u.cstr);
712: nesting--;
713: }
714:
715: static void
716: free_tree(void)
717: {
718: size_t i;
719:
720: for (i = 0; i < current; i++)
721: if (instructions[i].index == ALLOC_STRING)
722: free(instructions[i].u.astr);
723: current = 0;
724: }
725:
726: static ssize_t
727: numnode(int num)
728: {
729: const char *p;
730:
731: if (num < 10)
732: p = str_table['0' + num];
733: else if (num < 16)
734: p = str_table['A' - 10 + num];
735: else
736: err(1, "internal error: break num > 15");
737: return node(cs(" "), cs(p), END_NODE);
738: }
739:
740: static void
741: add_par(ssize_t n)
742: {
743: prologue = node(cs("S"), n, prologue, END_NODE);
744: epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE);
745: }
746:
747: static void
748: add_local(ssize_t n)
749: {
750: prologue = node(cs("0S"), n, prologue, END_NODE);
751: epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE);
752: }
753:
754: int
755: yywrap(void)
756: {
757: if (optind < sargc) {
758: filename = sargv[optind++];
759: yyin = fopen(filename, "r");
1.8 otto 760: lineno = 1;
1.1 otto 761: if (yyin == NULL)
762: err(1, "cannot open %s", filename);
763: return 0;
1.6 deraadt 764: } else if (optind == sargc) {
1.1 otto 765: optind++;
766: yyin = stdin;
1.8 otto 767: lineno = 1;
1.1 otto 768: filename = "stdin";
769: return 0;
770: }
771: return 1;
772: }
773:
774: void
775: yyerror(char *s)
776: {
1.10 otto 777: char *str, *p;
778:
779: if (isspace(yytext[0]) || !isprint(yytext[0]))
780: asprintf(&str, "%s: %s:%d: %s: ascii char 0x%x unexpected",
781: __progname, filename, lineno, s, yytext[0]);
1.1 otto 782: else
1.10 otto 783: asprintf(&str, "%s: %s:%d: %s: %s unexpected",
1.8 otto 784: __progname, filename, lineno, s, yytext);
1.10 otto 785: if (str == NULL)
1.12 otto 786: err(1, NULL);
1.10 otto 787:
788: fputs("c[", stdout);
789: for (p = str; *p != '\0'; p++) {
790: if (*p == '[' || *p == ']' || *p =='\\')
791: putchar('\\');
792: putchar(*p);
793: }
794: fputs("]pc\n", stdout);
795: free(str);
1.1 otto 796: }
797:
1.8 otto 798: void
1.1 otto 799: fatal(const char *s)
800: {
801: errx(1, "%s:%d: %s", filename, lineno, s);
802: }
803:
804: static void
805: warning(const char *s)
806: {
807: warnx("%s:%d: %s", filename, lineno, s);
808: }
809:
810: static void
811: init(void)
812: {
813: int i;
814:
815: for (i = 0; i < UCHAR_MAX; i++) {
816: str_table[i][0] = i;
817: str_table[i][1] = '\0';
818: }
819: }
820:
821:
822: static __dead void
823: usage(void)
824: {
1.4 deraadt 825: fprintf(stderr, "%s: usage: [-cl] [file ...]\n", __progname);
1.1 otto 826: exit(1);
827: }
828:
829:
830: int
831: main(int argc, char *argv[])
832: {
833: int ch, ret;
834: int p[2];
835:
836: init();
837: setlinebuf(stdout);
838:
839: /* The d debug option is 4.4 BSD dc(1) compatible */
840: while ((ch = getopt(argc, argv, "cdl")) != -1) {
841: switch (ch) {
842: case 'c':
843: case 'd':
844: do_fork = false;
845: break;
846: case 'l':
847: argv[1] = _PATH_LIBB;
848: optind = 1;
849: break;
850: default:
1.5 deraadt 851: usage();
1.1 otto 852: }
853: }
854:
855: sargc = argc;
856: sargv = argv;
857:
858: if (do_fork) {
859: if (pipe(p) == -1)
860: err(1, "cannot create pipe");
861: ret = fork();
862: if (ret == -1)
863: err(1, "cannot fork");
864: else if (ret == 0) {
865: close(STDOUT_FILENO);
866: dup(p[1]);
867: close(p[0]);
868: close(p[1]);
1.6 deraadt 869: } else {
1.1 otto 870: signal(SIGINT, SIG_IGN);
871: close(STDIN_FILENO);
872: dup(p[0]);
873: close(p[0]);
874: close(p[1]);
875: execl(_PATH_DC, "dc", "-", (char *)NULL);
876: err(1, "cannot find dc");
877: }
878: }
879: signal(SIGINT, abort_line);
880: yywrap();
881: return yyparse();
882: }