Annotation of src/usr.bin/bc/bc.y, Revision 1.50
1.1 otto 1: %{
1.50 ! otto 2: /* $OpenBSD: bc.y,v 1.49 2015/11/23 09:58:55 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:
1.28 otto 33: #include <sys/types.h>
34: #include <sys/wait.h>
35:
1.1 otto 36: #include <ctype.h>
37: #include <err.h>
1.28 otto 38: #include <errno.h>
1.34 otto 39: #include <histedit.h>
1.1 otto 40: #include <limits.h>
1.20 otto 41: #include <search.h>
1.1 otto 42: #include <signal.h>
43: #include <stdarg.h>
44: #include <string.h>
45: #include <unistd.h>
46:
47: #include "extern.h"
48: #include "pathnames.h"
49:
50: #define END_NODE ((ssize_t) -1)
51: #define CONST_STRING ((ssize_t) -2)
52: #define ALLOC_STRING ((ssize_t) -3)
53:
54: struct tree {
55: ssize_t index;
56: union {
57: char *astr;
58: const char *cstr;
59: } u;
60: };
61:
62: int yyparse(void);
63: int yywrap(void);
64:
1.24 otto 65: int fileindex;
66: int sargc;
67: char **sargv;
68: char *filename;
69: char *cmdexpr;
70:
1.1 otto 71: static void grow(void);
72: static ssize_t cs(const char *);
73: static ssize_t as(const char *);
74: static ssize_t node(ssize_t, ...);
1.49 otto 75: static void emit(ssize_t, int);
1.1 otto 76: static void emit_macro(int, ssize_t);
77: static void free_tree(void);
78: static ssize_t numnode(int);
1.20 otto 79: static ssize_t lookup(char *, size_t, char);
80: static ssize_t letter_node(char *);
81: static ssize_t array_node(char *);
82: static ssize_t function_node(char *);
83:
1.1 otto 84: static void add_par(ssize_t);
85: static void add_local(ssize_t);
86: static void warning(const char *);
87: static void init(void);
88: static __dead void usage(void);
1.15 otto 89: static char *escape(const char *);
1.1 otto 90:
1.26 otto 91: static ssize_t instr_sz = 0;
1.1 otto 92: static struct tree *instructions = NULL;
1.7 otto 93: static ssize_t current = 0;
1.1 otto 94: static int macro_char = '0';
95: static int reset_macro_char = '0';
96: static int nesting = 0;
97: static int breakstack[16];
98: static int breaksp = 0;
99: static ssize_t prologue;
100: static ssize_t epilogue;
1.11 otto 101: static bool st_has_continue;
1.1 otto 102: static char str_table[UCHAR_MAX][2];
103: static bool do_fork = true;
1.20 otto 104: static u_short var_count;
1.28 otto 105: static pid_t dc;
1.1 otto 106:
107: extern char *__progname;
108:
109: #define BREAKSTACK_SZ (sizeof(breakstack)/sizeof(breakstack[0]))
110:
1.20 otto 111: /* These values are 4.4BSD bc compatible */
1.1 otto 112: #define FUNC_CHAR 0x01
113: #define ARRAY_CHAR 0xa1
114:
1.20 otto 115: /* Skip '\0', [, \ and ] */
116: #define ENCODE(c) ((c) < '[' ? (c) : (c) + 3);
117: #define VAR_BASE (256-4)
118: #define MAX_VARIABLES (VAR_BASE * VAR_BASE)
1.1 otto 119:
120: %}
121:
122: %start program
123:
124: %union {
125: ssize_t node;
126: struct lvalue lvalue;
127: const char *str;
1.20 otto 128: char *astr;
1.1 otto 129: }
130:
1.9 otto 131: %token COMMA SEMICOLON LPAR RPAR LBRACE RBRACE LBRACKET RBRACKET DOT
132: %token NEWLINE
1.20 otto 133: %token <astr> LETTER
134: %token <str> NUMBER STRING
1.1 otto 135: %token DEFINE BREAK QUIT LENGTH
136: %token RETURN FOR IF WHILE SQRT
137: %token SCALE IBASE OBASE AUTO
1.15 otto 138: %token CONTINUE ELSE PRINT
1.1 otto 139:
1.19 otto 140: %left BOOL_OR
141: %left BOOL_AND
142: %nonassoc BOOL_NOT
1.1 otto 143: %nonassoc EQUALS LESS_EQ GREATER_EQ UNEQUALS LESS GREATER
144: %right <str> ASSIGN_OP
145: %left PLUS MINUS
146: %left MULTIPLY DIVIDE REMAINDER
1.17 otto 147: %right EXPONENT
1.1 otto 148: %nonassoc UMINUS
149: %nonassoc INCR DECR
150:
151: %type <lvalue> named_expression
152: %type <node> argument_list
153: %type <node> alloc_macro
154: %type <node> expression
155: %type <node> function
156: %type <node> function_header
157: %type <node> input_item
158: %type <node> opt_argument_list
1.13 otto 159: %type <node> opt_expression
160: %type <node> opt_relational_expression
1.1 otto 161: %type <node> opt_statement
1.15 otto 162: %type <node> print_expression
163: %type <node> print_expression_list
1.1 otto 164: %type <node> relational_expression
165: %type <node> return_expression
166: %type <node> semicolon_list
167: %type <node> statement
168: %type <node> statement_list
169:
170: %%
171:
172: program : /* empty */
1.20 otto 173: | program input_item
1.1 otto 174: ;
175:
176: input_item : semicolon_list NEWLINE
177: {
1.49 otto 178: emit($1, 0);
1.1 otto 179: macro_char = reset_macro_char;
180: putchar('\n');
181: free_tree();
1.11 otto 182: st_has_continue = false;
1.1 otto 183: }
184: | function
185: {
186: putchar('\n');
187: free_tree();
1.11 otto 188: st_has_continue = false;
1.1 otto 189: }
1.8 otto 190: | error NEWLINE
1.1 otto 191: {
1.8 otto 192: yyerrok;
1.1 otto 193: }
1.25 otto 194: | error QUIT
195: {
196: yyerrok;
197: }
1.1 otto 198: ;
199:
200: semicolon_list : /* empty */
201: {
202: $$ = cs("");
203: }
204: | statement
205: | semicolon_list SEMICOLON statement
206: {
207: $$ = node($1, $3, END_NODE);
208: }
209: | semicolon_list SEMICOLON
210: ;
211:
212: statement_list : /* empty */
213: {
214: $$ = cs("");
215: }
216: | statement
217: | statement_list NEWLINE
218: | statement_list NEWLINE statement
219: {
220: $$ = node($1, $3, END_NODE);
221: }
222: | statement_list SEMICOLON
223: | statement_list SEMICOLON statement
224: {
225: $$ = node($1, $3, END_NODE);
226: }
227: ;
228:
229:
230: opt_statement : /* empty */
231: {
232: $$ = cs("");
233: }
234: | statement
235: ;
236:
237: statement : expression
238: {
239: $$ = node($1, cs("ps."), END_NODE);
240: }
241: | named_expression ASSIGN_OP expression
242: {
1.11 otto 243: if ($2[0] == '\0')
244: $$ = node($3, cs($2), $1.store,
245: END_NODE);
246: else
247: $$ = node($1.load, $3, cs($2), $1.store,
248: END_NODE);
1.1 otto 249: }
250: | STRING
251: {
252: $$ = node(cs("["), as($1),
253: cs("]P"), END_NODE);
254: }
255: | BREAK
256: {
257: if (breaksp == 0) {
258: warning("break not in for or while");
259: YYERROR;
260: } else {
261: $$ = node(
262: numnode(nesting -
263: breakstack[breaksp-1]),
264: cs("Q"), END_NODE);
265: }
266: }
1.11 otto 267: | CONTINUE
268: {
269: if (breaksp == 0) {
270: warning("continue not in for or while");
271: YYERROR;
272: } else {
273: st_has_continue = true;
274: $$ = node(numnode(nesting -
275: breakstack[breaksp-1] - 1),
276: cs("J"), END_NODE);
277: }
278: }
1.1 otto 279: | QUIT
280: {
1.28 otto 281: sigset_t mask;
282:
1.1 otto 283: putchar('q');
284: fflush(stdout);
1.29 otto 285: if (dc) {
286: sigprocmask(SIG_BLOCK, NULL, &mask);
287: sigsuspend(&mask);
288: } else
289: exit(0);
1.1 otto 290: }
1.16 otto 291: | RETURN return_expression
1.1 otto 292: {
293: if (nesting == 0) {
1.8 otto 294: warning("return must be in a function");
1.1 otto 295: YYERROR;
296: }
1.16 otto 297: $$ = $2;
1.1 otto 298: }
1.13 otto 299: | FOR LPAR alloc_macro opt_expression SEMICOLON
300: opt_relational_expression SEMICOLON
301: opt_expression RPAR opt_statement pop_nesting
1.1 otto 302: {
1.11 otto 303: ssize_t n;
304:
305: if (st_has_continue)
306: n = node($10, cs("M"), $8, cs("s."),
307: $6, $3, END_NODE);
308: else
309: n = node($10, $8, cs("s."), $6, $3,
310: END_NODE);
311:
1.1 otto 312: emit_macro($3, n);
313: $$ = node($4, cs("s."), $6, $3, cs(" "),
314: END_NODE);
315: }
316: | IF LPAR alloc_macro pop_nesting relational_expression RPAR
317: opt_statement
318: {
319: emit_macro($3, $7);
320: $$ = node($5, $3, cs(" "), END_NODE);
1.14 otto 321: }
322: | IF LPAR alloc_macro pop_nesting relational_expression RPAR
323: opt_statement ELSE alloc_macro pop_nesting opt_statement
324: {
325: emit_macro($3, $7);
326: emit_macro($9, $11);
327: $$ = node($5, $3, cs("e"), $9, cs(" "),
328: END_NODE);
1.1 otto 329: }
330: | WHILE LPAR alloc_macro relational_expression RPAR
331: opt_statement pop_nesting
332: {
1.11 otto 333: ssize_t n;
334:
335: if (st_has_continue)
336: n = node($6, cs("M"), $4, $3, END_NODE);
337: else
338: n = node($6, $4, $3, END_NODE);
1.1 otto 339: emit_macro($3, n);
340: $$ = node($4, $3, cs(" "), END_NODE);
341: }
342: | LBRACE statement_list RBRACE
343: {
344: $$ = $2;
345: }
1.15 otto 346: | PRINT print_expression_list
347: {
348: $$ = $2;
349: }
1.1 otto 350: ;
351:
352: alloc_macro : /* empty */
353: {
354: $$ = cs(str_table[macro_char]);
355: macro_char++;
356: /* Do not use [, \ and ] */
357: if (macro_char == '[')
358: macro_char += 3;
359: /* skip letters */
360: else if (macro_char == 'a')
361: macro_char = '{';
362: else if (macro_char == ARRAY_CHAR)
363: macro_char += 26;
1.20 otto 364: else if (macro_char == 255)
1.1 otto 365: fatal("program too big");
366: if (breaksp == BREAKSTACK_SZ)
367: fatal("nesting too deep");
368: breakstack[breaksp++] = nesting++;
369: }
1.11 otto 370: ;
371:
1.1 otto 372: pop_nesting : /* empty */
373: {
374: breaksp--;
375: }
1.11 otto 376: ;
1.1 otto 377:
1.16 otto 378: function : function_header opt_parameter_list RPAR opt_newline
1.1 otto 379: LBRACE NEWLINE opt_auto_define_list
380: statement_list RBRACE
381: {
1.16 otto 382: int n = node(prologue, $8, epilogue,
1.1 otto 383: cs("0"), numnode(nesting),
384: cs("Q"), END_NODE);
385: emit_macro($1, n);
386: reset_macro_char = macro_char;
387: nesting = 0;
388: breaksp = 0;
389: }
390: ;
391:
392: function_header : DEFINE LETTER LPAR
393: {
1.20 otto 394: $$ = function_node($2);
395: free($2);
1.1 otto 396: prologue = cs("");
397: epilogue = cs("");
398: nesting = 1;
399: breaksp = 0;
400: breakstack[breaksp] = 0;
401: }
1.11 otto 402: ;
1.1 otto 403:
1.16 otto 404: opt_newline : /* empty */
405: | NEWLINE
406: ;
407:
1.1 otto 408: opt_parameter_list
409: : /* empty */
410: | parameter_list
411: ;
412:
413:
414: parameter_list : LETTER
415: {
1.20 otto 416: add_par(letter_node($1));
417: free($1);
1.1 otto 418: }
419: | LETTER LBRACKET RBRACKET
420: {
1.20 otto 421: add_par(array_node($1));
422: free($1);
1.1 otto 423: }
424: | parameter_list COMMA LETTER
425: {
1.20 otto 426: add_par(letter_node($3));
427: free($3);
1.1 otto 428: }
429: | parameter_list COMMA LETTER LBRACKET RBRACKET
430: {
1.20 otto 431: add_par(array_node($3));
432: free($3);
1.1 otto 433: }
434: ;
435:
436:
437:
438: opt_auto_define_list
439: : /* empty */
440: | AUTO define_list NEWLINE
441: | AUTO define_list SEMICOLON
442: ;
443:
444:
445: define_list : LETTER
446: {
1.20 otto 447: add_local(letter_node($1));
448: free($1);
1.1 otto 449: }
450: | LETTER LBRACKET RBRACKET
451: {
1.20 otto 452: add_local(array_node($1));
453: free($1);
1.1 otto 454: }
455: | define_list COMMA LETTER
456: {
1.20 otto 457: add_local(letter_node($3));
458: free($3);
1.1 otto 459: }
460: | define_list COMMA LETTER LBRACKET RBRACKET
461: {
1.20 otto 462: add_local(array_node($3));
463: free($3);
1.1 otto 464: }
465: ;
466:
467:
468: opt_argument_list
469: : /* empty */
470: {
471: $$ = cs("");
472: }
473: | argument_list
474: ;
475:
476:
477: argument_list : expression
478: | argument_list COMMA expression
479: {
480: $$ = node($1, $3, END_NODE);
481: }
482: | argument_list COMMA LETTER LBRACKET RBRACKET
483: {
1.20 otto 484: $$ = node($1, cs("l"), array_node($3),
1.3 deraadt 485: END_NODE);
1.20 otto 486: free($3);
1.1 otto 487: }
488: ;
489:
1.13 otto 490: opt_relational_expression
491: : /* empty */
492: {
493: $$ = cs(" 0 0=");
494: }
495: | relational_expression
496: ;
1.1 otto 497:
498: relational_expression
1.19 otto 499: : expression EQUALS expression
1.1 otto 500: {
501: $$ = node($1, $3, cs("="), END_NODE);
502: }
503: | expression UNEQUALS expression
504: {
505: $$ = node($1, $3, cs("!="), END_NODE);
506: }
507: | expression LESS expression
508: {
509: $$ = node($1, $3, cs(">"), END_NODE);
510: }
511: | expression LESS_EQ expression
512: {
513: $$ = node($1, $3, cs("!<"), END_NODE);
514: }
515: | expression GREATER expression
516: {
517: $$ = node($1, $3, cs("<"), END_NODE);
518: }
519: | expression GREATER_EQ expression
520: {
521: $$ = node($1, $3, cs("!>"), END_NODE);
522: }
1.19 otto 523: | expression
524: {
525: $$ = node($1, cs(" 0!="), END_NODE);
526: }
1.1 otto 527: ;
528:
529:
530: return_expression
531: : /* empty */
532: {
533: $$ = node(cs("0"), epilogue,
534: numnode(nesting), cs("Q"), END_NODE);
535: }
536: | expression
537: {
538: $$ = node($1, epilogue,
1.16 otto 539: numnode(nesting), cs("Q"), END_NODE);
540: }
541: | LPAR RPAR
542: {
543: $$ = node(cs("0"), epilogue,
1.1 otto 544: numnode(nesting), cs("Q"), END_NODE);
545: }
546: ;
547:
1.13 otto 548:
549: opt_expression : /* empty */
550: {
551: $$ = cs(" 0");
552: }
553: | expression
554: ;
1.1 otto 555:
556: expression : named_expression
557: {
558: $$ = node($1.load, END_NODE);
1.9 otto 559: }
560: | DOT {
561: $$ = node(cs("l."), END_NODE);
1.1 otto 562: }
563: | NUMBER
564: {
565: $$ = node(cs(" "), as($1), END_NODE);
566: }
567: | LPAR expression RPAR
568: {
569: $$ = $2;
570: }
571: | LETTER LPAR opt_argument_list RPAR
572: {
573: $$ = node($3, cs("l"),
1.20 otto 574: function_node($1), cs("x"),
1.1 otto 575: END_NODE);
1.20 otto 576: free($1);
1.1 otto 577: }
578: | MINUS expression %prec UMINUS
579: {
580: $$ = node(cs(" 0"), $2, cs("-"),
581: END_NODE);
582: }
583: | expression PLUS expression
584: {
585: $$ = node($1, $3, cs("+"), END_NODE);
586: }
587: | expression MINUS expression
588: {
589: $$ = node($1, $3, cs("-"), END_NODE);
590: }
591: | expression MULTIPLY expression
592: {
593: $$ = node($1, $3, cs("*"), END_NODE);
594: }
595: | expression DIVIDE expression
596: {
597: $$ = node($1, $3, cs("/"), END_NODE);
598: }
599: | expression REMAINDER expression
600: {
601: $$ = node($1, $3, cs("%"), END_NODE);
602: }
603: | expression EXPONENT expression
604: {
605: $$ = node($1, $3, cs("^"), END_NODE);
606: }
607: | INCR named_expression
608: {
609: $$ = node($2.load, cs("1+d"), $2.store,
610: END_NODE);
611: }
612: | DECR named_expression
613: {
614: $$ = node($2.load, cs("1-d"),
615: $2.store, END_NODE);
616: }
617: | named_expression INCR
618: {
619: $$ = node($1.load, cs("d1+"),
620: $1.store, END_NODE);
621: }
622: | named_expression DECR
623: {
624: $$ = node($1.load, cs("d1-"),
625: $1.store, END_NODE);
626: }
627: | named_expression ASSIGN_OP expression
628: {
1.11 otto 629: if ($2[0] == '\0')
630: $$ = node($3, cs($2), cs("d"), $1.store,
631: END_NODE);
632: else
633: $$ = node($1.load, $3, cs($2), cs("d"),
634: $1.store, END_NODE);
1.1 otto 635: }
636: | LENGTH LPAR expression RPAR
637: {
638: $$ = node($3, cs("Z"), END_NODE);
639: }
640: | SQRT LPAR expression RPAR
641: {
642: $$ = node($3, cs("v"), END_NODE);
643: }
644: | SCALE LPAR expression RPAR
645: {
646: $$ = node($3, cs("X"), END_NODE);
1.19 otto 647: }
648: | BOOL_NOT expression
649: {
650: $$ = node($2, cs("N"), END_NODE);
651: }
652: | expression BOOL_AND alloc_macro pop_nesting expression
653: {
654: ssize_t n = node(cs("R"), $5, END_NODE);
655: emit_macro($3, n);
656: $$ = node($1, cs("d0!="), $3, END_NODE);
657: }
658: | expression BOOL_OR alloc_macro pop_nesting expression
659: {
660: ssize_t n = node(cs("R"), $5, END_NODE);
661: emit_macro($3, n);
662: $$ = node($1, cs("d0="), $3, END_NODE);
663: }
664: | expression EQUALS expression
665: {
666: $$ = node($1, $3, cs("G"), END_NODE);
667: }
668: | expression UNEQUALS expression
669: {
670: $$ = node($1, $3, cs("GN"), END_NODE);
671: }
672: | expression LESS expression
673: {
674: $$ = node($3, $1, cs("("), END_NODE);
675: }
676: | expression LESS_EQ expression
677: {
678: $$ = node($3, $1, cs("{"), END_NODE);
679: }
680: | expression GREATER expression
681: {
682: $$ = node($1, $3, cs("("), END_NODE);
683: }
684: | expression GREATER_EQ expression
685: {
686: $$ = node($1, $3, cs("{"), END_NODE);
1.1 otto 687: }
688: ;
689:
690: named_expression
691: : LETTER
692: {
1.20 otto 693: $$.load = node(cs("l"), letter_node($1),
1.1 otto 694: END_NODE);
1.20 otto 695: $$.store = node(cs("s"), letter_node($1),
1.1 otto 696: END_NODE);
1.20 otto 697: free($1);
1.1 otto 698: }
699: | LETTER LBRACKET expression RBRACKET
700: {
701: $$.load = node($3, cs(";"),
1.20 otto 702: array_node($1), END_NODE);
1.1 otto 703: $$.store = node($3, cs(":"),
1.20 otto 704: array_node($1), END_NODE);
705: free($1);
1.1 otto 706: }
707: | SCALE
708: {
709: $$.load = cs("K");
710: $$.store = cs("k");
711: }
712: | IBASE
713: {
714: $$.load = cs("I");
715: $$.store = cs("i");
716: }
717: | OBASE
718: {
719: $$.load = cs("O");
720: $$.store = cs("o");
721: }
722: ;
1.15 otto 723:
724: print_expression_list
725: : print_expression
726: | print_expression_list COMMA print_expression
727: {
728: $$ = node($1, $3, END_NODE);
729: }
730:
731: print_expression
732: : expression
733: {
1.18 otto 734: $$ = node($1, cs("ds.n"), END_NODE);
1.15 otto 735: }
736: | STRING
737: {
738: char *p = escape($1);
1.18 otto 739: $$ = node(cs("["), as(p), cs("]n"), END_NODE);
1.15 otto 740: free(p);
741: }
1.1 otto 742: %%
743:
744:
745: static void
746: grow(void)
747: {
748: struct tree *p;
1.26 otto 749: size_t newsize;
1.1 otto 750:
751: if (current == instr_sz) {
752: newsize = instr_sz * 2 + 1;
1.46 deraadt 753: p = reallocarray(instructions, newsize, sizeof(*p));
1.1 otto 754: if (p == NULL) {
755: free(instructions);
1.12 otto 756: err(1, NULL);
1.1 otto 757: }
758: instructions = p;
759: instr_sz = newsize;
760: }
761: }
762:
1.7 otto 763: static ssize_t
1.1 otto 764: cs(const char *str)
765: {
766: grow();
767: instructions[current].index = CONST_STRING;
768: instructions[current].u.cstr = str;
769: return current++;
770: }
771:
1.7 otto 772: static ssize_t
1.1 otto 773: as(const char *str)
774: {
775: grow();
776: instructions[current].index = ALLOC_STRING;
777: instructions[current].u.astr = strdup(str);
1.2 otto 778: if (instructions[current].u.astr == NULL)
1.12 otto 779: err(1, NULL);
1.1 otto 780: return current++;
781: }
782:
783: static ssize_t
784: node(ssize_t arg, ...)
785: {
786: va_list ap;
787: ssize_t ret;
788:
789: va_start(ap, arg);
790:
791: ret = current;
792: grow();
793: instructions[current++].index = arg;
794:
795: do {
796: arg = va_arg(ap, ssize_t);
797: grow();
798: instructions[current++].index = arg;
799: } while (arg != END_NODE);
800:
801: va_end(ap);
802: return ret;
803: }
804:
805: static void
1.49 otto 806: emit(ssize_t i, int level)
1.1 otto 807: {
1.49 otto 808: if (level > 1000)
809: errx(1, "internal error: tree level > 1000");
810: if (instructions[i].index >= 0) {
811: while (instructions[i].index != END_NODE &&
812: instructions[i].index != i) {
813: emit(instructions[i].index, level + 1);
814: i++;
815: }
816: } else if (instructions[i].index != END_NODE)
1.1 otto 817: fputs(instructions[i].u.cstr, stdout);
818: }
819:
820: static void
821: emit_macro(int node, ssize_t code)
822: {
823: putchar('[');
1.49 otto 824: emit(code, 0);
1.1 otto 825: printf("]s%s\n", instructions[node].u.cstr);
826: nesting--;
827: }
828:
829: static void
830: free_tree(void)
831: {
1.26 otto 832: ssize_t i;
1.1 otto 833:
834: for (i = 0; i < current; i++)
835: if (instructions[i].index == ALLOC_STRING)
836: free(instructions[i].u.astr);
837: current = 0;
838: }
839:
840: static ssize_t
841: numnode(int num)
842: {
843: const char *p;
844:
845: if (num < 10)
846: p = str_table['0' + num];
847: else if (num < 16)
848: p = str_table['A' - 10 + num];
849: else
1.20 otto 850: errx(1, "internal error: break num > 15");
1.1 otto 851: return node(cs(" "), cs(p), END_NODE);
852: }
853:
1.20 otto 854:
855: static ssize_t
856: lookup(char * str, size_t len, char type)
857: {
858: ENTRY entry, *found;
859: u_short num;
860: u_char *p;
861:
862: /* The scanner allocated an extra byte already */
863: if (str[len-1] != type) {
864: str[len] = type;
865: str[len+1] = '\0';
866: }
867: entry.key = str;
868: found = hsearch(entry, FIND);
869: if (found == NULL) {
870: if (var_count == MAX_VARIABLES)
871: errx(1, "too many variables");
872: p = malloc(4);
873: if (p == NULL)
874: err(1, NULL);
875: num = var_count++;
876: p[0] = 255;
877: p[1] = ENCODE(num / VAR_BASE + 1);
878: p[2] = ENCODE(num % VAR_BASE + 1);
879: p[3] = '\0';
880:
1.22 otto 881: entry.data = (char *)p;
1.20 otto 882: entry.key = strdup(str);
883: if (entry.key == NULL)
884: err(1, NULL);
885: found = hsearch(entry, ENTER);
886: if (found == NULL)
887: err(1, NULL);
888: }
889: return cs(found->data);
890: }
891:
892: static ssize_t
893: letter_node(char *str)
894: {
895: size_t len;
896:
897: len = strlen(str);
898: if (len == 1 && str[0] != '_')
899: return cs(str_table[(int)str[0]]);
900: else
901: return lookup(str, len, 'L');
902: }
903:
904: static ssize_t
905: array_node(char *str)
906: {
907: size_t len;
908:
909: len = strlen(str);
910: if (len == 1 && str[0] != '_')
911: return cs(str_table[(int)str[0] - 'a' + ARRAY_CHAR]);
912: else
913: return lookup(str, len, 'A');
914: }
915:
916: static ssize_t
917: function_node(char *str)
918: {
919: size_t len;
920:
921: len = strlen(str);
922: if (len == 1 && str[0] != '_')
923: return cs(str_table[(int)str[0] - 'a' + FUNC_CHAR]);
924: else
925: return lookup(str, len, 'F');
926: }
927:
1.1 otto 928: static void
929: add_par(ssize_t n)
930: {
931: prologue = node(cs("S"), n, prologue, END_NODE);
932: epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE);
933: }
934:
935: static void
936: add_local(ssize_t n)
937: {
938: prologue = node(cs("0S"), n, prologue, END_NODE);
939: epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE);
940: }
941:
942: void
943: yyerror(char *s)
944: {
1.10 otto 945: char *str, *p;
1.27 otto 946: int n;
1.10 otto 947:
1.32 otto 948: if (yyin != NULL && feof(yyin))
1.27 otto 949: n = asprintf(&str, "%s: %s:%d: %s: unexpected EOF",
1.40 otto 950: __progname, filename, lineno, s);
951: else if (yytext[0] == '\n')
952: n = asprintf(&str,
953: "%s: %s:%d: %s: newline unexpected",
1.25 otto 954: __progname, filename, lineno, s);
1.44 deraadt 955: else if (isspace((unsigned char)yytext[0]) ||
956: !isprint((unsigned char)yytext[0]))
1.27 otto 957: n = asprintf(&str,
958: "%s: %s:%d: %s: ascii char 0x%02x unexpected",
1.49 otto 959: __progname, filename, lineno, s, yytext[0] & 0xff);
1.1 otto 960: else
1.27 otto 961: n = asprintf(&str, "%s: %s:%d: %s: %s unexpected",
1.8 otto 962: __progname, filename, lineno, s, yytext);
1.27 otto 963: if (n == -1)
1.12 otto 964: err(1, NULL);
1.10 otto 965:
966: fputs("c[", stdout);
967: for (p = str; *p != '\0'; p++) {
968: if (*p == '[' || *p == ']' || *p =='\\')
969: putchar('\\');
970: putchar(*p);
971: }
1.50 ! otto 972: fputs("]ec\n", stdout);
1.10 otto 973: free(str);
1.1 otto 974: }
975:
1.8 otto 976: void
1.1 otto 977: fatal(const char *s)
978: {
979: errx(1, "%s:%d: %s", filename, lineno, s);
980: }
981:
982: static void
983: warning(const char *s)
984: {
985: warnx("%s:%d: %s", filename, lineno, s);
986: }
987:
988: static void
989: init(void)
990: {
991: int i;
992:
993: for (i = 0; i < UCHAR_MAX; i++) {
994: str_table[i][0] = i;
995: str_table[i][1] = '\0';
996: }
1.20 otto 997: if (hcreate(1 << 16) == 0)
998: err(1, NULL);
1.1 otto 999: }
1000:
1001:
1002: static __dead void
1003: usage(void)
1004: {
1.30 otto 1005: fprintf(stderr, "usage: %s [-cl] [-e expression] [file ...]\n",
1.24 otto 1006: __progname);
1.1 otto 1007: exit(1);
1008: }
1009:
1.15 otto 1010: static char *
1011: escape(const char *str)
1012: {
1013: char *ret, *p;
1014:
1015: ret = malloc(strlen(str) + 1);
1016: if (ret == NULL)
1017: err(1, NULL);
1018:
1019: p = ret;
1020: while (*str != '\0') {
1021: /*
1022: * We get _escaped_ strings here. Single backslashes are
1023: * already converted to double backslashes
1024: */
1025: if (*str == '\\') {
1026: if (*++str == '\\') {
1027: switch (*++str) {
1028: case 'a':
1029: *p++ = '\a';
1030: break;
1031: case 'b':
1032: *p++ = '\b';
1033: break;
1034: case 'f':
1035: *p++ = '\f';
1036: break;
1037: case 'n':
1038: *p++ = '\n';
1039: break;
1040: case 'q':
1041: *p++ = '"';
1042: break;
1043: case 'r':
1044: *p++ = '\r';
1045: break;
1046: case 't':
1047: *p++ = '\t';
1048: break;
1049: case '\\':
1050: *p++ = '\\';
1051: break;
1052: }
1053: str++;
1054: } else {
1055: *p++ = '\\';
1056: *p++ = *str++;
1057: }
1058: } else
1059: *p++ = *str++;
1060: }
1061: *p = '\0';
1062: return ret;
1063: }
1.1 otto 1064:
1.28 otto 1065: /* ARGSUSED */
1.43 deraadt 1066: static void
1.28 otto 1067: sigchld(int signo)
1068: {
1069: pid_t pid;
1.37 deraadt 1070: int status, save_errno = errno;
1.28 otto 1071:
1072: for (;;) {
1.39 otto 1073: pid = waitpid(dc, &status, WCONTINUED | WNOHANG);
1.28 otto 1074: if (pid == -1) {
1075: if (errno == EINTR)
1076: continue;
1077: _exit(0);
1.39 otto 1078: } else if (pid == 0)
1079: break;
1.28 otto 1080: if (WIFEXITED(status) || WIFSIGNALED(status))
1081: _exit(0);
1082: else
1083: break;
1084: }
1.37 deraadt 1085: errno = save_errno;
1.28 otto 1086: }
1087:
1.34 otto 1088: static const char *
1089: dummy_prompt(void)
1090: {
1091:
1092: return ("");
1093: }
1094:
1.1 otto 1095: int
1096: main(int argc, char *argv[])
1097: {
1.31 deraadt 1098: int i, ch;
1.1 otto 1099: int p[2];
1.24 otto 1100: char *q;
1.1 otto 1101:
1.48 deraadt 1102: if (pledge("stdio rpath proc tty", NULL) == -1)
1103: err(1, "pledge");
1104:
1.1 otto 1105: init();
1.47 millert 1106: setvbuf(stdout, NULL, _IOLBF, 0);
1.1 otto 1107:
1.45 deraadt 1108: sargv = reallocarray(NULL, argc, sizeof(char *));
1.23 otto 1109: if (sargv == NULL)
1110: err(1, NULL);
1111:
1.24 otto 1112: if ((cmdexpr = strdup("")) == NULL)
1113: err(1, NULL);
1114: /* The d debug option is 4.4 BSD bc(1) compatible */
1115: while ((ch = getopt(argc, argv, "cde:l")) != -1) {
1.1 otto 1116: switch (ch) {
1117: case 'c':
1118: case 'd':
1119: do_fork = false;
1.24 otto 1120: break;
1121: case 'e':
1122: q = cmdexpr;
1123: if (asprintf(&cmdexpr, "%s%s\n", cmdexpr, optarg) == -1)
1124: err(1, NULL);
1125: free(q);
1.1 otto 1126: break;
1127: case 'l':
1.23 otto 1128: sargv[sargc++] = _PATH_LIBB;
1.1 otto 1129: break;
1130: default:
1.5 deraadt 1131: usage();
1.1 otto 1132: }
1133: }
1134:
1.23 otto 1135: argc -= optind;
1136: argv += optind;
1137:
1.50 ! otto 1138: interactive = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) &&
! 1139: isatty(STDERR_FILENO);
1.23 otto 1140: for (i = 0; i < argc; i++)
1141: sargv[sargc++] = argv[i];
1.1 otto 1142:
1143: if (do_fork) {
1144: if (pipe(p) == -1)
1145: err(1, "cannot create pipe");
1.28 otto 1146: dc = fork();
1147: if (dc == -1)
1.1 otto 1148: err(1, "cannot fork");
1.28 otto 1149: else if (dc != 0) {
1150: signal(SIGCHLD, sigchld);
1.1 otto 1151: close(STDOUT_FILENO);
1152: dup(p[1]);
1153: close(p[0]);
1154: close(p[1]);
1.6 deraadt 1155: } else {
1.48 deraadt 1156: char *dc_argv[] = { "dc", "-x", NULL };
1157: extern int dc_main(int, char **);
1158:
1159: if (pledge("stdio", NULL) == -1)
1160: err(1, "pledge");
1161:
1.1 otto 1162: close(STDIN_FILENO);
1163: dup(p[0]);
1164: close(p[0]);
1165: close(p[1]);
1.48 deraadt 1166:
1167: exit (dc_main(2, dc_argv));
1.1 otto 1168: }
1.41 otto 1169: }
1170: if (interactive) {
1171: gettty(&ttysaved);
1172: el = el_init("bc", stdin, stderr, stderr);
1173: hist = history_init();
1174: history(hist, &he, H_SETSIZE, 100);
1175: el_set(el, EL_HIST, history, hist);
1176: el_set(el, EL_EDITOR, "emacs");
1177: el_set(el, EL_SIGNAL, 0);
1178: el_set(el, EL_PROMPT, dummy_prompt);
1179: el_set(el, EL_ADDFN, "bc_eof", "", bc_eof);
1180: el_set(el, EL_BIND, "^D", "bc_eof", NULL);
1181: el_source(el, NULL);
1.1 otto 1182: }
1.48 deraadt 1183:
1184: if (pledge("stdio rpath tty", NULL) == -1)
1185: err(1, "pledge");
1186:
1.1 otto 1187: yywrap();
1188: return yyparse();
1189: }