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