Annotation of src/usr.bin/bc/bc.y, Revision 1.15
1.1 otto 1: %{
1.15 ! otto 2: /* $OpenBSD: bc.y,v 1.14 2003/10/22 12:24:41 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.15 ! otto 34: static const char rcsid[] = "$OpenBSD: bc.y,v 1.14 2003/10/22 12:24:41 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);
1.15 ! otto 77: static char *escape(const char *);
1.1 otto 78:
79: static size_t instr_sz = 0;
80: static struct tree *instructions = NULL;
1.7 otto 81: static ssize_t current = 0;
1.1 otto 82: static int macro_char = '0';
83: static int reset_macro_char = '0';
84: static int nesting = 0;
85: static int breakstack[16];
86: static int breaksp = 0;
87: static ssize_t prologue;
88: static ssize_t epilogue;
1.11 otto 89: static bool st_has_continue;
1.1 otto 90: static char str_table[UCHAR_MAX][2];
91: static int sargc;
92: static char **sargv;
93: static char *filename;
94: static bool do_fork = true;
95:
96: extern char *__progname;
97:
98: #define BREAKSTACK_SZ (sizeof(breakstack)/sizeof(breakstack[0]))
99:
100: /* These values are 4.4BSD dc compatible */
101: #define FUNC_CHAR 0x01
102: #define ARRAY_CHAR 0xa1
103:
104: #define LETTER_NODE(str) (cs(str_table[(int)str[0]]))
105: #define ARRAY_NODE(str) (cs(str_table[(int)str[0] - 'a' + ARRAY_CHAR]))
106: #define FUNCTION_NODE(str) (cs(str_table[(int)str[0] - 'a' + FUNC_CHAR]))
107:
108: %}
109:
110: %start program
111:
112: %union {
113: ssize_t node;
114: struct lvalue lvalue;
115: const char *str;
116: }
117:
1.9 otto 118: %token COMMA SEMICOLON LPAR RPAR LBRACE RBRACE LBRACKET RBRACKET DOT
119: %token NEWLINE
1.1 otto 120: %token <str> LETTER NUMBER STRING
121: %token DEFINE BREAK QUIT LENGTH
122: %token RETURN FOR IF WHILE SQRT
123: %token SCALE IBASE OBASE AUTO
1.15 ! otto 124: %token CONTINUE ELSE PRINT
1.1 otto 125:
126: %nonassoc EQUALS LESS_EQ GREATER_EQ UNEQUALS LESS GREATER
127: %right <str> ASSIGN_OP
128: %left PLUS MINUS
129: %left MULTIPLY DIVIDE REMAINDER
130: %left EXPONENT
131: %nonassoc UMINUS
132: %nonassoc INCR DECR
133:
134: %type <lvalue> named_expression
135: %type <node> argument_list
136: %type <node> alloc_macro
137: %type <node> expression
138: %type <node> function
139: %type <node> function_header
140: %type <node> input_item
141: %type <node> opt_argument_list
1.13 otto 142: %type <node> opt_expression
143: %type <node> opt_relational_expression
1.1 otto 144: %type <node> opt_statement
1.15 ! otto 145: %type <node> print_expression
! 146: %type <node> print_expression_list
1.1 otto 147: %type <node> relational_expression
148: %type <node> return_expression
149: %type <node> semicolon_list
150: %type <node> statement
151: %type <node> statement_list
152:
153: %%
154:
155: program : /* empty */
156: {
157: putchar('q');
158: fflush(stdout);
159: exit(0);
160: }
161: | input_item program
162: ;
163:
164: input_item : semicolon_list NEWLINE
165: {
166: emit($1);
167: macro_char = reset_macro_char;
168: putchar('\n');
169: free_tree();
1.11 otto 170: st_has_continue = false;
1.1 otto 171: }
172: | function
173: {
174: putchar('\n');
175: free_tree();
1.11 otto 176: st_has_continue = false;
1.1 otto 177: }
1.8 otto 178: | error NEWLINE
1.1 otto 179: {
1.8 otto 180: yyerrok;
1.1 otto 181: }
182: ;
183:
184: semicolon_list : /* empty */
185: {
186: $$ = cs("");
187: }
188: | statement
189: | semicolon_list SEMICOLON statement
190: {
191: $$ = node($1, $3, END_NODE);
192: }
193: | semicolon_list SEMICOLON
194: ;
195:
196: statement_list : /* empty */
197: {
198: $$ = cs("");
199: }
200: | statement
201: | statement_list NEWLINE
202: | statement_list NEWLINE statement
203: {
204: $$ = node($1, $3, END_NODE);
205: }
206: | statement_list SEMICOLON
207: | statement_list SEMICOLON statement
208: {
209: $$ = node($1, $3, END_NODE);
210: }
211: ;
212:
213:
214: opt_statement : /* empty */
215: {
216: $$ = cs("");
217: }
218: | statement
219: ;
220:
221: statement : expression
222: {
223: $$ = node($1, cs("ps."), END_NODE);
224: }
225: | named_expression ASSIGN_OP expression
226: {
1.11 otto 227: if ($2[0] == '\0')
228: $$ = node($3, cs($2), $1.store,
229: END_NODE);
230: else
231: $$ = node($1.load, $3, cs($2), $1.store,
232: END_NODE);
1.1 otto 233: }
234: | STRING
235: {
236: $$ = node(cs("["), as($1),
237: cs("]P"), END_NODE);
238: }
239: | BREAK
240: {
241: if (breaksp == 0) {
242: warning("break not in for or while");
243: YYERROR;
244: } else {
245: $$ = node(
246: numnode(nesting -
247: breakstack[breaksp-1]),
248: cs("Q"), END_NODE);
249: }
250: }
1.11 otto 251: | CONTINUE
252: {
253: if (breaksp == 0) {
254: warning("continue not in for or while");
255: YYERROR;
256: } else {
257: st_has_continue = true;
258: $$ = node(numnode(nesting -
259: breakstack[breaksp-1] - 1),
260: cs("J"), END_NODE);
261: }
262: }
1.1 otto 263: | QUIT
264: {
265: putchar('q');
266: fflush(stdout);
267: exit(0);
268: }
269: | RETURN
270: {
271: if (nesting == 0) {
1.8 otto 272: warning("return must be in a function");
1.1 otto 273: YYERROR;
274: }
275: $$ = node(cs("0"), epilogue,
276: numnode(nesting), cs("Q"), END_NODE);
277: }
278: | RETURN LPAR return_expression RPAR
279: {
280: if (nesting == 0) {
1.8 otto 281: warning("return must be in a function");
1.1 otto 282: YYERROR;
283: }
284: $$ = $3;
285: }
1.13 otto 286: | FOR LPAR alloc_macro opt_expression SEMICOLON
287: opt_relational_expression SEMICOLON
288: opt_expression RPAR opt_statement pop_nesting
1.1 otto 289: {
1.11 otto 290: ssize_t n;
291:
292: if (st_has_continue)
293: n = node($10, cs("M"), $8, cs("s."),
294: $6, $3, END_NODE);
295: else
296: n = node($10, $8, cs("s."), $6, $3,
297: END_NODE);
298:
1.1 otto 299: emit_macro($3, n);
300: $$ = node($4, cs("s."), $6, $3, cs(" "),
301: END_NODE);
302: }
303: | IF LPAR alloc_macro pop_nesting relational_expression RPAR
304: opt_statement
305: {
306: emit_macro($3, $7);
307: $$ = node($5, $3, cs(" "), END_NODE);
1.14 otto 308: }
309: | IF LPAR alloc_macro pop_nesting relational_expression RPAR
310: opt_statement ELSE alloc_macro pop_nesting opt_statement
311: {
312: emit_macro($3, $7);
313: emit_macro($9, $11);
314: $$ = node($5, $3, cs("e"), $9, cs(" "),
315: END_NODE);
1.1 otto 316: }
317: | WHILE LPAR alloc_macro relational_expression RPAR
318: opt_statement pop_nesting
319: {
1.11 otto 320: ssize_t n;
321:
322: if (st_has_continue)
323: n = node($6, cs("M"), $4, $3, END_NODE);
324: else
325: n = node($6, $4, $3, END_NODE);
1.1 otto 326: emit_macro($3, n);
327: $$ = node($4, $3, cs(" "), END_NODE);
328: }
329: | LBRACE statement_list RBRACE
330: {
331: $$ = $2;
332: }
1.15 ! otto 333: | PRINT print_expression_list
! 334: {
! 335: $$ = $2;
! 336: }
1.1 otto 337: ;
338:
339: alloc_macro : /* empty */
340: {
341: $$ = cs(str_table[macro_char]);
342: macro_char++;
343: /* Do not use [, \ and ] */
344: if (macro_char == '[')
345: macro_char += 3;
346: /* skip letters */
347: else if (macro_char == 'a')
348: macro_char = '{';
349: else if (macro_char == ARRAY_CHAR)
350: macro_char += 26;
351: else if (macro_char == 256)
352: fatal("program too big");
353: if (breaksp == BREAKSTACK_SZ)
354: fatal("nesting too deep");
355: breakstack[breaksp++] = nesting++;
356: }
1.11 otto 357: ;
358:
1.1 otto 359: pop_nesting : /* empty */
360: {
361: breaksp--;
362: }
1.11 otto 363: ;
1.1 otto 364:
365: function : function_header opt_parameter_list RPAR
366: LBRACE NEWLINE opt_auto_define_list
367: statement_list RBRACE
368: {
369: int n = node(prologue, $7, epilogue,
370: cs("0"), numnode(nesting),
371: cs("Q"), END_NODE);
372: emit_macro($1, n);
373: reset_macro_char = macro_char;
374: nesting = 0;
375: breaksp = 0;
376: }
377: ;
378:
379: function_header : DEFINE LETTER LPAR
380: {
381: $$ = FUNCTION_NODE($2);
382: prologue = cs("");
383: epilogue = cs("");
384: nesting = 1;
385: breaksp = 0;
386: breakstack[breaksp] = 0;
387: }
1.11 otto 388: ;
1.1 otto 389:
390: opt_parameter_list
391: : /* empty */
392: | parameter_list
393: ;
394:
395:
396: parameter_list : LETTER
397: {
398: add_par(LETTER_NODE($1));
399: }
400: | LETTER LBRACKET RBRACKET
401: {
402: add_par(ARRAY_NODE($1));
403: }
404: | parameter_list COMMA LETTER
405: {
406: add_par(LETTER_NODE($3));
407: }
408: | parameter_list COMMA LETTER LBRACKET RBRACKET
409: {
410: add_par(ARRAY_NODE($3));
411: }
412: ;
413:
414:
415:
416: opt_auto_define_list
417: : /* empty */
418: | AUTO define_list NEWLINE
419: | AUTO define_list SEMICOLON
420: ;
421:
422:
423: define_list : LETTER
424: {
425: add_local(LETTER_NODE($1));
426: }
427: | LETTER LBRACKET RBRACKET
428: {
429: add_local(ARRAY_NODE($1));
430: }
431: | define_list COMMA LETTER
432: {
433: add_local(LETTER_NODE($3));
434: }
435: | define_list COMMA LETTER LBRACKET RBRACKET
436: {
437: add_local(ARRAY_NODE($3));
438: }
439: ;
440:
441:
442: opt_argument_list
443: : /* empty */
444: {
445: $$ = cs("");
446: }
447: | argument_list
448: ;
449:
450:
451: argument_list : expression
452: | argument_list COMMA expression
453: {
454: $$ = node($1, $3, END_NODE);
455: }
456: | argument_list COMMA LETTER LBRACKET RBRACKET
457: {
458: $$ = node($1, cs("l"), ARRAY_NODE($3),
1.3 deraadt 459: END_NODE);
1.1 otto 460: }
461: ;
462:
1.13 otto 463: opt_relational_expression
464: : /* empty */
465: {
466: $$ = cs(" 0 0=");
467: }
468: | relational_expression
469: ;
1.1 otto 470:
471: relational_expression
472: : expression
473: {
474: $$ = node($1, cs(" 0!="), END_NODE);
475: }
476: | expression EQUALS expression
477: {
478: $$ = node($1, $3, cs("="), END_NODE);
479: }
480: | expression UNEQUALS expression
481: {
482: $$ = node($1, $3, cs("!="), END_NODE);
483: }
484: | expression LESS expression
485: {
486: $$ = node($1, $3, cs(">"), END_NODE);
487: }
488: | expression LESS_EQ expression
489: {
490: $$ = node($1, $3, cs("!<"), END_NODE);
491: }
492: | expression GREATER expression
493: {
494: $$ = node($1, $3, cs("<"), END_NODE);
495: }
496: | expression GREATER_EQ expression
497: {
498: $$ = node($1, $3, cs("!>"), END_NODE);
499: }
500: ;
501:
502:
503: return_expression
504: : /* empty */
505: {
506: $$ = node(cs("0"), epilogue,
507: numnode(nesting), cs("Q"), END_NODE);
508: }
509: | expression
510: {
511: $$ = node($1, epilogue,
512: numnode(nesting), cs("Q"), END_NODE);
513: }
514: ;
515:
1.13 otto 516:
517: opt_expression : /* empty */
518: {
519: $$ = cs(" 0");
520: }
521: | expression
522: ;
1.1 otto 523:
524: expression : named_expression
525: {
526: $$ = node($1.load, END_NODE);
1.9 otto 527: }
528: | DOT {
529: $$ = node(cs("l."), END_NODE);
1.1 otto 530: }
531: | NUMBER
532: {
533: $$ = node(cs(" "), as($1), END_NODE);
534: }
535: | LPAR expression RPAR
536: {
537: $$ = $2;
538: }
539: | LETTER LPAR opt_argument_list RPAR
540: {
541: $$ = node($3, cs("l"),
542: FUNCTION_NODE($1), cs("x"),
543: END_NODE);
544: }
545: | MINUS expression %prec UMINUS
546: {
547: $$ = node(cs(" 0"), $2, cs("-"),
548: END_NODE);
549: }
550: | expression PLUS expression
551: {
552: $$ = node($1, $3, cs("+"), END_NODE);
553: }
554: | expression MINUS expression
555: {
556: $$ = node($1, $3, cs("-"), END_NODE);
557: }
558: | expression MULTIPLY expression
559: {
560: $$ = node($1, $3, cs("*"), END_NODE);
561: }
562: | expression DIVIDE expression
563: {
564: $$ = node($1, $3, cs("/"), END_NODE);
565: }
566: | expression REMAINDER expression
567: {
568: $$ = node($1, $3, cs("%"), END_NODE);
569: }
570: | expression EXPONENT expression
571: {
572: $$ = node($1, $3, cs("^"), END_NODE);
573: }
574: | INCR named_expression
575: {
576: $$ = node($2.load, cs("1+d"), $2.store,
577: END_NODE);
578: }
579: | DECR named_expression
580: {
581: $$ = node($2.load, cs("1-d"),
582: $2.store, END_NODE);
583: }
584: | named_expression INCR
585: {
586: $$ = node($1.load, cs("d1+"),
587: $1.store, END_NODE);
588: }
589: | named_expression DECR
590: {
591: $$ = node($1.load, cs("d1-"),
592: $1.store, END_NODE);
593: }
594: | named_expression ASSIGN_OP expression
595: {
1.11 otto 596: if ($2[0] == '\0')
597: $$ = node($3, cs($2), cs("d"), $1.store,
598: END_NODE);
599: else
600: $$ = node($1.load, $3, cs($2), cs("d"),
601: $1.store, END_NODE);
1.1 otto 602: }
603: | LENGTH LPAR expression RPAR
604: {
605: $$ = node($3, cs("Z"), END_NODE);
606: }
607: | SQRT LPAR expression RPAR
608: {
609: $$ = node($3, cs("v"), END_NODE);
610: }
611: | SCALE LPAR expression RPAR
612: {
613: $$ = node($3, cs("X"), END_NODE);
614: }
615: ;
616:
617: named_expression
618: : LETTER
619: {
620: $$.load = node(cs("l"), LETTER_NODE($1),
621: END_NODE);
622: $$.store = node(cs("s"), LETTER_NODE($1),
623: END_NODE);
624: }
625: | LETTER LBRACKET expression RBRACKET
626: {
627: $$.load = node($3, cs(";"),
628: ARRAY_NODE($1), END_NODE);
629: $$.store = node($3, cs(":"),
630: ARRAY_NODE($1), END_NODE);
631: }
632: | SCALE
633: {
634: $$.load = cs("K");
635: $$.store = cs("k");
636: }
637: | IBASE
638: {
639: $$.load = cs("I");
640: $$.store = cs("i");
641: }
642: | OBASE
643: {
644: $$.load = cs("O");
645: $$.store = cs("o");
646: }
647: ;
1.15 ! otto 648:
! 649: print_expression_list
! 650: : print_expression
! 651: | print_expression_list COMMA print_expression
! 652: {
! 653: $$ = node($1, $3, END_NODE);
! 654: }
! 655:
! 656: print_expression
! 657: : expression
! 658: {
! 659: $$ = node($1, cs("dds.n"), END_NODE);
! 660: }
! 661: | STRING
! 662: {
! 663: char *p = escape($1);
! 664: $$ = node(cs("["), as(p), cs("]dn"),
! 665: END_NODE);
! 666: free(p);
! 667: }
1.1 otto 668: %%
669:
670:
671: static void
672: grow(void)
673: {
674: struct tree *p;
675: int newsize;
676:
677: if (current == instr_sz) {
678: newsize = instr_sz * 2 + 1;
679: p = realloc(instructions, newsize * sizeof(*p));
680: if (p == NULL) {
681: free(instructions);
1.12 otto 682: err(1, NULL);
1.1 otto 683: }
684: instructions = p;
685: instr_sz = newsize;
686: }
687: }
688:
1.7 otto 689: static ssize_t
1.1 otto 690: cs(const char *str)
691: {
692: grow();
693: instructions[current].index = CONST_STRING;
694: instructions[current].u.cstr = str;
695: return current++;
696: }
697:
1.7 otto 698: static ssize_t
1.1 otto 699: as(const char *str)
700: {
701: grow();
702: instructions[current].index = ALLOC_STRING;
703: instructions[current].u.astr = strdup(str);
1.2 otto 704: if (instructions[current].u.astr == NULL)
1.12 otto 705: err(1, NULL);
1.1 otto 706: return current++;
707: }
708:
709: static ssize_t
710: node(ssize_t arg, ...)
711: {
712: va_list ap;
713: ssize_t ret;
714:
715: va_start(ap, arg);
716:
717: ret = current;
718: grow();
719: instructions[current++].index = arg;
720:
721: do {
722: arg = va_arg(ap, ssize_t);
723: grow();
724: instructions[current++].index = arg;
725: } while (arg != END_NODE);
726:
727: va_end(ap);
728: return ret;
729: }
730:
731: static void
732: emit(ssize_t i)
733: {
734: if (instructions[i].index >= 0)
735: while (instructions[i].index != END_NODE)
736: emit(instructions[i++].index);
737: else
738: fputs(instructions[i].u.cstr, stdout);
739: }
740:
741: static void
742: emit_macro(int node, ssize_t code)
743: {
744: putchar('[');
745: emit(code);
746: printf("]s%s\n", instructions[node].u.cstr);
747: nesting--;
748: }
749:
750: static void
751: free_tree(void)
752: {
753: size_t i;
754:
755: for (i = 0; i < current; i++)
756: if (instructions[i].index == ALLOC_STRING)
757: free(instructions[i].u.astr);
758: current = 0;
759: }
760:
761: static ssize_t
762: numnode(int num)
763: {
764: const char *p;
765:
766: if (num < 10)
767: p = str_table['0' + num];
768: else if (num < 16)
769: p = str_table['A' - 10 + num];
770: else
771: err(1, "internal error: break num > 15");
772: return node(cs(" "), cs(p), END_NODE);
773: }
774:
775: static void
776: add_par(ssize_t n)
777: {
778: prologue = node(cs("S"), n, prologue, END_NODE);
779: epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE);
780: }
781:
782: static void
783: add_local(ssize_t n)
784: {
785: prologue = node(cs("0S"), n, prologue, END_NODE);
786: epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE);
787: }
788:
789: int
790: yywrap(void)
791: {
792: if (optind < sargc) {
793: filename = sargv[optind++];
794: yyin = fopen(filename, "r");
1.8 otto 795: lineno = 1;
1.1 otto 796: if (yyin == NULL)
797: err(1, "cannot open %s", filename);
798: return 0;
1.6 deraadt 799: } else if (optind == sargc) {
1.1 otto 800: optind++;
801: yyin = stdin;
1.8 otto 802: lineno = 1;
1.1 otto 803: filename = "stdin";
804: return 0;
805: }
806: return 1;
807: }
808:
809: void
810: yyerror(char *s)
811: {
1.10 otto 812: char *str, *p;
813:
814: if (isspace(yytext[0]) || !isprint(yytext[0]))
815: asprintf(&str, "%s: %s:%d: %s: ascii char 0x%x unexpected",
816: __progname, filename, lineno, s, yytext[0]);
1.1 otto 817: else
1.10 otto 818: asprintf(&str, "%s: %s:%d: %s: %s unexpected",
1.8 otto 819: __progname, filename, lineno, s, yytext);
1.10 otto 820: if (str == NULL)
1.12 otto 821: err(1, NULL);
1.10 otto 822:
823: fputs("c[", stdout);
824: for (p = str; *p != '\0'; p++) {
825: if (*p == '[' || *p == ']' || *p =='\\')
826: putchar('\\');
827: putchar(*p);
828: }
829: fputs("]pc\n", stdout);
830: free(str);
1.1 otto 831: }
832:
1.8 otto 833: void
1.1 otto 834: fatal(const char *s)
835: {
836: errx(1, "%s:%d: %s", filename, lineno, s);
837: }
838:
839: static void
840: warning(const char *s)
841: {
842: warnx("%s:%d: %s", filename, lineno, s);
843: }
844:
845: static void
846: init(void)
847: {
848: int i;
849:
850: for (i = 0; i < UCHAR_MAX; i++) {
851: str_table[i][0] = i;
852: str_table[i][1] = '\0';
853: }
854: }
855:
856:
857: static __dead void
858: usage(void)
859: {
1.4 deraadt 860: fprintf(stderr, "%s: usage: [-cl] [file ...]\n", __progname);
1.1 otto 861: exit(1);
862: }
863:
1.15 ! otto 864: static char *
! 865: escape(const char *str)
! 866: {
! 867: char *ret, *p;
! 868:
! 869: ret = malloc(strlen(str) + 1);
! 870: if (ret == NULL)
! 871: err(1, NULL);
! 872:
! 873: p = ret;
! 874: while (*str != '\0') {
! 875: /*
! 876: * We get _escaped_ strings here. Single backslashes are
! 877: * already converted to double backslashes
! 878: */
! 879: if (*str == '\\') {
! 880: if (*++str == '\\') {
! 881: switch (*++str) {
! 882: case 'a':
! 883: *p++ = '\a';
! 884: break;
! 885: case 'b':
! 886: *p++ = '\b';
! 887: break;
! 888: case 'f':
! 889: *p++ = '\f';
! 890: break;
! 891: case 'n':
! 892: *p++ = '\n';
! 893: break;
! 894: case 'q':
! 895: *p++ = '"';
! 896: break;
! 897: case 'r':
! 898: *p++ = '\r';
! 899: break;
! 900: case 't':
! 901: *p++ = '\t';
! 902: break;
! 903: case '\\':
! 904: *p++ = '\\';
! 905: break;
! 906: }
! 907: str++;
! 908: } else {
! 909: *p++ = '\\';
! 910: *p++ = *str++;
! 911: }
! 912: } else
! 913: *p++ = *str++;
! 914: }
! 915: *p = '\0';
! 916: return ret;
! 917: }
1.1 otto 918:
919: int
920: main(int argc, char *argv[])
921: {
922: int ch, ret;
923: int p[2];
924:
925: init();
926: setlinebuf(stdout);
927:
928: /* The d debug option is 4.4 BSD dc(1) compatible */
929: while ((ch = getopt(argc, argv, "cdl")) != -1) {
930: switch (ch) {
931: case 'c':
932: case 'd':
933: do_fork = false;
934: break;
935: case 'l':
936: argv[1] = _PATH_LIBB;
937: optind = 1;
938: break;
939: default:
1.5 deraadt 940: usage();
1.1 otto 941: }
942: }
943:
944: sargc = argc;
945: sargv = argv;
946:
947: if (do_fork) {
948: if (pipe(p) == -1)
949: err(1, "cannot create pipe");
950: ret = fork();
951: if (ret == -1)
952: err(1, "cannot fork");
953: else if (ret == 0) {
954: close(STDOUT_FILENO);
955: dup(p[1]);
956: close(p[0]);
957: close(p[1]);
1.6 deraadt 958: } else {
1.1 otto 959: signal(SIGINT, SIG_IGN);
960: close(STDIN_FILENO);
961: dup(p[0]);
962: close(p[0]);
963: close(p[1]);
964: execl(_PATH_DC, "dc", "-", (char *)NULL);
965: err(1, "cannot find dc");
966: }
967: }
968: signal(SIGINT, abort_line);
969: yywrap();
970: return yyparse();
971: }